What TermsFeed Free Cookie Consent stores in the browser and for how long
Cookie Consent stores the answer each visitor gives in 3 first-party cookies in the browser, for 365 days (12 months) by default. Cookie Consent uses no localStorage, sessionStorage, or IndexedDB. A visitor who clears cookies, switches browsers, or opens a private window while no other private window is open answers again.
The cookies decide whether the consent banner shows and which tagged scripts run on every page. Learn their format, their lifetime, and their limits before your own code reads them or your Privacy Policy describes them.
The 3 cookies Cookie Consent writes
Cookie Consent writes cookie_consent_level, cookie_consent_user_accepted, and cookie_consent_user_consent_token, all as first-party cookies of your own domain. It does not write any other cookie. Each cookie records the consent choice, a use the CNIL and the ICO treat as exempt from consent.
The cookie_consent_level cookie holds URL-encoded JSON, so decode it before you parse it.
| Cookie | What it holds | Example value |
|---|---|---|
cookie_consent_level |
The 4 categories with true or false, as a URL-encoded JSON object |
%7B%22strictly-necessary%22%3Atrue%2C%22functionality%22%3Afalse%2C%22tracking%22%3Atrue%2C%22targeting%22%3Afalse%7D |
cookie_consent_user_accepted |
true once the visitor answered |
true |
cookie_consent_user_consent_token |
A 12-character token of letters and digits that identifies the browser, or the value of the user_consent_token option |
q3ZT8bKx0LmA |
Decoded, the example value of cookie_consent_level is this object. The object always lists the 4 categories in this order.
{"strictly-necessary":true,"functionality":false,"tracking":true,"targeting":false}
An optional category your site does not use never runs, and user_consent_saved reports it as false, even when a cookie saved earlier holds true for it.
The 3 cookies share the same attributes: path=/, SameSite=Strict, and an expiry date. They do not carry an HttpOnly flag, because JavaScript writes them, so your own scripts read them too. The browser sends them to your server with requests from your own pages, but not with the first request of a visitor who arrives from another site. Secure appears only with cookie_secure, and domain= only with cookie_domain. Read the 3 cookies in JavaScript, PHP, Python, and Node.js with Read the Consent State.
The cookies appear at different moments, which matters when your code reads them.
cookie_consent_levelexists before the answer. Each page load of a visitor who has not answered writes it right afterrun()returns, with the categories that run on page load, such asstrictly-necessaryalone. This cookie alone never proves that the visitor answered.cookie_consent_user_acceptedmarks the answer. The visitor has answered only when this cookie holds exactlytrue.cookie_consent_user_consent_tokenfollows the consent type. Express consent writes it with the first answer. Implied consent writes it on any page load where it is missing, before or after the answer.- Every answer rewrites all 3. A click on the "I agree", "I decline", "Save my preferences", or implied-mode "OK" button writes the token, then
cookie_consent_user_accepted, thencookie_consent_level, before any callback runs. - A lost
cookie_consent_levelcookie removes the answer.cookie_consent_user_acceptedholdingtruewithout a validcookie_consent_levelcounts as no answer. Cookie Consent removes the copy ofcookie_consent_user_acceptedthat the current configuration writes, forcookie_domainor, without the option, for the hostname alone, and the consent banner asks again until the visitor answers.
How long consent lasts: 365 days by default
Consent lasts 365 days, counted from the last time Cookie Consent wrote the cookies, and the consent banner shows again once they expire. Each answer writes a fresh expiry date. Page loads of a visitor who answered leave the answer cookies as they are, so the 365 days run from the last answer, not from the last visit.
Browsers shorten that lifetime on their own. Safari caps every persistent cookie written through document.cookie at 7 days, according to the WebKit post on Intelligent Tracking Prevention 2.1. Safari visitors therefore see the consent banner again 7 days after they answer. Chrome caps any cookie expiry at 400 days, according to the Chrome developer blog, so a longer cookie_duration gives 400 days there.
Set a shorter lifetime with cookie_duration, a whole number of days. The value applies to all 3 cookies, and a fraction is rounded down to a whole day, so "30.9" gives 30 days. A value below 1 or not a number, such as 0, 0.5, -5, or "six months", gives 365 days, with the warning Invalid cookie_duration "<value>", using 365 days in the console when debug is on.
<script type="text/javascript" charset="UTF-8">
document.addEventListener('DOMContentLoaded', function () {
cookieconsent.run({
"notice_banner_type": "headline",
"consent_type": "express",
"language": "en",
"cookie_duration": 180
});
});
</script>
A new cookie_duration applies from the next write only. Cookies already saved in visitor browsers keep their original expiry date until the visitor answers again.
Rejecting does not delete cookies already set
Cookie Consent does not delete cookies that other scripts set, so turning a category off leaves the cookies of scripts that already ran in the browser. Scripts that ran on the current page keep running until the next page load, and they keep reading and writing their cookies there. From the next page load onward, Cookie Consent holds those scripts back.
Delete the first-party cookies of a refused vendor on the next page load, in the scripts_specific_loaded callback when it runs for strictly-necessary. With "callbacks_force": true, that call happens on every page load. The example removes the Google Analytics 4 cookies, _ga and _ga_<container-id>, whenever tracking is off. It expires each cookie on the host and on every parent domain. A cookie set with domain= stays until the code that deletes it names the same domain.
<script type="text/javascript">
function deleteCookieEverywhere(name) {
var expired = '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
var parts = window.location.hostname.split('.');
document.cookie = name + expired;
for (var i = 0; i < parts.length - 1; i++) {
document.cookie = name + expired + '; domain=' + parts.slice(i).join('.');
}
}
function deleteTrackingCookies() {
var levels = cookieconsent.cookieConsentObject.userConsent.acceptedLevels;
if (levels['tracking'] === true) {
return;
}
document.cookie.split(';').forEach(function (pair) {
var name = pair.split('=')[0].trim();
if (name === '_ga' || name.indexOf('_ga_') === 0) {
deleteCookieEverywhere(name);
}
});
}
</script>
<script type="text/javascript" src="https://www.termsfeed.com/public/cookie-consent/4.2.0/cookie-consent.js" charset="UTF-8"></script>
<script type="text/javascript" charset="UTF-8">
document.addEventListener('DOMContentLoaded', function () {
cookieconsent.run({
"notice_banner_type": "headline",
"consent_type": "express",
"language": "en",
"callbacks": {
"scripts_specific_loaded": function (level) {
switch (level) {
case 'strictly-necessary':
deleteTrackingCookies();
break;
}
}
},
"callbacks_force": true
});
});
</script>
Without callbacks_force, the callback runs only for categories that have tagged scripts, and most pages tag no strictly-necessary script. A script that writes the cookie again after the refusal sets it back, and your code deletes it again on the next page load. Your code deletes only cookies of your own domain, so cookies an ad network sets on its own domain stay out of reach.
How to force every visitor to answer again
Cookie Consent has no option that asks every visitor again. No change to an option other than demo, and no change to the texts of a self-hosted copy, shows the consent banner again to a visitor who answered. The cookies do not store a version, so a visitor who answered keeps the answer until the cookies expire. A category you add later to notice_banner_purposes_levels reads false for that visitor, with no consent banner, until the visitor opens the Preferences Center and accepts it.
Expire cookie_consent_user_accepted before Cookie Consent starts, and the consent banner shows again, with only the categories that run on page load switched on. Place this script before the Cookie Consent snippet, and change CONSENT_VERSION whenever every visitor must answer again.
<script type="text/javascript">
(function () {
// Change this value whenever every visitor must answer again
var CONSENT_VERSION = '2026-10';
var match = document.cookie.match(/(?:^|;\s*)site_consent_version=([^;]*)/);
if (!match || match[1] !== CONSENT_VERSION) {
// Add '; domain=example.com' to both lines when you set cookie_domain
document.cookie = 'cookie_consent_user_accepted=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
document.cookie = 'site_consent_version=' + CONSENT_VERSION + '; max-age=31536000; path=/; samesite=strict';
}
})();
</script>
The version script writes a cookie of your own, site_consent_version, so each visitor sees the consent banner again once per version. Deploy the new version together with the change that needs the new answer, such as a new tracking tool.
Secure cookies on HTTPS sites with cookie_secure
Turn on cookie_secure to add the Secure attribute to the 3 cookies, so browsers send them only over HTTPS. Use it only when every page of the site, on every hostname, loads over HTTPS. Browsers refuse a Secure cookie that an http: page writes. The answer then never saves, and the consent banner shows on every page.
<script type="text/javascript" charset="UTF-8">
document.addEventListener('DOMContentLoaded', function () {
cookieconsent.run({
"notice_banner_type": "headline",
"consent_type": "express",
"language": "en",
"cookie_secure": true
});
});
</script>
The cookies stay on one hostname unless you set cookie_domain. Share one answer across www.example.com, shop.example.com, and the other hostnames of your site with Share Consent Across Subdomains.
Demo mode does not write cookies
With demo: true, Cookie Consent writes none of the 3 cookies and shows the consent banner on every page load. Everything else works: the buttons release tagged scripts and run your callbacks, so you try the consent banner on a live site without leaving an answer behind.
Cookie Consent still reads cookies saved earlier without demo mode. Each demo answer takes its token from a token cookie saved earlier, else from user_consent_token, and gets a new token only when neither exists. Turn demo mode off before you go live.
Cookie Consent does not keep a record of the answer on a server
The answer exists only in the browser, so you do not hold a record of it unless your own code sends one. Keep a record from the user_consent_saved callback with Keep a Consent Log to Prove Consent.
How to check the 3 cookies in Chrome DevTools
Read the cookies in the Application tab of Chrome DevTools before and after an answer. Allow about 5 minutes for the 4 steps.
- Deploy any change to the cookie options and clear any page cache. Close every private window, open a new one, and load your site. The consent banner appears. Open Chrome DevTools before you answer.
- Select the Application tab, open Cookies, select your site, and type
cookie_consentin the filter box. In express consent with the defaultpage_load_consent_levels, confirm that onlycookie_consent_levelexists, withstrictly-necessarytrue. In implied consent,cookie_consent_user_consent_tokenexists too. - Click the "I agree" button, or the "OK" button in implied consent. Confirm that the 3 cookies now exist, that
cookie_consent_user_acceptedholdstrue, and that the Expires column shows a date 365 days ahead, or yourcookie_duration. - Confirm the Domain column shows your hostname, or
.example.comwhen you setcookie_domain, and that the Secure column is checked only withcookie_secure.