cookieowl

v0.1.0A bedtime story about privacy, free and MIT licensed

Cookie consent that keeps trackers outside the gate until visitors say yes

cookieowl is a free cookie consent banner for LGPD and GDPR. Analytics, pixels and heatmaps wait at the gate until their category is accepted, Google Consent Mode v2 is wired in, and the whole town runs on one script tag.

index.html
<script src="https://cdn.jsdelivr.net/npm/cookieowl@0.1.0/dist/cookieowl.js"
  data-lang="auto" data-policy-url="/privacy"
  data-consent-mode data-auto-block></script>
  • 15.0 kBgzip, one file
  • 0dependencies
  • 5languages
  • 11trackers known by name

Chapter ILive demo

The street at night, where trackers knock and wait

This is the real cookieowl, guarding a pretend coffee shop. Four tracker bugs and a video wait at the gate. Accept a category and the lamp for it lights up, the gate opens and only those bugs fly in. The logbook writes down everything that tried to get through.

  • Necessaryalways
  • Preferenceskept out
  • Analyticskept out
  • Marketingkept out
nightjar-coffee.example
Nightjar Coffee

Small batch, roasted at night

Coffee for people who stay up late

A pretend shop with four pretend trackers. None of them may come in until you say so.

Midnight BlendDark chocolate, plum
Owl RoastCaramel, hazelnut

Chapter IIHow blocking works

One night in the life of a tracker

A banner that only hides itself does nothing for privacy. cookieowl stops the browser from running trackers at all, and lets them in only after a choice.

  1. At dusk Hoot sits on a lantern post that is already lit

    Dusk

    Hoot lights the lantern first

    Put the script tag at the top of <head>, without async or defer. Consent Mode defaults and the auto blocker are in place before anything else runs.

    head
    <script src="https://cdn.jsdelivr.net/npm/cookieowl@0.1.0/dist/cookieowl.js"
      data-consent-mode data-auto-block></script>
  2. At midnight tracker bugs wait outside the closed gate

    Midnight

    Trackers wait outside as plain text

    Give each tracker type="text/plain" and a category. Browsers do not run text, so nothing is requested. Embeds keep their address in data-cookieowl-src.

    tracker markup
    <script type="text/plain" data-cookieowl="analytics"
      src="https://www.googletagmanager.com/gtag/js?id=G-X"></script>
    <iframe data-cookieowl="marketing"
      data-cookieowl-src="https://youtube.com/embed/ID"></iframe>
  3. In the morning the gate opens for an invited tracker

    Morning

    A choice opens the gate

    On consent, each accepted script runs in document order, waiting for the one before it. Withdrawal sweeps out the category cookies and reloads the page.

    events.js
    cookieowl.on('change', ({ accepted }) => {
      console.log('now allowed:', accepted);
    });

The usual suspects

Load cookieowl first with data-auto-block and these 11 tracker patterns are held by URL, even when a vendor snippet sneaks them in. Video embeds become a click to load placeholder.

  • WantedGoogle Analyticsanalytics
  • WantedGoogle Tag Manageranalytics
  • WantedGoogle Adsmarketing
  • WantedMeta Pixelmarketing
  • WantedMicrosoft Clarityanalytics
  • WantedHotjaranalytics
  • WantedLinkedIn Insight Tagmarketing
  • WantedTikTok Pixelmarketing
  • WantedYouTubemarketing
  • WantedVimeomarketing

Chapter IIIConfigurator

The lantern workshop: build your snippet

Pick the language, the look and the categories. The lantern glows in your accent color, one gem per category, and the snippet below it is ready to copy. Try it on the demo street before you take it home.

Language and wording
Look
Categories
Blocking and signals

A box banner in the visitor's language

  • Necessary
  • Preferences
  • Analytics
  • Marketing
Every option

Load it as the first script in <head>, then mark your trackers with type="text/plain" and data-cookieowl.

Chapter IVWhat Hoot guards

Twelve promises Hoot keeps every night

Everything a consent banner should do, in one small file.

  1. Real blocking before consent

    Marked scripts and iframes stay inert, then run in document order once their category is accepted.

  2. Auto mode for known trackers

    Google Analytics, Tag Manager, Meta Pixel, Clarity, Hotjar, LinkedIn and TikTok are caught by URL, even when a snippet injects them.

  3. Google Consent Mode v2

    Denied defaults with wait_for_update, region defaults, an update on every choice and a dataLayer event for Tag Manager.

  4. Click to load embeds

    YouTube and Vimeo iframes become a placeholder with Load once and Allow marketing cookies.

  5. Categories and services

    Necessary, preferences, analytics, marketing and your own, each with services, cookies and durations.

  6. Records for audits

    Version, timestamp, random consent id and method in a first party cookie, plus an onConsent hook for your log.

  1. Withdraw as easily as giving

    A floating owl reopens the preferences anywhere, and withdrawal erases cookies and stops scripts.

  2. Privacy signals respected

    Global Privacy Control is honored by default, Do Not Track when you turn it on.

  3. Accessible, no dark patterns

    Focus trap, keyboard, screen reader labels, Reject as prominent as Accept and no pre-ticked boxes.

  4. Five languages, LGPD and GDPR

    Portuguese with LGPD wording, English, Spanish, French and German, RTL safe, every text overridable.

  5. Themed by one color

    Light and dark mode out of the box and a --seed color for the accent, in a scoped stylesheet.

  6. One small file

    About 15 kB gzip, no dependencies, no requests of its own, no account and no server.

