How to Use Scriptlets to Block Specific Ad Initializations in uBlock Origin

You can block ad initializations before they execute by injecting scriptlets—tiny JavaScript snippets that abort, spoof, or neutralize ad scripts via filter rules that reference files in src/js/scriptlets/.

The gorhill/uBlock repository provides a powerful scriptlet-filtering engine that allows you to intervene in the page lifecycle before ad scripts run. Unlike network blocking, which prevents the download of resources, scriptlets modify or abort JavaScript execution in real-time, making them ideal for stopping ad initializations that occur within bundled or first-party scripts.

Understanding the Scriptlet Architecture in uBlock Origin

Core Engine Components

The scriptlet system relies on two primary modules located in the source tree. The scriptlet-filtering-core.js file (src/js/scriptlet-filtering-core.js) maintains the scriptlet database and handles the lookup logic, while scriptlet-filtering.js (src/js/scriptlet-filtering.js) manages the injection process and coordinates with the browser's content script API.

When a page loads, the engine calls vAPI.scriptletsInjector(hostname, scriptletDetails) (lines 308-311 of src/js/scriptlet-filtering.js) to create and insert the scriptlet code into the page context.

The Scriptlet Database

All available scriptlets reside in the src/js/scriptlets/ directory. The build process automatically scans this folder to populate an internal Map that associates scriptlet names with their source code. Built-in scriptlets include:

  • abort-current-script – Immediately terminates the execution of the current script.
  • noeval-if – Prevents eval() calls containing specific strings.
  • prevent-addEventListener – Blocks event listener registration for specified patterns.
  • noscript-spoof – Replaces global properties with harmless values.

How Scriptlets Block Ad Initializations Before Execution

Filter Parsing and Detection

When uBlock Origin encounters a filter rule containing the scriptlet( option, the static-filtering-parser.js module detects the //#%#//scriptlet( syntax and extracts the scriptlet name and arguments. This parsing occurs during filter list compilation, ensuring that scriptlet references are validated before runtime.

Injection Timing and Execution

Scriptlets execute in the page's main world (or an isolated world in Manifest V3) before the targeted ad scripts are parsed by the JavaScript engine. This temporal priority is crucial because it allows scriptlets to:

  1. Redefine global functions that ads depend on (e.g., replacing window.initAds with a no-op).
  2. Abort execution of scripts containing specific signatures before they initialize ad objects.
  3. Spoof detection mechanisms by returning fake values for properties like window.googletag.

Practical Scriptlet Filter Examples

Aborting Specific Ad Scripts

To stop a script from running entirely when it matches a specific domain pattern, use the abort-current-script scriptlet:

||example.com^$script,scriptlet(abort-current-script)

This rule targets scripts loaded from example.com and injects the abort scriptlet (located at src/js/scriptlets/abort-current-script.js) immediately before execution, preventing any ad initialization code within that file from running.

Blocking Function Calls

When you need to disable a specific initialization function like initAds without blocking the entire script, use noeval-if:

||ads.provider.com^$script,scriptlet(noeval-if,initAds)

The noeval-if scriptlet scans the script source for the string initAds and neutralizes the call, preventing the ad system from initializing while allowing the rest of the script's functionality to remain intact.

Spoofing Global Variables

Many ad scripts check for the existence of window.googletag before initializing. You can spoof this property to make the ad think the library is unavailable:

||publisher.net^$script,scriptlet(noscript-spoof,window.googletag,false)

The noscript-spoof scriptlet replaces the specified global property with the provided value (false in this case) before the ad script executes, causing initialization checks to fail silently.

Combining Multiple Scriptlets

For robust blocking, you can chain multiple scriptlets in a single filter rule:

||spammyads.io^$script,scriptlet(abort-current-script),scriptlet(noscript-spoof,document.cookie,"")

This combination first attempts to abort the script entirely. If the script executes partially before the abort takes effect, the second scriptlet wipes document.cookie, neutralizing any cookie-based ad logic that might have initialized.

Creating Custom Scriptlets for Advanced Ad Blocking

When built-in scriptlets don't cover specific initialization patterns, you can create custom solutions:

  1. Create a new file in src/js/scriptlets/ named after your scriptlet (e.g., my-custom-blocker.js).

  2. Write a self-executing function that accepts arguments from the filter rule:

    // src/js/scriptlets/my-custom-blocker.js
    (function (propertyName, fakeValue) {
        Object.defineProperty(window, propertyName, {
            value: fakeValue,
            writable: false,
            configurable: false
        });
    })(/* arguments populated by uBlock */);
  3. Build the extension – The build process automatically scans src/js/scriptlets/ and registers your new scriptlet in the database maintained by scriptlet-filtering-core.js.

  4. Deploy in a filter rule:

    ||badads.com^$script,scriptlet(my-custom-blocker,window.adInit,null)

Summary

  • Scriptlets are JavaScript snippets stored in src/js/scriptlets/ that execute before ad scripts to block or modify initialization code.
  • The scriptlet-filtering engine (src/js/scriptlet-filtering.js and src/js/scriptlet-filtering-core.js) handles parsing, database lookup, and injection via vAPI.scriptletsInjector().
  • Common blocking patterns include using abort-current-script to stop execution, noeval-if to disable specific functions, and noscript-spoof to fake global properties.
  • Custom scriptlets can be added to src/js/scriptlets/ and are automatically registered during the build process.

Frequently Asked Questions

How do I know if a scriptlet is actually running on a page?

Open uBlock Origin's Logger (the eye icon in the dashboard) and reload the page. Look for entries labeled "scriptlet injected" next to the hostname. If you see your filter rule listed with a plus (+) icon, the scriptlet executed successfully. You can also add console.log() statements to custom scriptlets during development to verify execution order.

Can scriptlets block ads that initialize from inline scripts rather than external files?

Yes. Use the $inline-script filter option instead of $script to target JavaScript embedded directly in the HTML. For example: example.com##+js(abort-current-script, inlineAds) uses the ##+js() syntax (equivalent to scriptlet()) to inject the abort logic specifically for inline script contexts. The engine in src/js/scriptlet-filtering.js handles both external and inline injection points.

What is the difference between abort-current-script and prevent-addEventListener?

abort-current-script (located in src/js/scriptlets/abort-current-script.js) terminates the execution of the currently parsing script immediately, preventing any subsequent code from running. prevent-addEventListener (in src/js/scriptlets/prevent-addEventListener.js) specifically targets and neutralizes calls to addEventListener, preventing ads from binding to user interactions like clicks or scrolls without stopping the entire script. Use the former to block initialization routines and the latter to disable event-driven ad behaviors.

Are custom scriptlets compatible with Manifest V3 (MV3) builds of uBlock Origin?

Yes, but with execution context differences. In MV3 builds, scriptlets injected by vAPI.scriptletsInjector() run in an isolated world rather than the page's main world, which prevents direct access to some page-defined variables but still allows modification of global objects like window and document. The scriptlet-filtering.js module automatically handles the injection method based on the manifest version. Custom scriptlets should avoid relying on variables defined by page scripts unless running in MV2 or using specific messaging APIs.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →