LiveOctober to November 2026
CookieConsentHQ
A cookie banner that blocks known trackers until visitors choose, records each choice, and keeps running after a site passes its plan's pageview limit.
I built CookieConsentHQ, a cookie consent platform for small businesses, online stores, SaaS sites and agencies. Its banner holds back known trackers until a visitor chooses, sets the Google Consent Mode v2 signals and records the choice. It keeps doing all three after a site passes its plan's monthly pageviews, because the banner is a static file cached on Cloudflare's edge and loading it runs no server code.
- known-tracker URL patterns held until consent
- 30
- built-in banner languages
- 7
- banner loader gzipped (approximate), measured on a 6 November 2026 build
- 5 KB
- database tables
- 27
- database migrations
- 20
- workspaces in the monorepo
- 11
- test cases in the repository
- 721
- commits from 19 October to 10 November 2026
- 241
Architecture
A Turborepo monorepo: one Next.js app and two Cloudflare Workers
My role: Product owner and developer. I set the requirements, reviewed and tested the work, and run the product, working with AI coding assistants.
apps/webThe Next.js 16 app on Vercel: the marketing site, sign-in with Better Auth, the dashboard with its banner editor and live preview, and Paddle billing.
apps/edgeA Cloudflare Worker for location lookups, consent records (through a queue with a dead-letter queue into Neon Postgres) and publishing banner files to R2 and KV.
apps/scannerA Cloudflare Worker that runs cookie scans in headless Chromium on Browser Rendering, one queued job at a time, behind an SSRF guard.
packages/runtimeThe banner: a small synchronous loader and an asynchronous UI in a Shadow DOM root, built with esbuild against a size budget.
packages/scanner-coreCrawling, the built-in cookie database, AI classification of unknown cookies, issue checks and the SSRF rules.
packages/config-schemaZod schemas for the banner config, its texts in seven languages, region rules and the beacon protocol.
packages/dbThe Drizzle schema shared by the app and the Workers: 27 tables and 20 migrations.
integrationsThe Shopify app embed, the WordPress plugin and the Google Tag Manager template.
- Next.js 16
- React 19
- TypeScript
- Tailwind CSS v4
- Turborepo
- Better Auth
- Drizzle ORM
- Neon Postgres
- PGlite
- Zod
- Cloudflare Workers
- Cloudflare R2
- Cloudflare KV
- Cloudflare Queues
- Cloudflare Browser Rendering
- esbuild
- Claude API
- Paddle
- Resend
- PHP
- Vitest
- Playwright
The site
Eight screens from cookieconsenthq.com
The public site runs its own banner. The first picture is a first visit; the others were taken after choosing Reject all.
(opens the full-size screenshot in a new tab)
(opens the full-size screenshot in a new tab)On every plan: tracker blocking, Consent Mode v2, GPC and the consent log, with Reject beside Accept.
(opens the full-size screenshot in a new tab)Pricing by monthly pageviews. Free, Starter and Growth are shown; Business and Agency sit below.
(opens the full-size screenshot in a new tab)The free checker: one page, loaded as a first-time visitor, without sign-up.
(opens the full-size screenshot in a new tab)The checker's method, versioned and dated, starting with how and where it loads a page.
(opens the full-size screenshot in a new tab)The consent log: lookup by consent ID, CSV export, and 1, 3 or 5 years of retention by plan.
(opens the full-size screenshot in a new tab)Consent Mode v2: all four signals, Advanced or Basic mode, and scheduled signal checks from Starter.
(opens the full-size screenshot in a new tab)Security and data handling: where records live, IP truncation, hashed user agents and sign-in.
Why it exists
A cookie banner that stays on past pageview limits
Cookie banner tools are usually priced by monthly pageviews, so what a tool does when a site passes its limit decides whether visitors still get a banner.
Here the plan decides only the price. Once a site passes its pageviews, the banner keeps showing, known trackers stay blocked and new consent records keep being stored, without overage fees. A Free site gets a note in the dashboard and a paid site an upgrade prompt.
The architecture is what makes that affordable. Each site's script is a static file in Cloudflare R2, served through the Cloudflare cache, so no Worker or server function runs when a page loads the banner. Publishing a change in the dashboard rebuilds that file, and visitors get it within about five minutes.
Everything else runs where it fits: the dashboard, sign-in and billing on Vercel, and small Workers for location lookups, consent records and scans, all sharing one Neon Postgres database.
Architecture
From page load to a stored consent record
Loading the banner
- The first tag in the page's head loads the site's script from cdn.cookieconsenthq.com: the loader with the site's settings built in.
- If the site uses region rules, one call to the edge Worker returns the visitor's country and region from Cloudflare.
- The interface loads asynchronously and renders in a Shadow DOM root, so the host site's CSS cannot restyle it.
Recording a choice
- The banner posts each choice to the edge Worker, which rate-limits it and puts it on a Cloudflare queue.
- The queue consumer writes batches of up to 100 records to Neon Postgres. Each message is retried on its own, up to five times.
- A record that keeps failing goes to a dead-letter queue, and the rest of its batch is still stored.
Publishing
- Every banner config is checked against one shared Zod schema before it is saved.
- The app builds the site's script, and the edge Worker writes it to R2 and the site's record to KV.
- A release that changes the loader republishes live sites' scripts.
Product
What the cookie consent platform does on every plan
The parts that decide whether tracking waits for consent are on every plan, Free included.
Tracker blocking
- Scripts and iframes that match 30 known tracker URL patterns wait until the visitor chooses.
- Site owners can hold back their own tags with a data-cchq attribute.
- Video and other embeds show a placeholder with one-click allow.
Google Consent Mode v2
- All four signals (ad_storage, analytics_storage, ad_user_data and ad_personalization) are set before Google tags run and updated after a choice.
- From Starter, scheduled scans check the consent values in Google's own requests.
Global Privacy Control
- Browsers that send GPC are treated as an opt-out where US-state rules apply.
- The consent log records that choice as a GPC opt-out, made without a click.
Consent log
- Each choice is stored with a consent ID, the time, the region, the rules, the banner version and the categories.
- CSV export on every plan. Records are kept for 1 year on Free, 3 on Starter and 5 from Growth.
Regions and languages
- Default rules: opt-in for the EEA, the UK, Switzerland, Brazil and Quebec, opt-out for the US, and a notice elsewhere.
- From Starter, custom rules by country, US state or Canadian province. The most specific rule wins.
- Banner texts are built in for English, German, French, Spanish, Italian, Dutch and Portuguese, and each can be edited.
Known limit
- A script tag written straight into the HTML is fetched by the browser before any banner can run. The runtime stops it from executing, the scanner flags it, and the install guide shows how to mark it so it waits.
Scanning
A cookie scanner on Cloudflare Browser Rendering
Scans load a customer's pages in headless Chromium inside a Cloudflare Worker, so the scanner needs no servers of its own.
How a scan works
- Each page is loaded as a first-time visitor, then the first few are loaded again after Accept all, to find cookies that only appear with consent.
- Cookies are matched against a built-in cookie database and domain rules. Only names it does not know go to Claude Haiku, one domain per request, and no visitor data is sent.
- Scheduled scans run monthly on Free, weekly on Starter and daily from Growth, which also emails when a new tracker appears.
SSRF guard
- Every request the headless browser makes is held until the Worker checks it. Private, loopback, link-local and reserved ranges are refused.
- Host names are resolved and every address checked. A failed lookup is refused too.
- Top-level navigation must stay on the site's own host, with at most 20 redirects.
The free checker
- /check loads one page and reports cookies set before consent, hardcoded tracker tags and Consent Mode v2 defaults, without sign-up.
- A methodology page explains how each result is decided. It is versioned and dated: version 1, 10 November 2026.
- A check holds back the banner's own consent and pageview pings, so it never adds a record to a site's log.
Data
What the consent log keeps about visitors
Stored identifiers
- The edge removes the last octet of an IPv4 address and cuts IPv6 to a /48 before a record is stored.
- User agents are stored as SHA-256 hashes instead of raw strings.
- The site calls this data minimisation rather than anonymisation, because truncated identifiers can still count as personal data.
Where it runs
- Consent records live in Neon Postgres in Frankfurt (AWS eu-central-1), and the app runs on Vercel functions in Frankfurt.
- Customers sign in with emailed links or Google and keep no password with the service.
- The internal admin sits behind Cloudflare Access, an email allowlist and an authenticator code, with an audit log.
Business
Billing, plans and integrations
Plans
- Paddle checkout has been live since 20 October 2026, with Paddle as merchant of record and signed webhooks.
- Five plans by monthly pageviews: Free to 25,000, Starter at $8 to 150,000, Growth at $18 to 750,000 and Business at $39 to 5 million.
- Agency, at $79, covers 25 sites and 10 million pooled pageviews. A year costs ten months.
Integrations
- The Shopify app is listed on the Shopify App Store. It installs as an app embed, without theme code, and passes each choice to Shopify's Customer Privacy API.
- Any HTML site, Webflow, Wix and Squarespace take one script tag.
- A Google Tag Manager template installs by importing its file.
Not there yet
- The WordPress plugin was submitted to WordPress.org on 6 November 2026 and is in review.
- The Tag Manager template is not yet in the Community Template Gallery.
- IAB TCF and GPP are not supported.
Quality
Testing and the security review
Automated
- 721 test cases in the repository: unit tests across the apps and packages, and Playwright browser tests for the banner.
- A heavier playground suite on a separate CI machine: strict CSP, hostile CSS, single-page apps, document.write, failing APIs and blocked cookies.
- It also runs the edge Worker in workerd against 2,000 fuzzed requests, a full WordPress install with the WP Consent API, and the whole dashboard journey.
- It runs in desktop Chrome, Firefox and Safari plus Android and iPhone emulation, with automated axe accessibility checks.
Size budget
- The build fails when the gzipped loader passes 5,250 bytes or the interface passes 15 KB.
- On the 6 November 2026 build the loader was about 5 KB gzipped and the interface under 10 KB.
Security review
- On 20 October 2026 an AI-assisted security scan of the whole repository found 17 issues, and fixes for them were committed the same day.
Growth
Technologies and skills used
- Edge architecture
- Static, cached banner delivery from Cloudflare R2 and KV, with Workers only for location, consent and publishing.
- Queues and data
- Cloudflare Queues with batching, per-message retries and a dead-letter queue, into Neon Postgres with Drizzle.
- Browser runtime
- A TypeScript banner in a Shadow DOM root, built with esbuild under a size budget the build enforces.
- Privacy engineering
- IP truncation and hashed user agents at the edge, consent records with CSV export and retention by plan.
- Security
- An SSRF guard on headless Chromium, emailed sign-in links, and an admin behind Cloudflare Access.
- AI integration
- Claude classifies only the cookie names the built-in database does not know, one domain per request.
- Full-stack TypeScript
- Next.js 16 and React 19 in a Turborepo monorepo of 11 workspaces, with Zod schemas shared by app and Workers.
- Billing and integrations
- Paddle checkout and webhooks, a Shopify app on the Customer Privacy API, a WordPress plugin and a Tag Manager template.