Global Privacy Control is not a banner feature. It is an HTTP header that arrives on the first request, before your consent script exists. Every Californian enforcement action over it between July 2025 and February 2026 punished a site that detected the signal and then applied it too narrowly — Disney paid $2.75m in February for scoping it to one device while the user was logged in. Klaro 0.7.21 and CookieConsent 3.1.0 contain no GPC code at all; c15t 2.2.1 does, but reads only the JavaScript property. What honouring it actually requires, in code.
The state-by-state tables, including ours, all have a column that says “GPC Required: Yes”. None of them tell you what your code has to do. That gap is where the fines are.
The signal is three surfaces, and only one is early enough
The specification lives at w3c.github.io/gpc/. It defines three things, and they are routinely confused with one another.
Sec-GPC: 1— a request header. The field-value is exactly the numeric character1. Your server sees it on the very first request, before a byte of HTML is parsed.navigator.globalPrivacyControl— a read-only boolean. Same information, available only once JavaScript runs./.well-known/gpc.json— this one points the other way. You serve it. It carriesgpcandlastUpdate, and the spec says thegpcmember “MUST be eithertrue, to indicate that the server intends to abide by GPC requests at least to the extent it is legally obligated to do so, orfalse“. It is your declaration, not the user’s.
The first two carry the same value — the spec ties both to the browsing context’s gpcAtNavigation, cached when the page began loading. They differ only in when you can read them, and that difference is the whole engineering problem. A tag that fires from a <script> in the head has already run by the time a client-side check reports the signal.
The failure is scope, not detection
On 11 February 2026 the California Attorney General announced a $2.75m settlement with Disney, the largest CCPA settlement in the state’s history at the time. The GPC allegation is worth reading closely:
“For consumers who opted out via the Global Privacy Control (GPC), Disney limited the request to the specific device the consumer was using, even when the consumer was logged into their account.”
Disney read the signal. Disney acted on the signal. Disney applied it to the browser that sent it, which is the obvious implementation and the one almost every hand-rolled integration produces. That was the violation.
The CPPA’s own guidance is explicit about scope. A business receiving an opt-out preference signal must stop selling and sharing personal information associated with all three of:
- That browser or device.
- Any profile, including pseudonymous profiles (their example is
user1234), associated with that browser or device. - “The consumer, if known. If a consumer is logged into their account with the business while visiting the business’s website, the business knows the identity of the consumer and must apply the OOPS to all personal information associated with the consumer’s account.”
Point three turns a front-end problem into a back-end one. If your site has accounts, GPC is not something your consent library can finish for you — it has to reach whatever holds the user’s advertising preferences server-side. The deadline is 15 business days.
What the open-source libraries actually ship
We grepped the published npm tarballs and the repository trees today, for every spelling we could think of. The result is cleaner than expected:
| Library | Version / licence | GPC support |
|---|---|---|
klaro |
0.7.21, BSD-3-Clause | None. Zero matches in package or repo. |
vanilla-cookieconsent |
3.1.0, MIT | None. Zero matches in package or repo. |
c15t |
2.2.1, Apache-2.0 | Yes, client-side property only. |
The only GPC strings in the Klaro and CookieConsent repositories are substrings of base64 integrity hashes inside package-lock.json. Neither library has ever implemented the signal. This is not a criticism — both are consent interfaces built for an opt-in jurisdiction, and GPC is an opt-out mechanism from a different legal tradition. But if you deployed either one and assumed the “GPC Required: Yes” box was ticked, it is not.
c15t does implement it. It exports hasGlobalPrivacyControlSignal(), and its own source comment sets the boundary honestly: the helper is “intentionally conservative and only checks for the presence of the client-side navigator.globalPrivacyControl flag”. Its policy packs carry a consent.gpc flag which, under the opt-out and none consent models, denies marketing and measurement instead of auto-granting them. That is real support, and it still leaves you the header and the account scope.
A minimal implementation that survives the scope test
Read the header at the edge, because it is the only surface available before your tags are. Anything that can set a cookie or render a variable into the document will do — middleware, a reverse proxy, a template.
// Edge middleware. Runs before any tag exists.
const gpc = request.headers.get('sec-gpc') === '1';
// Expose it to the document, and to the tag layer, synchronously.
response.headers.set('Set-Cookie', `gpc=${gpc ? '1' : '0'}; Path=/; SameSite=Lax`);
Then gate before anything loads, rather than reacting after it has:
<script>
// Inline, first thing in <head>. No await, no library.
var gpc = document.cookie.indexOf('gpc=1') !== -1
|| navigator.globalPrivacyControl === true;
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
if (gpc) {
gtag('consent', 'default', {
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied',
analytics_storage: 'denied',
security_storage: 'granted'
});
gtag('set', 'ads_data_redaction', true);
}
</script>
The cookie check comes first and the navigator check is the fallback, not the other way round: the header path works even where the property has not been populated yet.
Three rules from the CPPA guidance that shape the interface, and that are easy to get backwards:
- Do not interrupt the user. A “frictionless” response must not “Display a notification, pop-up, text, graphic, animation, sound, video, or any interstitial content in response to the OOPS.” Showing a banner because someone sent GPC is the wrong reflex. Displaying the resulting opt-out status is explicitly fine.
- The signal beats your stored setting. If GPC conflicts with a site-specific preference allowing sale or sharing, the business “must apply the OOPS unless the consumer states otherwise”.
- You may ask them to opt back in once a year. For a known consumer, once every 12 months. Not on every visit.
The timing problem is about to become a rule
At its meeting of 6–7 August 2026 the CPPA took staff recommendations on opt-out preference signal rulemaking, drawn from 43 written comments running to 376 pages. Four recommendations went to the Board: identify GPC explicitly as an opt-out preference signal in the regulations; add examples covering pseudonymous profiles; require reporting of OOPS metrics; and add “Examples Clarifying Timing Issues Regarding GPC and Sale / Share Tracking Technologies”.
That last one is the section above, written by a regulator. The gap between the header arriving and the tag being gated is now a named rulemaking topic.
Stage matters here. These are staff recommendations for Board consideration in a preliminary rulemaking. They are not adopted regulations, there is no compliance date, and the text may change or go nowhere. What is already binding is the existing s.7025 obligation and the enforcement record against it.
In the EU, GPC cannot grant anything
GPC expresses a refusal. Under the GDPR and ePrivacy the absence of consent is already the default, so a European visitor sending GPC does not change your legal position — you needed an affirmative act before you could fire anything regardless. It cannot be read as consent, and no EU instrument currently makes it binding on controllers. The provision that would have, Digital Omnibus Article 88b, was dropped from the Council’s compromise text of 18 June 2026 and has stayed out since; the Council has adopted no position.
Honouring it in Europe anyway costs you nothing and is a defensible reading of an objection. Just do not build your EU banner logic around it.
Why this gets harder in 2027
Today GPC traffic is small. The project lists Brave, DuckDuckGo (on by default), Firefox (in settings) and a handful of extensions; Chrome, Safari and Edge are absent. Its own figures claim over 150 million users and more than 66,000 participating websites, which is the project’s number rather than an audited one.
That changes. AB 566, the California Opt Me Out Act, was chaptered on 8 October 2025 and takes effect on 1 January 2027. It requires browser developers to include consumer-configurable functionality for sending an opt-out preference signal. It binds browser makers, not websites — your obligations do not change on that date. Your traffic does. A signal that today arrives from a privacy-conscious minority will arrive from whatever share of users find a toggle in a mainstream browser.
Colorado gives a preview of the direction: GPC was the first universal opt-out mechanism recognised under the Colorado Privacy Act, remains the only one on the Department’s list, and controllers have been required to honour it since 1 July 2024.
Method
Checked 2026-09-07. Specification text from w3c.github.io/gpc/. Scope, timing and frictionless requirements from the CPPA’s own “What Is OOPS And How Does A Business Respond?” guidance (supporting resources: Civil Code s.1798.135(b), (e); 11 C.C.R. ss.7025, 7026) and from the Agency’s 6–7 August 2026 board materials. Settlement figures from California Attorney General press releases: Disney, 11 February 2026, $2.75m; Healthline Media, 1 July 2025, $1.55m. The CPPA’s own timeline slide lists Healthline, Tractor Supply, PlayOn Sports and Disney as GPC-related actions between July 2025 and February 2026. AB 566 status from the Legislature’s bill record. Library support determined by grepping the published npm tarballs and the master trees of kiprotect/klaro and orestbida/cookieconsent case-insensitively for globalPrivacyControl, Sec-GPC, privacyControl, doNotSell, globalprivacy and GPC — a null result on one spelling proves nothing, so all six were run. Versions move; re-check before relying on any of this.
The check that matters is what your site does on a request that carries Sec-GPC: 1 — not what your banner says afterwards. Scan your site and see what actually fires with CookieInspector.