People still search for DART Floodlight tags. DART was DoubleClick's ad server. Campaign Manager 360 still serves the same activity on doubleclick.net. The request returns a GIF. The conversion still lands on the wrong activity, or it lands once.
Floodlight is not a query string, and it is not a Conversions API with the host changed.
The shape is semicolon pairs on the path:
https://ad.doubleclick.net/ddm/activity/src=1234567;type=conv;cat=purch;ord=987654321;qty=1;cost=19.99
src is the numeric Floodlight configuration id, the advertiser. type is the activity group tag. cat is the activity tag. Trafficking the wrong cat is a silent wrong conversion, not a 404. The activity you meant never increments. A different activity does. DART Floodlight tags is that identity. The path table is the Floodlight pack.
$ pixellint validate url @floodlight.txt --rulepack vendor/floodlight
Missing, empty, or illegal values show up as vendor.floodlight.param.src.missing, .type.missing, .cat.missing, and the empty and invalid twins. Staging has to use a staging cat. A QA purchase on the production activity is real revenue in Campaign Manager and a lie in the test plan. Server-to-server Floodlight is a different Campaign Manager feature. If you use it, src, type, and cat still have to name the activity you think they name. There is no second pipe with a different clock. Do not invent an event_id query because a Meta playbook said both sides need one. Dedup for this tag is the counting method on the activity, not a shared UUID with a browser pixel.
ord=1 is a cache, not a counter
ord is required cache busting. A browser or a CDN that sees the same URL will collapse a thousand impressions into one response. A standard counter tag needs a unique ord on every fire. Unique counting is the other method: you send ord=1 together with a random num. vendor.floodlight.counting.unique_requires_ord fires when num is present and ord is not. A leftover ord=1 on a standard counter, copied from a screenshot or a sample tag, collapses fires into one cached GET. The GIF still returns 200. The activity count does not move.
Do not put an email or a phone in ord. Cache busting is the same job on display impression pixels: a unique query value, expanded before the request, with no personal data in the slot. An unexpanded [CACHEBUSTER] or [timestamp] on a URL that already served is an undercount. Macros from Google Ad Manager have to expand. If you still see square brackets, you copied the template from the trafficking UI, or the player never substituted. That is a template versus a fired URL. Validate the tag as stored with --state template. Validate the HAR row with --state fired. One fixture cannot be both. A literal 1 that survived into production is the classic miss.
cost and qty on purchase activities are numbers you defined in Campaign Manager. A currency symbol in cost is not a number. Floodlight has no event_time digit count and no SHA-256 em field on the standard activity tag. Do not hash the path. Hashing a Floodlight URL because a Conversions API helper hashed every string does not make the activity match better. It makes the path nonsense.
Consent on the path is still a TC String
gdpr, gdpr_consent, gpp, gpp_sid, and us_privacy ride as the same semicolon fields. Core privacy rules read the query string and Floodlight-style path parameters, which is why those checks are not a Google-only pack. gdpr is 0 or 1. gdpr=1 needs a TC String whose header decodes as version 2. gdpr_consent=1 and gdpr_consent=true pass an alphabet check and fail a decode. They are valid base64. They are not a TC String. They do not carry consent.
Empty values and unexpanded macros are template slots. A fired tag that still contains an unexpanded GDPR token never carried consent. Duplicate gdpr_consent parameters are core.privacy.duplicate_signal. Floodlight on the same page as Google Consent Mode still wants the TC String on the tag. Consent Mode is not TCF. A US Privacy string such as 1YNN is not a GPP header, and gpp without gpp_sid fails on its own.
https://ad.doubleclick.net/ddm/activity/src=1234567;type=conv;cat=purch;ord=1;num=9988;gdpr=1;gdpr_consent=CPXXXXXXXX
That ord=1 is legal only because num is present and you meant unique counting. The same ord=1 without num on a standard counter is the cache bug. Mixed macro families in one URL, [NAME] next to ${NAME} next to {{NAME}}, is a mixed-syntax finding in core. A pixel URL uses one syntax.
Preview is not the published tag
GTM preview can show a Floodlight tag with macros filled in the panel while the published container still sends the token. Confirm Network after publish, on a clean profile. Copy the activity URL. A filter on the word pixel misses doubleclick.net. Lint it twice:
$ pixellint validate url @floodlight.txt --rulepack vendor/floodlight
$ pixellint validate url @floodlight.txt --rulepack core
The vendor pack checks src, type, cat, and the counting pair. Core checks scheme, macros, and the consent strings. Unknown hosts get attribution, not a pile of invented rules. A click URL must not be trafficked as this impression activity. An impression activity should return the GIF or a 204. A 302 to a landing page is a click tracker wearing an activity path.
Paste the fired URL into the playground at pixellint.org. If the string still has brackets, set the state to template or you will fail every legal macro in the creative. I maintain Pixellint. It is not affiliated with Google or Campaign Manager. The rules cite Campaign Manager's activity URL because that is the contract, not because this is an official tag checker. A model or a trafficking sheet can emit src, type, and cat that look filled in. The package is the check that those three name an activity, that ord matches the counting method, and that gdpr_consent decodes.
Top comments (0)