Developer Hub › JavaScript

JavaScript Script Blocking for LGPD

How to block non-essential scripts before consent using MutationObserver and type rewriting — the two techniques every LGPD implementation requires.

How do you block scripts before consent under LGPD?

Two mechanisms work together. First, change non-essential <script> tags from type="text/javascript" to type="text/plain" and add a data-consent-category attribute — the browser ignores scripts with unknown MIME types, so they never execute. Second, install a MutationObserver that watches the document for dynamically injected scripts and rewrites them before the browser can execute them.

After the visitor consents, the consent manager re-injects the held scripts with type="text/javascript" restored, triggering normal browser execution. Essential scripts in the Necessary category are never blocked.

Technique 1 — Type rewriting

Mark your tracking scripts as text/plain before the page loads. The consent manager restores them after consent.

Before — script fires immediately (LGPD violation)

<!-- WRONG: fires before consent -->
<script async src="https://www.googletagmanager.com/gtm.js?id=GTM-XXXXX"></script>

After — blocked until consent granted

<!-- CORRECT: blocked until consent granted -->
<script
    type="text/plain"
    data-consent-category="analytics"
    src="https://www.googletagmanager.com/gtm.js?id=GTM-XXXXX"></script>

Accepted values for data-consent-category: analytics, marketing, functional. Necessary scripts should never have this attribute — they always execute.

Technique 2 — MutationObserver

Type rewriting only blocks static HTML scripts. A MutationObserver intercepts scripts dynamically injected by tag managers, ad networks, and analytics libraries.

// Intercept dynamically injected scripts before they execute
const observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        mutation.addedNodes.forEach(function(node) {
            if (node.nodeName !== 'SCRIPT') return;

            const src = node.src || '';
            const isTracking = isTrackingScript(src);

            if (isTracking && !hasConsent(node)) {
                node.remove(); // remove before browser executes
                queueScript(node); // re-inject after consent
            }
        });
    });
});

observer.observe(document.documentElement, {
    childList: true,
    subtree: true
});

The observer must be started before any tracking library loads — place it synchronously in the <head> before GTM, GA4, or any other tag.

Consent state management

Read and react to consent decisions using the CookieFácil consent API.

// Read current consent state
const consent = window.CookieFacil?.getConsent();
// Returns: { analytics: true/false, marketing: true/false, functional: true/false }

// Listen for consent changes
document.addEventListener('cf:consent', function(e) {
    const { analytics, marketing, functional } = e.detail;

    if (analytics) {
        // Safe to fire analytics now
        loadGoogleAnalytics();
    }
    if (marketing) {
        // Safe to fire ad pixels now
        loadMetaPixel();
    }
});

// Check specific category
if (window.CookieFacil?.hasConsent('analytics')) {
    // Analytics consent already granted on this visit
    initAnalytics();
}

How CookieFácil handles this automatically

With the CookieFácil script installed as the first item in your <head>, all of the above is handled automatically. You do not need to write a MutationObserver, manage consent state, or re-inject scripts manually. The script intercepts GA4, GTM, Meta Pixel, Hotjar, TikTok Pixel, and hundreds of other known tracking libraries by pattern matching against their source URLs.

For custom scripts, add data-consent-category="analytics" (or marketing / functional) to your existing script tags — no other change needed.

Choose the right plan for your business

Start free and scale as your consent volume grows. Billed in BRL — no credit card required to start.

Free

Start collecting consent records


  • 1 site · 1,000 visitors/month

  • Cookie consent banner — LGPD + GDPR ready

  • Basic consent reports

Start Free
Most Popular

Basic

For growing businesses


  • 2 sites · 5,000 visitors/month

  • CSV export of consent records

  • Remove CookieFácil branding

Get Started

Professional

For multiple sites and agencies


  • 5 sites · 50,000 visitors/month

  • CSV + PDF + advanced reports

  • Custom CSS and geo-targeting rules

Get Started

Frequently asked questions

  • How do you block scripts before consent under LGPD?

    Change non-essential script tags from type="text/javascript" to type="text/plain" and add a data-consent-category attribute. A MutationObserver intercepts dynamically injected scripts. After consent, re-inject with the correct type restored.

  • Can I use async or defer on the LGPD consent script?

    No. The consent script must be synchronous and the first script in the HTML head. Using async or defer means tracking scripts may execute before the consent script loads — a direct LGPD violation.

  • What is type rewriting in the context of LGPD cookie consent?

    Type rewriting changes script tags from type="text/javascript" to type="text/plain" so the browser ignores them. The consent manager restores the original type after the user accepts, causing the browser to execute them.

  • How do I handle dynamically injected scripts for LGPD compliance?

    Use a MutationObserver watching the document body for added script nodes. When a script with a tracked src is detected before consent, remove it immediately or rewrite its type before the browser can execute it.