Skip to main content
Back to Guides
Compliance9 min read

How to Block Scripts Until Cookie Consent

Learn how to prevent tracking scripts like Google Analytics, Facebook Pixel, and Hotjar from firing until the user has given cookie consent — step by step with copy-paste examples.

Under GDPR and the ePrivacy Directive, tracking scripts must not execute until the user has actively given consent for the relevant cookie category. This means that simply showing a cookie banner is not enough — you need to technically prevent scripts from running until consent is granted.

CookieBeam provides a built-in mechanism called script blocking (also called script management) that lets you do exactly this. By adding two HTML attributes to your script tags, CookieBeam will hold them dormant and only activate them after the user accepts the matching cookie category.

Using Google Tag Manager?

Good News

If all your tracking scripts are loaded through Google Tag Manager and you have enabled Consent Mode V2, GTM already gates script execution based on consent signals. You do not need manual script blocking for GTM-managed tags. This guide is for scripts that are hardcoded directly in your HTML, outside of GTM.

How Script Blocking Works

CookieBeam's script blocking works by exploiting how browsers handle the type attribute on <script> tags. When a script has type="text/plain" instead of type="text/javascript", the browser treats it as a data block and does not execute it.

CookieBeam scans the page for all script tags marked with a data-category attribute. When a user gives consent for that category, CookieBeam clones the dormant script tag, restores its original type and source, and inserts it back into the page — causing the browser to execute it normally.

The Blocking Lifecycle

1

Page loads with dormant scripts

Your script tags have type="text/plain" and data-category="...". The browser sees them but does not execute them.

2

CookieBeam initializes

The CookieBeam banner script scans the DOM and finds all <script data-category="..."> elements, recording which category each belongs to.

3

User interacts with the cookie banner

The user clicks "Accept All" or selects specific categories in the preferences modal.

4

Consented scripts are activated

CookieBeam replaces each dormant script that belongs to an accepted category with a fresh, executable copy. External scripts are loaded sequentially to maintain dependency order.

Required Attributes

To block a script, you need exactly two attributes:

Required and optional script blocking attributes
AttributeRequiredDescription
type="text/plain"YesPrevents the browser from executing the script. CookieBeam restores the original type when consent is given.
data-category="..."YesTells CookieBeam which cookie category this script belongs to: necessary, analytics, marketing, or preferences.
data-src="..."For external scriptsUse instead of src for external scripts. Prevents the browser from fetching the file before consent.
data-service="..."OptionalGives the script a human-readable name that appears as a toggle in the preferences modal, letting users control it individually.
data-type="..."OptionalSet a custom script type (e.g. "module") that CookieBeam will restore when the script is activated.

Basic Example: Inline Script

Here is the simplest case — an inline script that should only run when the user consents to analytics cookies:

inline-script-example.html

External Scripts: Use data-src

For external scripts that load a file via the src attribute, you must replace src with data-src. This prevents the browser from fetching the file before consent is given — even though type="text/plain" stops execution, many browsers still download the resource when src is present.

external-script-example.html

Always use data-src for external scripts