Chapter VInstall anywhere

Every house in town can hire Hoot

Plain HTML, React, Next.js, Vue, Angular or WordPress. The script tag works on any site, and on npm cookieowl ships ES modules, CommonJS and types, plus thin React and Vue helpers.

index.html
<!doctype html>
<html lang="en">
<head>
  <script src="https://cdn.jsdelivr.net/npm/cookieowl@0.1.0/dist/cookieowl.js"
    data-policy-url="/privacy" data-consent-mode data-auto-block></script>

  <script type="text/plain" data-cookieowl="analytics" src="/js/analytics.js"></script>
</head>
<body>
  <a href="#" data-cookieowl-open>Cookie settings</a>
</body>
</html>
src/Video.tsx
import { cookieowl } from 'cookieowl';
import { ConsentGate, useConsent } from 'cookieowl/react';

cookieowl.init({ policyUrl: '/privacy', consentMode: true });

export function Video() {
  const marketing = useConsent('marketing');
  return (
    <ConsentGate category="marketing" fallback={<p>Accept marketing cookies to watch.</p>}>
      <iframe src="https://www.youtube-nocookie.com/embed/VIDEO_ID" title="Tour" />
    </ConsentGate>
  );
}
app/layout.tsx
import Script from 'next/script';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script
          src="https://cdn.jsdelivr.net/npm/cookieowl@0.1.0/dist/cookieowl.js"
          strategy="beforeInteractive"
          data-policy-url="/privacy"
          data-consent-mode=""
        />
      </body>
    </html>
  );
}
src/main.ts
import { createApp } from 'vue';
import { CookieOwlPlugin } from 'cookieowl/vue';
import App from './App.vue';

createApp(App)
  .use(CookieOwlPlugin, { policyUrl: '/privacy', consentMode: true })
  .mount('#app');

// In a template:
// <ConsentGate category="marketing">
//   <iframe src="https://player.vimeo.com/video/123" />
//   <template #fallback>Accept marketing cookies to watch.</template>
// </ConsentGate>
src/main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { cookieowl } from 'cookieowl';
import { AppComponent } from './app/app.component';

cookieowl.init({ policyUrl: '/privacy', consentMode: true });

bootstrapApplication(AppComponent);

// Anywhere: cookieowl.on('change', ({ accepted }) => console.log(accepted));
cookieowl.php
<?php
// wp-content/mu-plugins/cookieowl.php
add_action('wp_head', function () {
    $policy = esc_url(get_privacy_policy_url());
    echo '<script src="https://cdn.jsdelivr.net/npm/cookieowl@0.1.0/dist/cookieowl.js"'
        . ' data-policy-url="' . $policy . '" data-consent-mode data-auto-block></script>';
}, 1);

Chapter VIWhat gets stored

A small, honest library card

cookieowl keeps one first party cookie with the choice and nothing else. No server, no fingerprint, no third party. Send the same record to your own log with onConsent when you need proof of consent.

A consent card with a green approval stamp
cookie: cookieowl
{
  "id": "1f0c9a7e-6b2d-4c41-9a1e-3f6f0d2b8c55",
  "version": "2026-10",
  "timestamp": "2026-10-13T21:04:11.093Z",
  "expires": "2027-10-13T21:04:11.093Z",
  "categories": { "necessary": true, "preferences": false, "analytics": true, "marketing": false },
  "method": "custom",
  "lang": "pt-BR",
  "page": "/checkout"
}
Fields of a consent record
FieldWhat it holds
idRandom consent id, kept across updates on the same device
versionThe policy version the visitor agreed to
timestampWhen the choice was made, ISO 8601
expiresWhen the banner asks again (12 months by default)
methodaccept-all, reject-all, custom or signal
categoriesEvery category and whether it was accepted
lang and pageThe banner language and the path where the choice was made

Chapter VIIGuides

The storybook shelf

Nine practical guides, from the LGPD checklist to Next.js. Each one ends with questions people really ask.

Chapter I

The LGPD and GDPR cookie consent checklist

