A visitor accepts on www.example.com and meets the banner again on shop.example.com because Klaro, CookieConsent and tarteaucitron all default to storing consent for the exact hostname. Each has one option that widens it to the parent domain. Setting that option is the easy half. The hard half is that a shared cookie is only safe if every subdomain runs the same consent configuration: we tested all three with a different service list on each subdomain, and each library handled it differently — one never asks about the new category, one re-prompts back and forth, and one merges cleanly.
Everything below was read from the released source and then run in headless Chromium in September 2026, with two hostnames, www.example.test and shop.example.test, mapped to a local server. Versions: CookieConsent (vanilla-cookieconsent) 3.1.0, Klaro 0.7.21, tarteaucitron 1.34.0 — the current npm releases as of that date.
Why the choice does not follow the visitor
There are two storage options and neither crosses a subdomain by default.
localStorage never does. It is scoped to the origin, meaning scheme, host and port. If you have switched Klaro to storageMethod: 'localStorage' or CookieConsent to useLocalStorage: true, no configuration will make a choice made on www visible on shop. In our test Klaro on shop reported no confirmed consent while www, in the same browser, still held it.
Cookies can, if the Domain attribute says so. RFC 6265 is short on this: with Domain=example.com the browser sends the cookie to example.com, www.example.com and anything else beneath it; without a Domain attribute, it goes back only to the host that set it. The three libraries do not agree on their default:
| Library | Option | Default, as stored by Chromium | Visible on a sibling subdomain? |
|---|---|---|---|
| CookieConsent 3.1.0 | cookie.domain |
cc_cookie on .www.example.test |
No |
| Klaro 0.7.21 | cookieDomain |
klaro on www.example.test, host-only |
No |
| tarteaucitron 1.34.0 | cookieDomain |
tarteaucitron on www.example.test, host-only |
No |
CookieConsent’s default is the subtle one. It sets cookie.domain to location.hostname and writes it as an explicit attribute, so the cookie is a domain cookie for www.example.com. That reaches www.example.com and hosts beneath it, but never shop.example.com, which sits beside it.
Widening the scope
One line each. A leading dot is ignored by the browser, so example.com and .example.com behave the same.
// CookieConsent 3.x
CookieConsent.run({
cookie: { domain: 'example.com' },
// ...
});
// Klaro
var klaroConfig = {
cookieDomain: '.example.com',
// ...
};
// tarteaucitron
tarteaucitron.init({
cookieDomain: '.example.com',
// ...
});
With that in place, all three shared the choice in our test: accept on www, load shop, no banner.
The wrong domain gives you a banner on every page
The browser rejects a Domain attribute that does not cover the current host. Hard-code example.com, deploy to staging.example.net or load the page on localhost, and the write fails silently. We ran all three libraries with example.com configured on www.example.test: no cookie was stored by any of them, and after a reload each one showed its banner again. Nothing throws: an assignment to document.cookie that the browser refuses simply does nothing.
Derive the value rather than hard-coding it:
// true on example.com and its subdomains; false on staging, previews, localhost
var shareConsent = /(^|\.)example\.com$/.test(location.hostname);
// CookieConsent: omit the key; do not pass domain: undefined
cookie: shareConsent ? { domain: 'example.com' } : {},
// Klaro
cookieDomain: shareConsent ? '.example.com' : undefined,
// tarteaucitron
cookieDomain: shareConsent ? '.example.com' : '',
The CookieConsent line is written that way on purpose. The library spreads your cookie object over its defaults, so an explicit domain: undefined replaces the hostname default instead of falling back to it.
Two limits no option gets around. Separate registrable domains, such as example.com and example.de, cannot share a cookie at all. And browsers refuse public suffixes, so co.uk is not a usable scope; example.co.uk is.
Sharing the cookie means sharing the configuration
This is the part the option names do not mention. Once two subdomains read the same cookie, each library interprets the other site’s record against its own list of categories or services. Subdomains built by different teams almost never have identical lists. So we gave shop one extra item, ads, accepted everything on www, then crossed over.
CookieConsent: the new category is never offered
CookieConsent treats a cookie as valid consent if it has a consent ID, timestamps, a matching revision and an array of categories. It does not check whether every category in the current configuration is present in that array. On shop it reported valid consent with ads not accepted, and showed no banner. The visitor was never asked about ads. That fails closed, since nothing runs, but the category will stay off until someone opens the preferences modal on their own.
The documented tool for “ask again” is revision, and it is a trap here, because the revision lives in the shared cookie too. With revision 0 on www and 1 on shop, each site found the other’s cookie invalid. Accept on www, prompted on shop; accept there, prompted on www; and again on the third crossing. Bumping the revision when a tracker is added is right on a single site. Across a shared cookie, every subdomain has to bump it together.
Klaro: correct on arrival, then it undoes the other site
Klaro checks the stored record against its own service list. On shop, ads had no entry, so Klaro marked consent unconfirmed and showed the notice. That is the right behaviour. After accepting, the cookie held {"analytics":true,"ads":true}.
The problem is the return trip. On load, Klaro deletes keys for services it does not know, in memory. The next time anything is saved on www (we changed one preference), it writes back only its own services. The cookie became {"analytics":false}, and on shop the notice was back. Visitors who adjust settings on one subdomain get asked again on the other, indefinitely.
One more thing to know if you set cookieDomain: resetConsents() deletes the cookie without passing the domain. In our test the shared cookie survived the call, and after a reload Klaro still reported the old consent as confirmed. If you expose a “reset” control, expire the cookie yourself with the same domain:
document.cookie = 'klaro=; Max-Age=0; path=/; domain=.example.com';
tarteaucitron: it merges
tarteaucitron stores one string of !service=value pairs, and each write replaces only its own key. On shop the banner appeared because ads had no answer. After accepting, the cookie read !analytics=true!ads=true, and www carried on without prompting. Of the three, it is the only one that tolerated divergent lists in this test.
What to do with this
- Serve one consent configuration to every subdomain that shares the cookie. Same categories, same services, same revision, loaded from one file. Every failure above comes from two configs reading one record.
- If the lists genuinely differ, do not share. Leave the domain unset, or give each site its own cookie name. Asking twice is better than a record that two sites keep rewriting.
- Remember that every subdomain can write it. A cookie scoped to
example.comcan be read and overwritten from any host under that domain, including a help centre or landing-page builder CNAMEd to a third party. - Be explicit about scope in the banner. Whether one choice may cover several sites is not something the storage layer decides. For the related multi-device case, the CNIL asks that people are told the scope before they choose.
To check a live site, open DevTools on each subdomain, go to Application, then Cookies, and read the Domain column for the consent cookie. Then change one preference on one host and reload the other. If a banner appears, one of the failures above is what you are looking at. If the consent cookie also dies when the browser quits on Safari, check how its Expires value is formatted.
A shared consent cookie is only as good as the subdomain that loads the most trackers. Scan each subdomain for what loads before consent with CookieInspector.