If you keep the src attribute, the browser may still download the script file (even though it won't execute it). This can trigger network requests to third-party servers before consent, which some Data Protection Authorities consider a GDPR violation. Always replace src with data-src.

Cookie Categories

CookieBeam uses four standard cookie categories. Use the exact lowercase string in the data-category attribute:

Cookie categories and their typical scripts
Categorydata-category valueTypical scriptsConsent required?
NecessarynecessaryLogin, security tokens, payment processing, reCAPTCHANo — always active. No tagging needed.
AnalyticsanalyticsGoogle Analytics, Hotjar, Mixpanel, Plausible, PostHog, AmplitudeYes
MarketingmarketingFacebook Pixel, Google Ads, LinkedIn Insight, TikTok Pixel, Twitter Pixel, CriteoYes
PreferencespreferencesChat widgets (Intercom, Drift), language preferences, UI customisationYes

Ready-to-Use Examples

Below are copy-paste examples for the most commonly used tracking scripts. Replace the placeholder IDs with your own.

Google Analytics (GA4)

google-analytics.html

Facebook Pixel

facebook-pixel.html

Hotjar

hotjar.html

LinkedIn Insight Tag

linkedin-insight.html

TikTok Pixel

tiktok-pixel.html

Google Ads Conversion Tracking

google-ads.html

Per-Service Toggles

When you add the data-service attribute, CookieBeam automatically generates a toggle in the preferences modal that lets users enable or disable that specific service within its category. For example, a user might accept the "analytics" category overall but disable Hotjar specifically.

All scripts with the same data-service name are grouped together — they are activated or deactivated as a unit.

When to use data-service

Use data-service when you have multiple tracking scripts in the same category and want to give users fine-grained control. For example, if you use both Google Analytics and Hotjar (both analytics), adding data-service to each lets users keep one while disabling the other.

Running Cleanup Scripts on Consent Withdrawal

Sometimes you need to run cleanup logic when a user withdraws consent for a category — for example, disabling a Google Analytics property or removing event listeners. You can do this by prefixing the category name with !:

cleanup-example.html

Disable scripts run only once

A data-category="!analytics" script can only fire once — when the user actively switches the category off. If you need logic that runs every time consent changes (e.g. the user toggles analytics on and off multiple times), use the onChange callback instead of script tag blocking.

Script Blocking vs Google Consent Mode

It is important to understand the difference between these two approaches, because they solve the same problem in different ways:

Script Blocking vs Consent Mode

AspectScript Blocking (data-category)Google Consent Mode V2
How it worksPrevents the script from executing entirely until consentLets the script load but sends consent signals so Google tags self-regulate
What scripts support itAny script — works with all vendorsOnly Google tags (GA4, Google Ads, Floodlight)
Data sent before consentNone — script does not even loadCookieless pings are sent (no PII, used for conversion modeling)
Best forNon-Google scripts (Facebook, Hotjar, TikTok, etc.)Google ecosystem tags loaded via GTM
SetupEdit HTML: add type and data-category to each scriptAutomatic when using CookieBeam GTM template

Can I use both?

Recommended

Yes — and you should. Use Google Consent Mode V2 for your Google tags (loaded through GTM), and use script blocking for any non-Google scripts hardcoded in your HTML. This gives you the best of both worlds: Google's cookieless conversion modeling plus strict blocking for everything else.

Troubleshooting

Script still fires before consent

Check that you have both required attributes: type="text/plain" and data-category="...". Missing either one means the browser will execute the script normally. Also make sure the CookieBeam banner script loads before the blocked scripts in your HTML.

External script file is still downloaded

Replace src with data-src. Even with type="text/plain", some browsers will still fetch the file from the server if src is present — it just won't execute it.

Script does not activate after consent

Verify the data-category value matches one of the configured categories exactly (lowercase): necessary, analytics, marketing, or preferences. A typo or different casing will cause CookieBeam to ignore the script.

Multiple scripts depend on each other

CookieBeam loads external scripts sequentially in DOM order. If script B depends on script A, make sure script A appears first in your HTML. Inline scripts execute immediately after replacement, before the next external script starts loading.

Checklist Before Going Live

Script Blocking Checklist

  • Every non-essential script has type="text/plain" and data-category

    Search your HTML source for <script src= tags that don't have these attributes

  • External scripts use data-src instead of src

    Prevents the browser from fetching the file before consent

  • CookieBeam banner script loads first

    Place it before any blocked scripts in <head> so it can intercept them

  • Test with a fresh browser (no cookies)

    Clear all cookies and localStorage, then reload — no tracking requests should appear in DevTools Network tab

  • Test consent flow end-to-end

    Accept cookies and verify blocked scripts activate — check the Network tab for the expected requests

  • Test reject flow

    Reject all cookies and verify no tracking requests are made on subsequent page loads

  • Verify Google Consent Mode still works

    If you use GTM, check that consent default and update commands still fire correctly alongside script blocking

How to Block Scripts Until Cookie Consent (with Examples) | CookieBeam | CookieBeam