An interactive LGPD and GDPR cookie consent checklist: prior blocking, equal Reject and Accept, no pre-ticked boxes, withdrawal, records and Consent Mode.8 min read
Chapter II

A cookie consent banner for the LGPD, in Portuguese, that really blocks

Add an LGPD cookie banner in Portuguese that blocks trackers before consent, follows the ANPD cookie guide and lets visitors revoke consent at any time.8 min read
Chapter III

What makes a cookie banner GDPR compliant

What makes a cookie banner GDPR compliant: prior blocking, Reject on the first layer, no pre-ticked boxes, easy withdrawal and proof. With a free, open source setup.9 min read
Chapter IV

Google Consent Mode v2 setup, step by step

Set up Google Consent Mode v2: denied defaults with wait_for_update, region defaults, updates on every choice, basic or advanced mode, with gtag.js or Tag Manager.8 min read
Chapter V

How to block Google Analytics until consent

How to block Google Analytics 4 until cookie consent: hold gtag.js and the config as text/plain, catch injected tags with auto mode, and verify it in DevTools.7 min read
Chapter VI

Cookie consent in React, without a provider maze

Add cookie consent to a React app: start cookieowl early, render embeds and analytics with ConsentGate, read choices with the useConsent hook, and block trackers.7 min read
Chapter VII

Cookie consent in Next.js, App Router and Pages Router

Add a cookie consent banner to Next.js: load cookieowl with next/script beforeInteractive, gate Google Analytics and embeds, and read consent in client components.8 min read
Chapter VIII

A free cookie banner for WordPress that blocks before consent

Add a free LGPD and GDPR cookie banner to WordPress without a plugin subscription: load cookieowl in wp_head, block analytics plugins and embeds until consent.7 min read
Chapter IX

A free cookie consent script, with nothing held back

A free, open source cookie consent script with no page view limits or account: one script tag, real blocking, Consent Mode v2, five languages, under 15 kB.7 min read

Chapter VIIIFAQ

Questions asked by lantern light

Not finding yours? Open an issue on GitHub.

Does cookieowl really block Google Analytics before consent?

Yes. Scripts you mark with type="text/plain" and data-cookieowl="analytics" are not executed by the browser at all, so gtag.js is never requested until analytics is accepted. With data-auto-block the gtag.js and Tag Manager URLs are also caught when they are inserted by a snippet. If you use Consent Mode advanced instead, Google tags load and send cookieless pings, which you choose explicitly.

Is cookieowl free for commercial sites?

Yes. It is MIT licensed, has no paid tier, no page view limits, no account and no server. You load one file from jsDelivr or install it from npm and host it yourself.

Does it support Google Consent Mode v2?

Yes. With consentMode on, cookieowl sets ad_storage, ad_user_data, ad_personalization and analytics_storage to denied with wait_for_update before any tag runs, supports region specific defaults, and sends a consent update on every choice, including on later visits.

Is a cookie banner enough to comply with LGPD or GDPR?

No banner alone makes a site compliant. cookieowl handles the technical part: prior blocking, granular and free choice, withdrawal as easy as consent, versioned records and an audit hook. You still need an accurate privacy policy, a legal basis for each processing and a review by your own counsel. This site is not legal advice.

Where is the consent stored and for how long?

In a first party cookie named cookieowl (or localStorage if you prefer) holding the categories, a random consent id, the policy version, a timestamp and an expiry date. The default lifetime is 12 months, after which the banner asks again. Changing your policy version asks everyone again right away.

How do visitors change their mind?

A small floating owl button reopens the preferences on every page, and any element with data-cookieowl-open does the same, for example a Cookie settings link in your footer. Withdrawing erases the cookies of that category and reloads the page when its scripts already ran.

Does it work with React, Vue, Next.js, Angular and WordPress?

Yes. The core is framework agnostic. cookieowl/react adds a useConsent hook and a ConsentGate component, cookieowl/vue adds a plugin, a composable and the same gate, and for WordPress you add the script tag in the theme head. Each one has a guide.

Will it slow my site down?

The script is about 15 kB gzip with five languages, the stylesheet and the blocker included, and it has no dependencies. It must load synchronously in the head to block trackers, which costs a few milliseconds, and it makes no network requests of its own.

What happens with Global Privacy Control?

When a browser sends Global Privacy Control, cookieowl records a refusal of optional categories, does not show the banner and notes the signal in the preferences, where the visitor can still opt in. Do Not Track can be honored the same way with respectDNT.

Can I keep a consent log for audits?

Yes. Pass onConsent(record) and send each record to your own endpoint. Every record has a random id, the policy version, the timestamp, the method (accept all, reject all, custom or signal), the categories, the language and the page.

Hoot suggests

Nothing here. Hoot looked under every cookie jar.