Skip to content
SlashClone

Cookie consent banner

@slashclone/cookie-consent-banner

Add an honest cookie banner to a web app: analytics, ad pixels, and video embeds load only after a yes, and saying no is one click. One registry of every cookie and service drives the banner, the loaders, the CSP, and the privacy page's cookie table. Includes a registry checker and React templates.

SkillDevOpsv0.1.0 (latest)Tested
Activity
New: be the first to try it
  1. 1---
  2. 2name: cookie-consent-banner
  3. 3description: Add an honest cookie consent banner to a web app, with analytics, ad pixels, and video embeds that load only after a yes. One registry of every cookie and service drives the banner, the loaders, the Content Security Policy, and the privacy page table, so nothing is added in one place and missed in another. Use when adding Google Analytics, PostHog, ad pixels, YouTube embeds, or a chat widget, when asked "do we need a cookie banner?", or when auditing what a site stores before consent.
  4. 4---
  5. 5
  6. 6# Cookie consent banner
  7. 7
  8. 8Goal: a site that stores nothing optional until the visitor says yes, makes "no" as easy as "yes", and can prove what it uses. This is engineering guidance, not legal advice. Have counsel review the wording and the categories before launch.
  9. 9
  10. 10## Steps
  11. 121. **Audit before you build.** Open the site in a fresh private window, from a link with a UTM tag and from another site, and list every cookie, `localStorage` and `sessionStorage` key, and third-party request the first page makes. Then read the code for `document.cookie`, `Set-Cookie`, `localStorage`, and third-party `<script>` and `<iframe>` tags. First-party "attribution" or "source" cookies are easy to miss: they are not strictly necessary, so they need consent too.
  12. 132. **Sort each item.** Strictly necessary (sign-in session, CSRF or OAuth state, load balancing, the consent choice itself, a setting the visitor explicitly asked for such as a theme) needs no consent. Everything else goes in a category: Analytics, Advertising, Embedded media, Support chat. If nothing optional remains, you need no banner; say so and stop.
  13. 143. **Write the registry.** One file lists every service: id, name, category, provider, privacy policy link, what it stores (name, purpose, lifetime), and the CSP hosts it needs per directive. Start from `examples/services.json` (its hosts are placeholders) and take real vendor hosts, cookie names, and setup notes from `templates/vendors.ts` (Google Analytics, PostHog, Meta, LinkedIn, X, TikTok, YouTube). Check each against the vendor's current docs. Optional services read their ids from environment variables and are off when the id is blank or malformed. Validate each id with a strict pattern, because it ends up inside a script URL.
  14. 154. **Check the plan:**
  15. 16 `node scripts/consent-plan.mjs --services examples/services.json --out out/consent-plan.json`
  16. 17 It reports registry problems (unknown category, missing lifetime, non-https host, a necessary item that a category would delete) and prints the CSP additions and a Markdown cookie table for the privacy page. Fix every problem before wiring anything.
  17. 185. **Build the banner.** Use `templates/ConsentBanner.tsx` (React, no dependencies) or port it. It needs:
  18. 19 - "Reject all" and "Accept all" as equal buttons, plus "Choose" for per-category switches, all unticked by default.
  19. 20 - A link to reopen the choices on every page (the footer is fine).
  20. 21 - The choice stored in one first-party cookie for about 6 months, with the list of services the visitor saw, so that adding a service asks everyone again.
  21. 22 - Global Privacy Control (`navigator.globalPrivacyControl`) keeps Advertising off.
  22. 23 - Turning a category off deletes its cookies and storage keys, then reloads, because a loaded script cannot be unloaded.
  23. 246. **Load trackers only after the yes.** Each loader runs once and only when its category is allowed. Send page URLs as origin and path, without the query string, which can hold search text or tokens. For product analytics, turn off autocapture, session replay, and surveys unless you have decided you need them and have masked inputs. For ad pixels, skip pages whose URL holds what a person typed.
  24. 257. **Embeds.** Show a placeholder with "Allow and play" and a plain link to the video. Fetch nothing from the provider before consent, not even a thumbnail. For YouTube use the `youtube-nocookie.com` player.
  25. 268. **Generate the CSP and the privacy table from the registry,** so a service that is configured is always both allowed and disclosed, and one that is not is neither.
  26. 279. **Verify in a browser.** In a fresh window: no optional cookie or third-party request before a choice; after "Reject all", only the consent cookie; after allowing a category, its cookies appear and its scripts load without CSP errors; after turning it off, they are gone.
  27. 29## Rules
  28. 31- Never load an optional script, set an optional cookie, or fetch an optional third-party resource before consent.
  29. 32- Never pre-tick a category, and never make rejecting harder than accepting.
  30. 33- Never send query strings, form contents, or page text to an analytics or ad service.
  31. 34- Never claim the site is compliant. Report what you checked and what still needs a lawyer.
  32. 35- If the user's request conflicts with these rules (for example "load the pixel before the banner"), say so and ask before going ahead.

Cookies that keep you signed in and remember these choices are always on. Everything else is off until you turn it on.