Cookie Scanner
Audit the cookies actually present against the cookies you declare — surface undeclared trackers that fall outside your cookie notice (NDPA 2023 S.25-26 / NDPC GAID 2025)
What this covers
Under NDPA 2023 Sections 25–26 and the NDPC GAID 2025 directive, consent for non-essential cookies must be specific and informed — which means the cookies your site actually sets should match the categories your notice describes. In practice, third-party scripts quietly drop cookies that were never declared. scanCookies() finds that gap.
It compares the cookies actually present against the cookies you declare and reports which are declared, which are undeclared (the compliance gap), which undeclared ones a built-in registry can still identify, and which remain fully unknown. It is a pure function with no React dependency and is DOM-optional — pass a cookie string (a Cookie: header server-side, or a test fixture) or let it read document.cookie in the browser. It ships from /core, /consent, /server, and the package root, plus the useCookieScan hook for client UIs.
A compliance-discovery aid, not legal advice
The scanner reads the cookies present in a given context and classifies them. It can't see cookies set on other pages, in other browsers, or by scripts that haven't run yet — run it where your third-party tags load, and verify against current NDPC guidance.
Using scanCookies()
Declare the cookies you expect — by exact name, a prefix, or a RegExp — each tagged with a consent category, and optionally a provider and purpose for your cookie policy:
import { scanCookies } from '@tantainnovative/ndpr-toolkit/core'; // or /server
const scan = scanCookies(
[
{ name: 'sid', category: 'necessary', provider: 'App', purpose: 'Login session' },
{ name: 'app_', prefix: true, category: 'functional' },
{ name: /^analytics-[0-9]+$/, category: 'analytics' },
],
{ cookieString: document.cookie }, // omit entirely in the browser to read it automatically
);
scan.total; // number of cookies present
scan.complete; // false while any undeclared cookie is present
scan.declared; // cookies that matched one of your declarations
scan.undeclared; // present but NOT declared — the compliance gap
scan.identified; // undeclared, but the registry knows them (_ga -> Google Analytics, ...)
scan.unknown; // undeclared and unidentifiable
scan.byCategory; // present cookies grouped by resolved category ('uncategorized' for nulls)On the server, pass a Cookie header instead — scanCookies(declared, { cookieString: req.headers.cookie ?? '' }) — which makes it safe to run inside Server Components, middleware, or a CI check.
Reading the result
Every present cookie is returned in scan.cookies as a ScannedCookie with how it was matched:
// ScannedCookie
{
name: '_ga',
category: 'analytics', // resolved category, or null when unclassified
matchedBy: 'known', // 'declared' | 'known' | 'none'
provider: 'Google Analytics',
purpose: 'Distinguishes users',
}- declared —
matchedBy: 'declared': matched one of your declarations. - identified —
matchedBy: 'known': undeclared, but recognised by the built-in registry. - unknown —
matchedBy: 'none': undeclared and unidentifiable.
undeclared is identified + unknown — the list to act on. Drop it into CI to fail a build when an unexpected cookie appears, or render it in a DPO dashboard.
The known-cookie registry
A built-in KNOWN_COOKIES registry recognises widely deployed third-party cookies — Google Analytics/GA4, Google Ads, Meta, Hotjar, Microsoft Clarity, LinkedIn, Stripe, HubSpot, TikTok, Intercom, and others — so undeclared cookies are usually still identified with a provider and a likely category. Your own declarations always take precedence over the registry.
// Extend the registry for tools it doesn't know yet
scanCookies(declared, {
knownCookies: [{ name: 'acme_pixel', category: 'marketing', provider: 'Acme Ads' }],
});
// Or rely solely on your own declarations
scanCookies(declared, { useKnownRegistry: false });The useCookieScan hook
For client UIs, useCookieScan (from /hooks) scans on mount and returns a stable rescan() to re-run after you set or clear cookies. result is null until the first client-side scan, so server and first client render agree — no hydration mismatch.
'use client';
import { useCookieScan } from '@tantainnovative/ndpr-toolkit/hooks';
function CookieAudit() {
const { result, rescan } = useCookieScan([
{ name: 'sid', category: 'necessary' },
]);
if (!result) return null; // pre-scan (SSR / first render)
return (
<div>
<p>{result.undeclared.length} undeclared cookie(s)</p>
<button onClick={rescan}>Re-scan</button>
</div>
);
}