DEV Community

Aleksander Sekowski
Aleksander Sekowski

Posted on

The URL in the tag manager is not the URL the browser fired.

The string in Campaign Manager and the string in Chrome Network are not the same artifact. One of them is allowed to contain [CACHEBUSTER]. The other is not. A pixel checker that does not know which one you pasted will fail every legal macro, or it will pass a token that never expanded.

That is the whole job of the tester: say what you pasted, then check it against the contract for that state.

Template versus fired URLs is the state model. The playground at pixellint.org is the same engine as pixellint validate, running in the browser. cargo install pixellint and npm install pixellint are the same rule ids again. A finding in the box is the finding CI will print. Pixel not firing is how you get a URL worth pasting. The GTM snippet is not that URL.

Three states, and unknown is not a third product

unknown is the default when you did not say. Macro rules stay conservative. They will not assume the token was supposed to expand, and they will not assume it was supposed to remain. You get core URL checks and vendor parameter checks, with less certainty on macros. A first paste in the playground without a state is fine. Leaving production CI on unknown because it feels safer is not. It is vaguer. Teams that leave unknown everywhere either ignore macro findings or argue about them every sprint.

template means this is what the ad server, the MMP, or the tag manager stores. [NAME], ${NAME}, and {{NAME}} are expected in legal slots. Empty consent fields are unfilled slots. Copying from the Google Ad Manager UI is a template even when it looks like a URL. A Slack message from trafficking with ord=[timestamp] is a template. A Jira attachment of the Floodlight tag as sold is a template. A GTM custom pixel field that still has {{dlv-order-id}} is a template.

fired means this is what left the device or the server. Chrome Network, Charles, a HAR, an access log, MMP raw data, server-side GTM preview of the outbound request. If you see ord=1724284800123, it has fired. If you see [TIMESTAMP], it has not. If you see both in one URL, one macro family expanded and another did not. That is a fired miss.

$ pixellint validate url 'https://example.com/pixel?cb=[CACHEBUSTER]' --state template
$ pixellint validate url 'https://example.com/pixel?cb=1724284800123' --state fired
Enter fullscreen mode Exit fullscreen mode

Validating the first line as fired fails a macro that is supposed to be there. Validating the second line as a template passes a shape you would never store, and it will also pass a dead token you should have caught. State only changes macro and empty-template behavior. A fired Meta Purchase URL without a numeric id is still vendor.meta.param.id.missing. Saying template will not invent an id. Core still applies in all three states: absolute URL, host present, http or https, no userinfo, fragments ignored, http flagged for upgrade. Vendor packs still apply when the host matches.

What to paste, and what not to paste

Paste the collector request. For a browser pixel that is facebook.com/tr, google-analytics.com/g/collect, ad.doubleclick.net/ddm/activity/..., ct.pinterest.com, analytics.tiktok.com. For a conversion API, set the format to JSON and paste the body the worker posts. Deep-link the box with ?kind=url or ?kind=json. Redact access tokens, raw emails, and cookies before the paste. A 64-character hex digest can stay. Artifacts you test on the site may be stored. The privacy note is the scope. The local CLI and pixellint-mcp do not send the artifact.

Do not paste the GTM loader and call it the conversion. Do not paste a Pixel Helper screenshot. Do not paste the base code snippet. The loader returning 200 only proves a container script was fetched. The conversion is the collector, or the JSON POST Pixel Helper cannot see.

Video ads add a third paste. A VAST document declares Impression and Tracking URLs. Those URLs are pixels: load beacons for impression and quartiles, a redirect chain for the click. The XML can be well formed and the fired start URL can still contain [CACHEBUSTER], or it can be http on an HTTPS player, or it can be the click URL reused as Impression. VAST tracking events are pixels is that split. Fetch the live tag in the VAST tester when the document still has to unwrap. Walk hops in the inspector when the player printed a wrapper error. Then paste the fired start URL into the pixel checker with --state fired. Two contracts, two pastes. Pixellint does not parse the VAST parent. vastlint does not decide whether the expanded URL is a legal Floodlight activity.

CI wants two fixtures, not a weekly HAR

One job, two states, two files. Run the template with --state template and the HAR-extracted URL with --state fired. For server bodies, pixellint validate json on a redacted production-shaped payload. Exit code 1 is an error-severity finding. Exit 0 still allows warnings. Exit 2 is a usage or input problem. A weekly archaeology session on a HAR does not catch the merge that shipped Date.now() as event_time. The fired JSON fixture does. A template fixture does not catch it, because that bug is not in the template. If you only store templates, you only test trafficking. If you only store HARs, you only test one serve, and you fail every legal macro in Ad Manager. Store both.

- uses: aleksUIX/pixellint@v0.31.10
  with:
    path: fixtures/conversion-pixel.txt
    kind: url
Enter fullscreen mode Exit fullscreen mode

The action downloads a prebuilt binary. It does not compile the rules on the runner. The same binary is what cargo install pixellint runs, which is what the playground runs. Pin the rulepack when the body has no host. A Meta JSON blob and a Snap JSON blob are both objects. action_source: website is Meta. action_source: web is Pinterest. WEB is Snap. Omit the field and more than one pack will speak.

Set the state on the command, not in a comment inside the URL. An agent that emits a pixel, a verification beacon, or a conversion body can still get HTTP 200 from the vendor. I maintain Pixellint. It is independent of Google, Meta, and IAB Tech Lab. It is the check on the artifact after the model or the trafficking sheet emits it, and before you treat a GIF or a 200 as proof the activity counted.

Top comments (0)