The Cookie Scanner is a compliance auditing tool that helps you detect undeclared cookies on your website. This is essential for maintaining compliance, especially when marketing teams or third-party integrations add tracking scripts without updating your consent configuration.
The Cookie Scanner monitors all cookies present in the browser and compares them against your declared services configuration. It automatically classifies cookies and identifies compliance issues before they become regulatory problems.
Consider this scenario: You configure your consent banner with Google Analytics and Meta Pixel. Your banner accurately tells users "We use 8 cookies". But then your marketing team adds Hotjar for heatmaps, and someone embeds a third-party widget that sets its own cookies. Suddenly, your site is setting 15 cookies, but your banner only knows about 8.
This is a compliance violation. Users aren't being informed about all the cookies, and they're not given the chance to consent to them. Under GDPR, LGPD, and similar laws, this can result in significant fines.
The Cookie Scanner solves this by:
- Scanning all cookies in the browser in real-time
- Comparing them against your declared services
- Identifying cookies from known services that aren't in your config
- Detecting completely unknown cookies that need investigation
- Generating compliance reports for documentation
- Providing actionable suggestions for fixing issues
- During development: Verify that your consent configuration matches the cookies being set
- Before deployment: Audit your site to ensure compliance before going live
- In production: Monitor for cookies added by third-party scripts or team members
- Regular audits: Schedule periodic scans to maintain ongoing compliance
- After changes: Verify compliance after adding new features or integrations
The scanner uses a three-tier classification system to categorize every cookie found in the browser:
Declared Cookies (OK)
- The cookie belongs to a service that IS in your configuration
- The cookie pattern matches a preset AND that service is declared
- Example:
_gamatches Google Analytics, andgoogleAnalyticsis in your services array - Status: Compliant - no action needed
Known Cookies (Warning)
- The cookie belongs to a known service preset that is NOT in your configuration
- The library recognizes the cookie, but you haven't declared it
- Example:
_hjSession_123matches Hotjar, buthotjaris not in your services array - Status: Non-compliant - add the service to your configuration
Unknown Cookies (Error)
- The cookie doesn't match any preset in the library
- Could be from a custom integration, new service, or unexpected script
- Example:
custom_tracker_xyzdoesn't match any known pattern - Status: Non-compliant - investigate the source and create a custom preset if needed
The scanner uses pattern matching to identify cookies. Patterns support wildcards:
_gamatches exactly_ga_ga_*matches_ga_ABC123,_ga_XYZ789, etc.*_sessionmatchesuser_session,admin_session, etc.
This allows the scanner to recognize cookies even when they have dynamic suffixes or prefixes.
The scanner automatically ignores common system and framework cookies that don't require consent:
- Session cookies (
PHPSESSID,JSESSIONID,ASP.NET_SessionId) - CSRF tokens (
csrf,XSRF-TOKEN,_csrf) - Framework cookies (
__next,__vercel,NEXT_*) - Authentication cookies (
auth,token) - Your own consent cookie (
consent,cookie_consent)
You can customize this list with additional cookies or patterns to ignore.
The useCookieScanner hook provides a React-friendly interface for cookie scanning.
import { useCookieScanner, googleAnalytics, metaPixel } from 'react-consent-shield';
function CookieAuditPanel() {
const {
result,
isScanning,
isCompliant,
issueCount,
scan,
downloadReport,
} = useCookieScanner(
[googleAnalytics, metaPixel], // Your declared services
{ autoScan: true } // Scan automatically on mount
);
if (!result) {
return <p>Scanning cookies...</p>;
}
if (isCompliant) {
return (
<div>
<p>All cookies are properly declared.</p>
<p>Total cookies found: {result.totalFound}</p>
<button onClick={scan}>Re-scan</button>
</div>
);
}
return (
<div>
<h3>{issueCount} compliance issues found</h3>
{result.knownNotDeclared.length > 0 && (
<div>
<h4>Cookies detected but not declared:</h4>
<ul>
{result.knownNotDeclared.map((cookie) => (
<li key={cookie.name}>
<strong>{cookie.name}</strong> belongs to {cookie.matchedPreset?.name}.
<br />
Add <code>{cookie.matchedPreset?.id}</code> to your services array.
</li>
))}
</ul>
</div>
)}
{result.unknown.length > 0 && (
<div>
<h4>Unknown cookies (investigate origin):</h4>
<ul>
{result.unknown.map((cookie) => (
<li key={cookie.name}>
<strong>{cookie.name}</strong> - Size: {cookie.size} bytes
<br />
{cookie.suggestion}
</li>
))}
</ul>
</div>
)}
<button onClick={scan}>Re-scan</button>
<button onClick={() => downloadReport('csv')}>Download CSV Report</button>
<button onClick={() => downloadReport('json')}>Download JSON Report</button>
</div>
);
}import { useCookieScanner } from 'react-consent-shield';
import { useEffect } from 'react';
function ComplianceMonitor() {
const { result, isCompliant, scan } = useCookieScanner(
declaredServices,
{
autoScan: true,
scanInterval: 60000, // Re-scan every minute
onIssueFound: (scanResult) => {
// Alert when issues are detected
console.error('Compliance issues found:', scanResult.summary.suggestions);
// Send to monitoring service
fetch('/api/compliance-alert', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
timestamp: scanResult.timestamp,
issues: scanResult.summary.issues,
suggestions: scanResult.summary.suggestions,
}),
});
},
onScanComplete: (scanResult) => {
console.log('Scan completed:', {
compliant: scanResult.summary.compliant,
totalCookies: scanResult.totalFound,
});
},
ignoreCookies: ['my_custom_session', 'app_state'],
ignorePatterns: ['temp_*', 'cache_*'],
}
);
useEffect(() => {
if (result && !isCompliant) {
// Show notification to admin
showAdminNotification('Cookie compliance issues detected');
}
}, [result, isCompliant]);
return (
<div>
<p>Compliance Status: {isCompliant ? 'OK' : 'Issues Found'}</p>
{result && (
<ul>
<li>Declared: {result.summary.declaredCount}</li>
<li>Known but not declared: {result.summary.knownNotDeclaredCount}</li>
<li>Unknown: {result.summary.unknownCount}</li>
</ul>
)}
</div>
);
}| Property | Type | Description |
|---|---|---|
result |
ScanResult | null |
Latest scan result with all details |
isScanning |
boolean |
Whether a scan is currently in progress |
lastScan |
Date | null |
Timestamp of the last completed scan |
isCompliant |
boolean | null |
Whether the site is compliant (null if not scanned) |
issueCount |
number |
Number of compliance issues found |
scan() |
function |
Manually trigger a new scan |
getReport(locale?) |
function |
Get formatted text report in specified locale |
exportJSON() |
function |
Export result as JSON string |
exportCSV() |
function |
Export result as CSV string |
downloadReport(format, filename?) |
function |
Download report as file |
You can also use the scanner functions directly without React hooks.
The main scanning function that performs the complete analysis.
import { scanCookies } from 'react-consent-shield';
const result = scanCookies(
declaredServices, // Your configured services
allKnownPresets, // All available presets (from library)
{
ignoreCookies: ['my_cookie'],
ignorePatterns: ['temp_*'],
valueTruncateLength: 20,
}
);
console.log('Compliant:', result.summary.compliant);
console.log('Issues:', result.summary.issues);
console.log('Suggestions:', result.summary.suggestions);Parameters:
declaredServices: Array of ServicePreset objects from your configurationallKnownPresets: Array of all known presets (importallPresetsfrom the library)options: Optional ScannerOptions object
Returns: ScanResult object containing:
timestamp: When the scan was performedtotalFound: Total number of cookies founddeclared: Array of properly declared cookiesknownNotDeclared: Array of known cookies not in your configunknown: Array of completely unknown cookiessummary: Summary with compliance status and suggestions
Generate a human-readable text report from scan results.
import { formatScanReport } from 'react-consent-shield';
const textReport = formatScanReport(result, 'en');
console.log(textReport);
// Example output:
// === Cookie Scan Report ===
// Date: 2025-12-01T10:30:00.000Z
// Total cookies found: 12
//
// [!] ISSUES FOUND - 3 problem(s)
//
// [WARN] Known but not declared (2):
// - _hjSession_123 -> Add hotjar
// - intercom-session -> Add intercom
//
// [ERR] Unknown cookies (1):
// - custom_tracker -> Investigate originParameters:
result: ScanResult object from scanCookieslocale: Language code ('en' or 'es'), defaults to 'en'
Returns: Formatted string report
Export scan results as a JSON string for storage or API transmission.
import { exportScanResultJSON } from 'react-consent-shield';
const jsonString = exportScanResultJSON(result);
const jsonData = JSON.parse(jsonString);
// Save to file
const blob = new Blob([jsonString], { type: 'application/json' });
const url = URL.createObjectURL(blob);
// ... download logicReturns: JSON string with structured scan data
Export scan results as CSV for spreadsheet analysis.
import { exportScanResultCSV } from 'react-consent-shield';
const csvString = exportScanResultCSV(result);
// Example CSV output:
// Cookie Name,Classification,Service ID,Service Name,Category,Pattern,Suggestion
// "_ga","declared","google-analytics","Google Analytics","analytics","_ga",""
// "_hjSession_123","known_not_declared","hotjar","Hotjar","analytics","_hjSession_*","Add hotjar to config"
// "custom_tracker","unknown","","","","","Investigate origin"Returns: CSV formatted string
parseBrowserCookies
Parse all cookies from document.cookie:
import { parseBrowserCookies } from 'react-consent-shield';
const cookies = parseBrowserCookies({
ignoreCookies: ['session'],
ignorePatterns: ['_app_*'],
valueTruncateLength: 30,
});
// Returns: Array of ScannedCookie objects
// [
// {
// name: '_ga',
// value: 'GA1.2.123456789.1...', // truncated
// size: 45,
// foundAt: Date
// },
// ...
// ]matchesCookiePattern
Check if a cookie name matches a pattern:
import { matchesCookiePattern } from 'react-consent-shield';
matchesCookiePattern('_ga', '_ga'); // true
matchesCookiePattern('_ga_ABC123', '_ga_*'); // true
matchesCookiePattern('user_session', '*_session'); // true
matchesCookiePattern('other', '_ga'); // falsefindPresetForCookie
Find which preset a cookie belongs to:
import { findPresetForCookie, allPresets } from 'react-consent-shield';
const match = findPresetForCookie('_ga', allPresets);
if (match) {
console.log('Service:', match.preset.name); // "Google Analytics"
console.log('Pattern:', match.pattern); // "_ga"
console.log('Category:', match.preset.category); // "analytics"
}Configure the scanner's behavior with these options:
| Option | Type | Default | Description |
|---|---|---|---|
ignoreCookies |
string[] |
[] |
Additional cookie names to ignore |
ignorePatterns |
string[] |
[] |
Additional patterns to ignore (supports wildcards) |
valueTruncateLength |
number |
20 |
Maximum length of cookie values in reports (for privacy) |
The useCookieScanner hook accepts additional options:
| Option | Type | Default | Description |
|---|---|---|---|
autoScan |
boolean |
false |
Automatically scan when component mounts |
scanInterval |
number | null |
null |
Re-scan interval in milliseconds (null = no auto-rescan) |
onIssueFound |
function |
- | Callback fired when issues are detected |
onScanComplete |
function |
- | Callback fired after each scan completes |
knownPresets |
ServicePreset[] |
allPresets |
Custom list of known presets to check against |
The scanner ignores these cookies by default:
// Framework cookies
'__next', '__nextauth', 'next-auth', '__vercel'
// Session cookies
'session', 'sessionid', 'PHPSESSID', 'JSESSIONID', 'ASP.NET_SessionId'
// CSRF tokens
'csrf', 'csrftoken', '_csrf', 'XSRF-TOKEN'
// Authentication
'auth', 'token'
// Consent management
'consent', 'cookie_consent''NEXT_*' // Next.js cookies
'__Host-*' // Secure host cookies
'__Secure-*' // Secure cookiesAdd your own cookies or patterns to ignore:
const { result } = useCookieScanner(services, {
ignoreCookies: [
'my_app_session',
'user_preferences',
'theme',
],
ignorePatterns: [
'cache_*', // Ignore all cache cookies
'temp_*', // Ignore temporary cookies
'*_internal', // Ignore internal tracking
'dev_*', // Ignore development cookies
],
});Create a compliance dashboard for site administrators:
import { useCookieScanner, allPresets } from 'react-consent-shield';
import { useState } from 'react';
function AdminComplianceDashboard({ declaredServices }) {
const {
result,
isScanning,
isCompliant,
issueCount,
scan,
downloadReport,
getReport,
} = useCookieScanner(declaredServices, { autoScan: true });
const [showDetails, setShowDetails] = useState(false);
if (isScanning) {
return <div>Scanning cookies...</div>;
}
if (!result) {
return <button onClick={scan}>Run Cookie Scan</button>;
}
return (
<div className="compliance-dashboard">
<h2>Cookie Compliance Status</h2>
<div className={`status ${isCompliant ? 'ok' : 'warning'}`}>
{isCompliant ? (
<>
<span className="icon">✓</span>
<span>All cookies properly declared</span>
</>
) : (
<>
<span className="icon">⚠</span>
<span>{issueCount} compliance issues detected</span>
</>
)}
</div>
<div className="stats">
<div className="stat">
<h3>{result.totalFound}</h3>
<p>Total Cookies</p>
</div>
<div className="stat">
<h3>{result.summary.declaredCount}</h3>
<p>Declared</p>
</div>
<div className="stat">
<h3>{result.summary.knownNotDeclaredCount}</h3>
<p>Not Declared</p>
</div>
<div className="stat">
<h3>{result.summary.unknownCount}</h3>
<p>Unknown</p>
</div>
</div>
{!isCompliant && (
<div className="issues">
<h3>Action Required</h3>
<ul>
{result.summary.suggestions.map((suggestion, idx) => (
<li key={idx}>{suggestion}</li>
))}
</ul>
</div>
)}
{showDetails && (
<div className="details">
<h3>All Cookies</h3>
{result.declared.length > 0 && (
<>
<h4>Declared Cookies ({result.declared.length})</h4>
<table>
<thead>
<tr>
<th>Cookie</th>
<th>Service</th>
<th>Category</th>
</tr>
</thead>
<tbody>
{result.declared.map((cookie) => (
<tr key={cookie.name}>
<td><code>{cookie.name}</code></td>
<td>{cookie.matchedPreset?.name}</td>
<td>{cookie.category}</td>
</tr>
))}
</tbody>
</table>
</>
)}
{result.knownNotDeclared.length > 0 && (
<>
<h4>Known but Not Declared ({result.knownNotDeclared.length})</h4>
<table>
<thead>
<tr>
<th>Cookie</th>
<th>Service</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{result.knownNotDeclared.map((cookie) => (
<tr key={cookie.name} className="warning">
<td><code>{cookie.name}</code></td>
<td>{cookie.matchedPreset?.name}</td>
<td>Add <code>{cookie.matchedPreset?.id}</code></td>
</tr>
))}
</tbody>
</table>
</>
)}
{result.unknown.length > 0 && (
<>
<h4>Unknown Cookies ({result.unknown.length})</h4>
<table>
<thead>
<tr>
<th>Cookie</th>
<th>Size</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{result.unknown.map((cookie) => (
<tr key={cookie.name} className="error">
<td><code>{cookie.name}</code></td>
<td>{cookie.size}b</td>
<td>Investigate origin</td>
</tr>
))}
</tbody>
</table>
</>
)}
</div>
)}
<div className="actions">
<button onClick={scan}>Re-scan Now</button>
<button onClick={() => setShowDetails(!showDetails)}>
{showDetails ? 'Hide' : 'Show'} Details
</button>
<button onClick={() => downloadReport('json')}>
Export JSON
</button>
<button onClick={() => downloadReport('csv')}>
Export CSV
</button>
<button onClick={() => {
navigator.clipboard.writeText(getReport());
alert('Report copied to clipboard');
}}>
Copy Text Report
</button>
</div>
</div>
);
}Set up continuous monitoring with alerts:
import { useCookieScanner } from 'react-consent-shield';
import { useEffect } from 'react';
function CookieMonitor({ services }) {
const { result, isCompliant } = useCookieScanner(services, {
autoScan: true,
scanInterval: 300000, // Scan every 5 minutes
onIssueFound: async (scanResult) => {
// Send alert to your backend
await fetch('/api/compliance/alert', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
timestamp: scanResult.timestamp,
issues: scanResult.summary.issues,
knownNotDeclared: scanResult.knownNotDeclared.map(c => ({
name: c.name,
service: c.matchedPreset?.id,
})),
unknown: scanResult.unknown.map(c => c.name),
}),
});
// Log to monitoring service (e.g., Sentry)
console.error('Cookie compliance violation detected', {
issues: scanResult.summary.issues,
suggestions: scanResult.summary.suggestions,
});
},
});
// Visual indicator (hidden by default, shown only to admins)
if (!isCompliant && isAdminUser()) {
return (
<div className="compliance-warning-badge">
<span>⚠ {result?.summary.issues} cookie issues</span>
</div>
);
}
return null;
}Use the scanner in your deployment pipeline:
// scripts/check-cookie-compliance.ts
import { scanCookies, formatScanReport } from 'react-consent-shield';
import { allPresets } from 'react-consent-shield';
import { declaredServices } from '../src/config/consent';
// Run in Node.js environment with jsdom
import { JSDOM } from 'jsdom';
async function checkCompliance() {
// Simulate browser environment
const dom = new JSDOM('<!DOCTYPE html>', { url: 'http://localhost' });
global.document = dom.window.document;
// Mock document.cookie with test cookies
Object.defineProperty(document, 'cookie', {
writable: true,
value: '_ga=test; _fbp=test; other_cookie=test',
});
// Run scan
const result = scanCookies(declaredServices, allPresets);
// Print report
console.log(formatScanReport(result));
// Exit with error if non-compliant
if (!result.summary.compliant) {
console.error('\n❌ Cookie compliance check failed!');
console.error('Please fix the issues above before deploying.\n');
process.exit(1);
}
console.log('\n✅ Cookie compliance check passed!\n');
process.exit(0);
}
checkCompliance();Add to your package.json:
{
"scripts": {
"check:cookies": "tsx scripts/check-cookie-compliance.ts",
"predeploy": "npm run check:cookies"
}
}Follow this workflow to maintain cookie compliance:
Configure your services and run the first scan:
import { ConsentProvider, googleAnalytics, metaPixel } from 'react-consent-shield';
const config = {
services: [googleAnalytics, metaPixel],
// ... other config
};
// In your admin panel
import { useCookieScanner } from 'react-consent-shield';
function InitialAudit() {
const { result, scan } = useCookieScanner(config.services);
useEffect(() => {
scan(); // Run initial scan
}, []);
// Review results and fix any issues
}For each issue, take the appropriate action:
Known but not declared:
// Before (issue detected)
const config = {
services: [googleAnalytics],
};
// After (issue fixed)
import { hotjar } from 'react-consent-shield';
const config = {
services: [googleAnalytics, hotjar], // Added missing service
};Unknown cookies:
// Option 1: Create custom preset
const customTracker = {
id: 'custom-tracker',
name: 'Custom Analytics',
category: 'analytics',
cookies: ['custom_tracker', 'ct_session'],
description: 'Our internal analytics system',
};
const config = {
services: [googleAnalytics, customTracker],
};
// Option 2: Ignore if not requiring consent
const { result } = useCookieScanner(services, {
ignoreCookies: ['custom_tracker'],
});Set up ongoing monitoring:
function App() {
return (
<ConsentProvider config={config}>
{/* Your app */}
{/* Only shown to admins */}
{isAdmin && <CookieComplianceMonitor />}
</ConsentProvider>
);
}
function CookieComplianceMonitor() {
useCookieScanner(config.services, {
autoScan: true,
scanInterval: 600000, // Every 10 minutes
onIssueFound: (result) => {
// Alert admins
showNotification('Cookie compliance issue detected');
},
});
return null;
}Schedule periodic manual audits:
function QuarterlyAudit() {
const { result, downloadReport } = useCookieScanner(services, {
autoScan: true,
});
useEffect(() => {
if (result) {
// Save audit report
downloadReport('json', `audit-${new Date().toISOString()}.json`);
// Send to compliance officer
emailReport(result);
}
}, [result]);
return <div>Running quarterly audit...</div>;
}Integrate into your CI/CD pipeline:
# In your CI/CD pipeline
npm run check:cookies # Fails if issues found
npm run build
npm run deployMaintain compliance documentation:
function generateComplianceReport(result: ScanResult) {
return {
date: new Date().toISOString(),
compliant: result.summary.compliant,
totalCookies: result.totalFound,
declaredServices: result.declared.map(c => ({
cookie: c.name,
service: c.matchedPreset?.name,
category: c.category,
})),
actions: result.summary.suggestions,
};
}
// Save to compliance records
const report = generateComplianceReport(scanResult);
await saveToComplianceLog(report);- Run scans after every deployment to catch new cookies
- Set up alerts for production issues
- Review unknown cookies immediately - they may be malicious
- Keep service presets updated with the latest cookie patterns
- Document custom presets for your team
- Schedule regular audits (weekly or monthly)
- Train your team on cookie compliance requirements
- Export reports for compliance records
Back to main documentation | Previous: Geographic Detection | Next: Audit Logging