Checks for proper cookie consent banners with accept/reject options
3 of 3 free audits left today
See what Cookie Consent finds on your site. No sign-up needed.
Render β launches a headless Chromium as 37AuditsBot, navigates to the audited URL, waits for the network to go idle and then two more seconds so consent scripts can inject their banner. A blocked navigation (HTTP 403, HTTP 429 or a Cloudflare challenge) ends the audit with 590; a navigation that returns no response or an HTTP status of 400 or more ends it with 500; a browser failure, after one relaunch when Chromium crashes, ends it with 501.
Find the banner β queries sixteen common selectors ([class*='cookie'], [id*='consent'], [class*='gdpr'], [role='dialog'], .cookie-banner, #cookieConsent and the like) and takes the first visible match per selector as the banner; hidden elements do not count. The text and the button labels of each banner are recorded.
Find the choices β reads the text of every button, a[role='button'] and input[type='button'] on the page and looks for accept keywords (accept, allow, agree, ok, enable, yes, continue), reject keywords (reject, decline, deny, disable, no, refuse, essential only, necessary only) and settings keywords (settings, preferences, customize, manage, options, choose). Links whose text or href mention privacy, policy, gdpr or data protection count as a privacy policy link.
Count the cookies β records the cookies present after the page loaded, flags likely tracking cookies (_ga, analytics, track, _utm, facebook, google) set before any consent, and, when a banner with an accept option exists, clicks the accept button, waits two seconds and counts the cookies again.
Rules β no visible banner fails (400); a banner with an accept option but no reject option (300), with a reject option but no accept option (301) or with neither (302) warns.
Aggregate β FAIL wins over WARNING; when the banner offers both choices the audit is SUCCESS (200) and the message names the mechanism, the buttons and the cookie counts before and after accepting.
Every row maps to one checkRule* method and one CheckCode, in the order the auditor runs them. CheckCode suffixes use status ranges: 200 success, 300β399 warning, 400β499 fail, 500β599 error.
| CheckCode | Status | When it fires | Recommendation | Why it matters |
|---|---|---|---|---|
37A-CookieConsentAuditor-400 | FAIL | No visible cookie consent banner was found on the rendered page. | Add a cookie consent banner to {url} that is visible on the first visit and offers both an accept and a reject choice; {count} cookies ({cookieNames}) set before any consent. | Visitors in the EU, the UK and many other jurisdictions must be asked before non-essential cookies are set; a site that never asks risks privacy complaints, regulator fines and the trust of its visitors. |
37A-CookieConsentAuditor-300 | WARNING | A banner is visible and the page has an accept button but no reject button. | Add a "Reject" or "Essential only" button next to the accept button of the banner on {url} (buttons today: {buttons}) so visitors can decline non-essential cookies as easily as they accept them. | A banner that only lets visitors accept is not a real choice: privacy regulators treat that consent as invalid, and privacy-conscious visitors leave rather than agree. |
37A-CookieConsentAuditor-301 | WARNING | A banner is visible and the page has a reject button but no accept button. | Add a clear "Accept" button next to the reject button of the banner on {url} (buttons today: {buttons}) so visitors who want analytics or personalisation can opt in. | Without a clear accept choice visitors cannot opt in to analytics or personalisation, so the site loses measurement and has no consent record for the cookies it sets. |
37A-CookieConsentAuditor-302 | WARNING | A banner is visible but the page has neither an accept nor a reject button. | Add both an "Accept" and a "Reject" button to the banner on {url} (buttons today: {buttons}) so visitors can make a real choice about non-essential cookies. | A notice visitors cannot act on collects no consent at all, so every non-essential cookie it covers is set without permission while the banner still gets in the way. |
37A-CookieConsentAuditor-200 | SUCCESS | All rules passed: a visible banner with both accept and reject options. Message names the mechanism, the buttons and the cookie counts, for example The cookie consent banner on {url} offers both accept and reject options (Binary Choice; buttons: "Accept All", "Reject All"); 1 cookie set before consent and 3 cookies after accepting. | β | β |
37A-CookieConsentAuditor-500 | ERROR | The browser navigation returned no response, or the page answered with an HTTP status of 400 or more that is not a block. | Make sure {url} answers with HTTP 2xx, then run the audit again. Last error: {error}. | β |
37A-CookieConsentAuditor-501 | ERROR | The headless browser failed to render the page (a navigation error, a timeout or a crash), after one relaunch on a crash. | Make sure {url} loads in a headless Chromium browser, then run the audit again. Last error: {error}. | β |
37A-CookieConsentAuditor-590 | ERROR | The audited page answered HTTP 403, HTTP 429 or a Cloudflare challenge, so 37AuditsBot was blocked before it could read the page. | Allow 37AuditsBot in your firewall or bot protection: allowlist its user agent, or verify its Web Bot Auth signature. See https://www.37audits.com/bot. | While 37AuditsBot is blocked this audit cannot look at the site, so problems on it go unreported. |
Every check carries the data the browser collected: hasConsentBanner, hasAcceptOption, hasRejectOption, hasSettingsOption, consentMechanism (None, Granular, Binary Choice, Accept Only or Banner Only), hasPrivacyPolicyLink, bannerText, availableOptions, detectedBannerSelectors, cookiesBeforeConsent, cookiesAfterAccept, cookiesAfterReject, their three counts and blocksNonEssentialByDefault.
| Status | Description | Test logic |
|---|---|---|
| SUCCESS | The banner offers a real choice | A visible consent banner, an accept button and a reject button (200). |
| WARNING | The banner does not offer both choices | Accept but no reject (300); reject but no accept (301); neither (302). |
| FAIL | No consent banner | No visible element matched any consent selector after rendering (400). |
| ERROR | The auditor could not read the page | No navigation response or HTTP status of 400 or more (500); browser render failure (501); site blocked 37AuditsBot (590). |
The ePrivacy Directive, the GDPR and the UK PECR require consent before non-essential cookies (analytics, advertising, social media) are set, and regulators have said that consent is only valid when rejecting is as easy as accepting.
Consent collected through an accept-only banner can be declared invalid, which turns every cookie set under it into an unlawful one.
Similar rules exist outside Europe (Brazil's LGPD, several US state laws), so the banner is rarely optional for a site with international visitors.
The banner is found by selector: an element whose class or id contains cookie, consent, gdpr or privacy, or that has role="dialog" or role="banner". A site header with role="banner" or a privacy link with privacy in its class is matched too, so a page without a consent banner can read as having one.
The accept, reject and settings buttons are looked up on the whole page by keyword, not only inside the banner: an unrelated OK or No button counts, and a banner whose buttons use other words (Got it, I understand) is not recognised.
The page is rendered with the bot's user agent from one location, so a banner shown only to EU visitors, or hidden from bots, is not seen.
Only the accept button is clicked. The reject path is not exercised, so cookies set after rejecting are not measured; cookiesAfterReject repeats the cookies seen before consent.
Granular settings (Manage preferences) are recorded in hasSettingsOption and the Granular mechanism name but do not change the verdict.
A page that answers HTTP 400 or more is now an ERROR (500) instead of being audited like any other page; a browser navigation that returns no response is also 500.
A browser failure that survives the relaunch is an ERROR with code 501 instead of a code-less check carrying the raw Playwright message.
Every check now carries the audited URL as its resource and a CheckCode; the verdict severities (no banner fails, a banner missing a choice warns, both choices pass) are unchanged.
This documentation is built and hosted on Mintlify, a developer documentation platform.
Add this auditor to your monitoring setup and start identifying issues on your websites today.