Cookie audit methodology for analytics stacks

last verified · against MDN, Chrome DevTools docs, RFC 6265 & ICO PECR guidance as of 2026-07

Cookie audit methodology for analytics stacks: the ICO audit checklist, cookie and Web Storage fields, DevTools inventory steps, and consent-gate classification.

What this is

A cookie audit is the systematic inventory of every cookie and client-side storage mechanism a site sets, recording each item’s attributes, purpose, lifespan, and party so it can be classified for consent. This reference lists the fields to capture, the DevTools locations that expose them, the ICO checklist an audit must satisfy, and the CMP categories the output maps onto.

Method — two-pass norm

The practical pattern is automation to discover, humans to classify. A single point-in-time scan of one page misses interaction-gated and consent-gated cookies, and JavaScript scanners cannot see HttpOnly or backend-set cookies at all — the ICO explicitly asks for “a combination of browser-based tools and server-side code review”.

Pass Tooling Catches
1. Discover Automated CMP scanner / crawler (e.g. Cookiebot, OneTrust) Cookies at scale; drafts the declaration
2. Verify Manual DevTools walk plus server-side code review Interaction- and consent-gated cookies; HttpOnly/backend cookies; resolves Unclassified
Pre-consent Fresh load with no interaction, then Reject-All Non-essential tags firing before opt-in (the regulatory defect)
Attribute What it controls / records
Domain Which hosts may receive the cookie
Path URL path that must match for the cookie to be sent
Expires Date/time at which the browser deletes the cookie
Max-Age Seconds until deletion; takes precedence over Expires when both are present
Secure Sent only over HTTPS
HttpOnly Not accessible to JavaScript / document.cookie
SameSite Cross-site send behaviour (see next table)

SameSite values

SameSite Sent when Notes
Strict Same-site / same-origin requests only
Lax Top-level navigations to the origin site Browser default when SameSite is not set
None Cross-site requests Requires Secure; DevTools flags these with a warning icon in Application and Network panels

Classification fields the audit must derive

Field Rule
Session vs persistent Session = no Max-Age and no Expires (persistent-flag false; removed when the session ends). Persistent = has Max-Age or Expires
First vs third party First party = set by and sent to the visited site. Third party = domain and/or scheme differs from the visited site (set via embedded iframes). Classify by domain, not by which company benefits
Name prefix __Secure- Signals it must be set with Secure from an HTTPS page
Name prefix __Host- Signals it must have Secure, must NOT carry Domain, and must set Path=/ (host-locked)

DevTools Cookies table — Application > Storage > Cookies

Column Reading
Name, Value Cookie identity; Show URL-decoded reveals unencoded values
Domain, Path Scope
Expires / Max-Age Displays the literal Session for session cookies
Size Cookie size in bytes; auto-updates and is not editable
HttpOnly, Secure, SameSite Security / scope flags
Partition Key Top-level site for partitioned cookies
Priority Low, Medium, or High

Filter by Name or Value (case-insensitive) via the Filter box. Double-click to edit any field except Size, double-click an empty row to add a cookie, delete a selected cookie, or Clear all.

Surface Lifetime / scope
Local Storage Partitioned by origin; persists after the browser is closed and reopened
Session Storage Partitioned per tab AND origin; destroyed when the tab closes
IndexedDB Structured client-side database
Web SQL Legacy
Application Cache Legacy
Extension Storage Browser-extension storage

Profile note: in private/incognito mode, localStorage behaves like sessionStorage — the APIs work but all data is deleted when the private window or tab closes. Choose the audit profile deliberately.

RFC 6265 storage minimums

These are floors a user agent SHOULD support, not per-browser ceilings.

Limit Minimum
Per cookie (name + value + attributes) 4096 bytes
Cookies per domain 50
Cookies total 3000

Real Chrome / Firefox / Safari ceilings differ and are not consistently documented across browsers — do not treat any single number as a universal hard limit.

Step Requirement
1 Identify every cookie operating on / through the site using browser-based tools AND server-side code review
2 Confirm the purpose(s) of each cookie
3 Confirm the type — session or persistent
4 Distinguish strictly necessary from non-essential
5 Determine each persistent cookie’s lifespan and whether the duration is justifiable
6 Determine first or third party, and who sets the third-party ones
7 Confirm whether cookies are linked to other user information (e.g. usernames) and whether personal data is processed
8 Identify what data each cookie holds / processes
9 Ensure the consent mechanism lets users control ALL non-essential cookies, including third-party
10 Double-check the privacy information is accurate for each cookie
11 Confirm what is shared with third parties and what users are told
12 Document findings and follow-up actions

Scope note: PECR regulation 6 covers “any similar technologies” beyond cookies — Local Shared Objects (Flash cookies), pixels, device fingerprinting, and any method of storing or accessing information on a device — so extend steps 1 to 12 to the non-cookie surfaces above.

Strictly-necessary exemption (ICO)

The exemption is narrow: a cookie must be essential to a service the user actually requested.

Consent needed? Examples
Exempt Online shopping-basket cookie; security session cookie essential to a requested service (e.g. online banking); load-balancing cookie
Consent required Analytics services; online advertising; cookies that are merely helpful or convenient; cookies essential only for the operator’s own purposes

The ICO states the legitimate purpose of facilitating a requested service “does not include third parties such as analytics services or online advertising” — so analytics and advertising cookies must be gated behind consent.

Rule Requirement
Positive action Consent must be freely given, specific and informed, given by a clear affirmative act (ticking / clicking) — more than continuing to use the site
No pre-enabling Non-essential cookies must not be pre-ticked and must not be set before consent, homepage included
No bundling Consent cannot be buried in terms and conditions or a privacy notice
Disclosure Give clear, comprehensive information on the purpose AND duration of each cookie
Scope of control The mechanism must let users control all cookies the site sets, including third-party

