Six lines in one US checkout file ignore Global Privacy Control, and the lint returns nine findings on them — for US front-end developers who own the ad-tag code.
The output, before a word of explanation:
analytics/tags.js
3: [error] Do Not Track is not an opt-out preference signal under any US state privacy law. The twelve states that require a universal signal recognise Global Privacy Control, not DNT.
4: [error] Advertising storage defaults to granted, so a GPC visitor is already shared on the very first page load, before any banner logic runs.
5: [error] A Google Ads (AW-) tag is a share for cross-context advertising. It has to be gated on the opt-out signal, not only on an EU cookie banner.
5: [error] Google Signals turns Analytics data into cross-context advertising audiences. That is a share you must stop for a GPC visitor.
6: [error] Meta Pixel init sends identifiers to Meta for cross-context behavioural advertising, which is a sale or share. It must not run for a visitor whose browser sent Global Privacy Control.
6: [error] Advanced matching is passing a raw email or phone number to an ad platform. That is a sale of an identifier, and the field must be SHA-256 hashed even for a visitor who has not opted out.
7: [error] The TikTok pixel is cross-context behavioural advertising. A visitor in the twelve opt-out-signal states who sent GPC must not have it loaded at all.
8: [error] Honouring the signal for California alone misses the other eleven states that require it as of 1 January 2026.
8: [warn] Since CPRA the required wording is "Do Not Sell or Share My Personal Information", or the single combined link titled "Your Privacy Choices".
—— 9 ——
Nine findings on six lines, in a file that passed review. navigator.doNotTrack is the worst: the signal the states recognise is navigator.globalPrivacyControl, a boolean, and the Sec-GPC header, whose value is 1 and never "true" — a detail that kills server-side opt-outs which compile, ship, and never once evaluate true.
The last finding has a date attached. As of 1 January 2026, twelve states require an opt-out preference signal to be honoured: California, Colorado, Connecticut, Delaware, Maryland, Minnesota, Montana, Nebraska, New Hampshire, New Jersey, Oregon and Texas. A California-only check misses eleven of them.
Why your scanner did not catch it
Your scanner loads a page: it sees the tags that fired for one region, one consent state, one code path. It cannot see the isEU branch that never runs for a US visitor, or a pixel behind a feature flag. And it runs after the deploy, which is after the share. The lint reads the source instead — the same twenty rules, in the editor, before the merge.
What being wrong costs
On 30 September 2025 the California Privacy Protection Agency settled with Tractor Supply for $1.35 million, its largest penalty to date. Failing to provide an effective opt-out from the sale and sharing of personal information, including via Global Privacy Control, was one of the counts. That same month the CPPA joined the Attorneys General of California, Colorado and Connecticut in a coordinated investigative sweep pointed directly at GPC.
The fix
Read the signal once — navigator.globalPrivacyControl === true || req.headers['sec-gpc'] === '1' — gate every tag on it, check the region against all twelve states rather than 'CA', and default ad_storage to 'denied'. Run the lint again and it returns nothing: the same twenty rules, the same file, zero findings.
Opt-Out Signal Lint audits the file you have open for free: all 20 rules, every line, no key, no cap. A licence key adds the different job — the whole-workspace sweep, a CSV, JSON or HTML export, and a CI exit code so a fixed leak cannot merge back in. Osano, the nearest hosted consent platform, starts at $199/month. This is $29 once, one licence key per person or team seat, 7-day full refund.
Free in your browser (the same rules): https://getreadystack.com/tools/optout-signal-lint
Licence ($29, once, 7-day refund): https://buy.polar.sh/polar_cl_gj151VTqWFpXoYSJLn1MtTGUJrDV3N8bEeFLH4cORhY

Top comments (0)