Install PrivacyPill

One script, about 5.2 kB gzipped. It sets Consent Mode defaults, shows your banner, remembers the choice, releases blocked scripts and tells Google what was decided.

Quick start

  1. 1. Design your banner in the customizer and save it to your domain. You'll get a site key like pp_3f9a1c….
  2. 2. Paste the embed as the first script inside <head>:
html
<script src="https://privacy-pill-consent-studio.lovable.app/api/public/v1/pp.js?site=pp_your_site_key"></script>

3. Open your site in a private window. The banner appears and Google tags start in denied mode until the visitor chooses. Design changes go live within a few minutes of saving — the script is cached briefly at the edge.

Placement & fail-safe

Load PrivacyPill synchronously (no async/defer) and before Google Tag Manager or gtag.js. Consent Mode defaults must exist before the first Google tag runs.

For extra safety, add this inline line directly above the embed. If our script is ever blocked, Google tags still start denied. PrivacyPill detects the existing default and won't push a second one.

html
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag('consent','default',{ad_storage:'denied',ad_user_data:'denied',ad_personalization:'denied',analytics_storage:'denied',functionality_storage:'denied',personalization_storage:'denied',security_storage:'granted',wait_for_update:500});</script>

Platform guides

  1. 1Open the template that renders the <head> on every page.
  2. 2Paste the snippet as the very first element inside <head>, above Google Tag Manager, gtag.js or any analytics.
  3. 3Mark non-Google trackers with type="text/plain" and data-pp-category so they wait for consent.
  4. 4Deploy and open your site in a private window: the banner appears and Google tags start in denied mode.
html
<!-- PrivacyPill: keep this first in <head>, before Google Tag Manager or analytics -->
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag('consent','default',{ad_storage:'denied',ad_user_data:'denied',ad_personalization:'denied',analytics_storage:'denied',functionality_storage:'denied',personalization_storage:'denied',security_storage:'granted',wait_for_update:500});</script>
<script src="https://privacy-pill-consent-studio.lovable.app/api/public/v1/pp.js?site=pp_your_site_key"></script>

More detail: Shopify guide · Webflow guide

Blocking scripts & iframes

Google tags respect Consent Mode on their own. Everything else — Meta Pixel, Hotjar, TikTok, chat widgets, video embeds — should wait. Change type to text/plain and add data-pp-category (analytics, marketing or functional). PrivacyPill turns them into real scripts the moment that category is allowed, including on returning visits.

html
<!-- Runs only after the visitor allows "analytics" -->
<script type="text/plain" data-pp-category="analytics"
        src="https://static.hotjar.com/c/hotjar-1234567.js?sv=6"></script>

<!-- Inline scripts work too -->
<script type="text/plain" data-pp-category="marketing">
  fbq('init', '000000000000000'); fbq('track', 'PageView');
</script>

<!-- Embeds: load the iframe only after consent -->
<iframe data-pp-category="functional"
        data-pp-src="https://www.youtube-nocookie.com/embed/VIDEO_ID"></iframe>

Need a script type other than JavaScript (e.g. module)? Add data-pp-type="module". When someone withdraws consent, PrivacyPill deletes first-party cookies you listed under the category's "cookies to delete" and can optionally reload the page.

Banner categoryConsent Mode signalsDefault
Strictly necessarysecurity_storagegranted
Analyticsanalytics_storagedenied
Marketing & advertisingad_storage, ad_user_data, ad_personalizationdenied
Functionalfunctionality_storage, personalization_storagedenied

On load, PrivacyPill pushes gtag('consent', 'default', …) with wait_for_update (500 ms by default), optionally ads_data_redaction and url_passthrough. If the visitor already chose, an update follows immediately. Build your own setup with the Consent Mode v2 generator.

Events & dataLayer

Every change is pushed to the dataLayer so you can trigger GTM tags on it:

js
dataLayer.push({
  event: "privacypill_consent",      // also: privacypill_ready, privacypill_show, privacypill_hide, privacypill_reset
  privacypill: {
    analytics: "granted",
    marketing: "denied",
    functional: "granted"
  }
});

The same moments fire DOM events on window: privacypill:ready, privacypill:consent, privacypill:show, privacypill:hide and privacypill:reset. event.detail contains consent, gcm, method (accept / reject / custom / api), id and decided.

JavaScript API

js
// Open the preferences panel (e.g. from a "Cookie settings" footer link)
PrivacyPill.open();

// Read the current choice
PrivacyPill.get();            // { necessary: true, analytics: true, marketing: false, functional: true }
PrivacyPill.allowed("marketing"); // false

// React to changes
PrivacyPill.on(function (e) {
  if (e.type === "consent" && e.consent.analytics) startMyAnalytics();
});

// Or listen to the DOM event
window.addEventListener("privacypill:consent", function (e) {
  console.log(e.detail.gcm); // { ad_storage: "denied", analytics_storage: "granted", … }
});

// Ask again (e.g. after you add a new tool)
PrivacyPill.reset();

Also available: PrivacyPill.accept(), PrivacyPill.reject(), PrivacyPill.set({ analytics: true }) and PrivacyPill.show().

Languages

English, German, French, Dutch, Spanish and Italian are built in. With detection on, PrivacyPill uses your page's <html lang> first, then the visitor's browser languages, then your fallback language. Only the languages you enable are shipped in your script.

Geo-targeting (Pro)

With geo-targeting on, visitors from the EU/EEA, UK, Switzerland and California see the banner as usual. Visitors elsewhere get consent granted by default and no banner — but can still open the settings via the floating button or PrivacyPill.open(). When we can't determine a visitor's location, the banner is shown.

What we store

  • In the visitor's browser: one first-party cookie, pp_consent, containing a random consent ID, the choice, the banner version and a timestamp. It lasts as long as you configure (default 182 days), is SameSite=Lax and Secure on HTTPS.
  • On our side: a monthly pageview counter per site, and a proof-of-consent record (consent ID, choice, banner version, country). No IP addresses, no user agents.

Troubleshooting

The banner doesn't appear

Check the site key in the script URL, and that you're testing in a private window (a stored choice hides the banner). Use 'Check installation' on your site's dashboard page.

Google tags fire before consent

PrivacyPill must load before GTM/gtag.js and without async. Add the fail-safe line above it.

My changes don't show up

The script is cached at the edge for a few minutes. Hard-refresh after ~5 minutes.

A blocked script never runs

Make sure the category name is exactly analytics, marketing or functional, and the type is text/plain.