CMP category map (Cookiebot / Usercentrics)

The dominant model is a fixed set of four categories plus an Unclassified bucket. You can rename categories but cannot add or truly delete one, and consent is granted per entire category.

Category Definition / example
Necessary Scripts needed to guarantee website functionality (e.g. shopping-basket cookie)
Preferences Remembering user choices to navigate the site
Statistics Analytical purposes (e.g. Google Analytics cookies)
Marketing Targeting users with (personalized) ads (e.g. Facebook pixel)
Unclassified Category unknown; “may be necessary”; needs manual classification before publishing a declaration

This four-category scheme is a vendor convention, not a legal taxonomy — the IAB TCF uses a different purpose scheme.

Re-audit cadence (regulatory guidance)

The ICO does not set a fixed interval. It requires that the audit “build in an appropriate review period” and that teams “undertake regular reviews of your cookie usage, as well as any third party services your website includes that may set cookies”; fresh consent may be needed if cookie use changes. Any specific cadence (quarterly, monthly, twice-yearly) seen in vendor material is industry recommendation, not a regulatory requirement.

Gotchas

  1. Session cookie never clears between runs — browser session-restore keeps session cookies alive across restarts, so “until the session ends” can mean indefinitely. Fix: audit in a fresh/incognito profile, disable “continue where you left off”, and use Clear-Site-Data or DevTools “Clear all” between passes rather than relying on browser close.
  2. A third-party cookie shows a first-party Domain and slips the consent gate — code injected via a <script> tag runs in the embedder’s context and writes to first-party storage; the Domain column reflects where it was written, not who controls it. Fix: classify by who sets/controls the cookie and by the network domain of the requests that create it (Network panel, Set-Cookie headers), cross-referenced against the server-side vendor list.
  3. The published inventory is incomplete — the auditor inspected only the Cookies pane on the homepage; non-cookie storage and cookies that fire after interaction, on deeper pages, or after Accept were never captured. Fix: inspect every Application > Storage type and drive a runtime walk that navigates key journeys and clicks Accept / Reject / Customize.
  4. A scanner report is full of “Unclassified” and the declaration is challenged — the scanner’s database did not recognise the cookie or its purpose could not be determined. Fix: treat every Unclassified entry as a manual work item — research purpose and lifespan, confirm the setting party, assign a category by hand, and do not leave it ungated.
  5. A cookie expected on a cross-site request is silently not sent — with no SameSite attribute the browser defaults it to Lax and withholds it on cross-site subrequests; only SameSite=None; Secure is sent cross-site. Fix: record SameSite for every cookie and flag cross-site-dependent cookies lacking SameSite=None (DevTools surfaces them with warning icons).
  6. Non-essential cookies are set on the first page load before any consent choice — tags fire on page load instead of being gated on consent state; the ICO bars setting non-essential cookies before consent, homepage included. Fix: add a pre-consent pass (load with no interaction, and again with Reject-All) and treat any analytics/marketing cookie present as a defect to fix in the tag/CMP blocking configuration.

Quick recipes

List cookies the current origin exposes to JavaScript:

list-cookies.js
// document.cookie exposes only non-HttpOnly cookies for the current origin.
// HttpOnly and backend-set cookies need the DevTools Application panel
// or a server-side code review — the ICO asks for both.
document.cookie.split('; ').forEach((c) => console.log(c));

Dump both Web Storage areas (a separate audit surface from cookies):

dump-web-storage.js
for (const [label, store] of [['localStorage', localStorage], ['sessionStorage', sessionStorage]]) {
console.group(label);
for (let i = 0; i < store.length; i++) {
const key = store.key(i);
console.log(key, '=', store.getItem(key));
}
console.groupEnd();
}

Enumerate IndexedDB databases (part of Application > Storage):

list-indexeddb.js
// Run in the DevTools console (top-level await is allowed there).
console.log(await indexedDB.databases());

Pre-consent test pass — anything printed here is a compliance finding:

pre-consent-check.js
// Load the page fresh with NO consent interaction; repeat after Reject-All.
// ICO: no non-essential cookie may be set before consent, homepage included.
// Print everything present, then classify each cookie by hand.
console.table(
document.cookie.split('; ').filter(Boolean).map((c) => {
const [name, ...rest] = c.split('=');
return { name, value: rest.join('=') };
}),
);
// Repeat against Application > Storage (Local/Session Storage, IndexedDB).

Reset state between pre- and post-consent passes:

reset-between-passes.http
# Delete one cookie: re-send it expired. Max-Age wins over Expires when both set.
Set-Cookie: COOKIE_NAME=; Max-Age=0; Path=/
# Or clear every cookie for the registrable domain and its subdomains at once:
Clear-Site-Data: "cookies"

Sources

Verification notes: the ICO detailed-guidance page carries a banner that it is based on the previous version and a revised version is under consultation, so treat any post-consultation specifics as unverified. The ICO sets no fixed re-audit interval. RFC 6265 gives only minimum storage capabilities, not real per-browser limits. The Cookiebot/Usercentrics four-category model is a vendor convention, not a legal taxonomy; IAB TCF purposes are not mapped here. This is an implementation reference, not legal advice.

Changelog

  • — Initial version, verified against official documentation.

dataLayer

0 events · 0 sent

    • home /
      writing /writing
      guides /guides
      work /#work
      about /about
      colophon /colophon
      toggle analyst mode ctrl+.
      print session receipt /#receipt