A trafficking export shows <UniversalAdId idRegistry="Ad-ID" idValue="CNPA0484000H"/>. The tag validates. Frequency caps do not move. The same creative wins two slots in one pod under different internal IDs.
The XML is not empty. The player just does not read the attribute anymore.
Where the identifier lives changed in 4.1
<UniversalAdId> is how VAST 4.0+ names the creative asset across systems. Ad servers, DSPs, and verification vendors each mint their own creative IDs. None of them match. UniversalAdId is the join key for deduplication, competitive separation, and cross-platform frequency capping.
In VAST 4.0, the identifier belongs in the idValue attribute:
<UniversalAdId idRegistry="Ad-ID" idValue="CNPA0484000H"></UniversalAdId>
In VAST 4.1 and later, IAB removed idValue. The identifier is the text content of the element:
<UniversalAdId idRegistry="Ad-ID">CNPA0484000H</UniversalAdId>
idRegistry stays required. It names who issued the ID (Ad-ID for US commercial creative, unknown when you only have an internal code). What moved is where the actual code lives.
VAST 4.2 then allowed multiple <UniversalAdId> elements on one creative so the same spot can carry Ad-ID and a regional registry at once. That is a separate change. The 4.0 to 4.1 move is the one I still see breaking live tags.
The failure mode that looks like a data problem
Copy a 4.0 template into a document that declares version="4.1" or 4.2. Leave the ID on idValue. Leave the element body empty:
<VAST version="4.1">
<Ad id="1">
<InLine>
<AdSystem>Example Ad Server</AdSystem>
<AdTitle>30s Spot</AdTitle>
<AdServingId>srv-20260825-001</AdServingId>
<Impression><![CDATA[https://track.example.com/imp]]></Impression>
<Creatives>
<Creative sequence="1">
<UniversalAdId idRegistry="Ad-ID" idValue="CNPA0484000H"></UniversalAdId>
<Linear>
<Duration>00:00:30</Duration>
<MediaFiles>
<MediaFile delivery="progressive" type="video/mp4" width="1920" height="1080">
<![CDATA[https://cdn.example.com/ad.mp4]]>
</MediaFile>
</MediaFiles>
</Linear>
</Creative>
</Creatives>
</InLine>
</Ad>
</VAST>
The video plays. Impressions fire. Downstream systems that read UniversalAdId from element text see no identifier.
That is not hypothetical pedantry. Pod dedup logic compares UniversalAdId values. If two demand paths return the same Ad-ID code but one response puts it in idValue and the player ignores attributes, the break looks like two unrelated creatives. Frequency caps keyed on UniversalAdId miss repeats. QA dashboards show "missing creative ID" on half the 4.x traffic while the trafficking UI still displays the attribute.
Do not confuse this with <AdServingId>, which VAST 4.1 added as a per-impression transaction ID. UniversalAdId identifies the asset. AdServingId identifies one serve. You need both on 4.1+ InLine ads, and they answer different questions.
How you catch it
I maintain vastlint, an open source VAST validator. On the tag above it prints a warning, not a hard error, because idValue is present even though the spec says to ignore it:
$ vastlint check universaladid-idvalue-only.xml
universaladid-idvalue-only.xml VAST 4.1
warning <UniversalAdId> idValue attribute was removed in VAST 4.1: value should be in element text content
VAST-4.1-universaladid-idvalue-removed
Treat that warning as a ship blocker on 4.1+ inventory. Players are not going to read the attribute back for you.
If both idValue and text content are missing on 4.1+, you get an error:
error <UniversalAdId> must have text content in VAST 4.1+ (the ID value is the element body)
VAST-4.1-universaladid-content
On a 4.0 document, the opposite mistake fires: empty element with no idValue and no text:
error <UniversalAdId> is missing required idValue attribute (required in VAST 4.0)
VAST-4.0-universaladid-idvalue
Run it locally on a file or paste XML into the browser validator workflow described on the UniversalAdId reference page. For a live ad tag URL that wraps through an SSP, fetch the resolved inline before you check identity; wrappers do not carry UniversalAdId.
cargo install vastlint
vastlint check my-tag.xml
The rules reference lists every ID above with the spec section cited in the output.
Where to go next
The UniversalAdId reference walks through registries, the 4.2 multi-ID shape, and how UniversalAdId differs from Creative id and AdServingId.
The dedicated rule page for the 4.1 attribute removal is VAST-4.1-universaladid-idvalue-removed. Pair it with the empty-body error on the same rules index when you are writing CI policy.
If the symptom is duplicate creatives in one break rather than a blank ID field, read the ad pods guide: pods are sibling <Ad> elements with sequence, and dedup only works when UniversalAdId is readable.
Tags exported from Google Ad Manager are a common source of version skew. The GAM VAST guide is the right place to align declared VAST version, required 4.x fields, and what your player actually consumes.
For a broader checklist (missing Impression, Duration format, HTTP media URLs), the common VAST errors page groups the structural mistakes validators catch before you spend an afternoon in player logs.
The short version
On VAST 4.0, put the creative code in idValue. On 4.1+, put it in the element text and drop the attribute. An empty <UniversalAdId> with only idValue set is a silent identity miss: video serves, caps and dedup do not see the creative they think you sent.
vastlint is independent of IAB Tech Lab. The rule ids cite the VAST spec because that is where the contract lives.
Top comments (0)