pixellint

The fired URL still says CACHEBUSTER

Short answer

Pixellint core treats [NAME], ${NAME}, {{NAME}}, %%NAME%%, !!NAME!!, and [%NAME%] as macros. A pixel URL uses one syntax. A VAST tracker may carry IAB [MACRO] beside ${MACRO}. An unexpanded macro on a fired artifact is a hard miss. A template in GAM is supposed to still contain the token. Tell the validator which one you pasted.

Validate a pixel Open the rulepack

Macro delimiters

Square brackets are GAM and many VAST insertions: [CACHEBUSTER], [TIMESTAMP], [CLICK_URL]. Dollar-braces are another family: ${CLICK_URL}, ${GDPR_CONSENT_1234}. Double braces are a third: {{CACHEBUSTER}}, {{PLAYER_WIDTH}}. Pixellint also recognizes %%NAME%%, !!NAME!!, and [%NAME%]. On a vast artifact, [TOKEN] is checked against the IAB macro table: unknown names, lowercase names, and the pre-4.1 playhead macros.

A pixel URL uses one syntax. Mixing [CACHEBUSTER] and ${RANDOM} means two systems were supposed to expand the same URL and probably only one did. core.macro.mixed_syntax flags that. A VAST tracker may carry IAB [MACRO] beside ${MACRO} without that warning. Pick the syntax the ad server that serves this creative actually expands.

Unsafe position

A macro in the hostname or scheme does not expand into a valid URL, it expands into garbage. https://${HOST}/pixel or [PROTOCOL]://ad.example/imp will not become a legal collector after substitution, or it will become a collector you did not intend. Macros never belong in scheme, authority, host, port, or userinfo. core.macro.unsafe_position is that rule.

Put macros in query or path slots the ad server documents. ord=[timestamp] on a Floodlight path is a documented slot. Cache busters in the query are a documented slot. A click URL as a query value (${CLICK_URL} encoded) is a documented slot. A macro as the host is a creative that will 404 after serve, or worse, send data to a substituted host you do not control.

Core URL still applies

After expansion the artifact must still be an absolute URL with a host, http or https, no userinfo. Fragments never reach the server. Plain http is flagged for upgrade. A macro that expands to an empty host trips core.url.host_missing. A macro that expands to javascript: trips unsupported scheme. Validate the fired form, not only the template, or you will ship a creative that is pretty in GAM and illegal on the wire.

The example below fails three ways if you mark it fired: mixed syntax, a macro in the host, and gdpr_consent=1 which decodes as base64 and is not a TC String. As a template it is still an unsafe host. Put the cache buster in the query, put a real host in the host, and put a CMP string in gdpr_consent when gdpr=1.

https://${HOST}/imp?cb=[CACHEBUSTER]&gdpr_consent=1

VAST Tracking URLs use the same tokens

A live VAST Impression or Tracking start that still contains [CACHEBUSTER] never uniquely counted. The player expands IAB VAST macros at fire time. The collector still wants an absolute URL with a real host after expansion. Treat those beacons as fired pixels, not as GAM templates.

Macro names and where they may sit in a VAST tag: https://vastlint.org/docs/vast-macros/ Event list and when each fires: https://vastlint.org/docs/vast-tracking-events/start/

Check the artifact

Paste the pixel URL or JSON body into the playground. Same engine as pixellint validate. Artifacts you test may be stored; see privacy.