{"id":47890503,"url":"https://github.com/dabrogost/chroma-ad-blocker","last_synced_at":"2026-05-16T05:21:06.761Z","repository":{"id":347274733,"uuid":"1191033952","full_name":"Dabrogost/Chroma-Ad-Blocker","owner":"Dabrogost","description":"Chroma Ad-Blocker || for Manifest v3","archived":false,"fork":false,"pushed_at":"2026-05-03T06:33:48.000Z","size":41194,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-03T08:28:02.342Z","etag":null,"topics":["ad-accelerator","ad-blocker","ad-blocking","ad-stripper","chromium-extension","mv3","mv3-extension","proxy-routing"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Dabrogost.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"docs/CONTRIBUTING.md","funding":".github/funding.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"docs/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"buy_me_a_coffee":"dabrogost"}},"created_at":"2026-03-24T21:22:24.000Z","updated_at":"2026-04-27T12:51:13.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Dabrogost/Chroma-Ad-Blocker","commit_stats":null,"previous_names":["dabrogost/chroma-ad-blocker"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/Dabrogost/Chroma-Ad-Blocker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dabrogost%2FChroma-Ad-Blocker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dabrogost%2FChroma-Ad-Blocker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dabrogost%2FChroma-Ad-Blocker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dabrogost%2FChroma-Ad-Blocker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Dabrogost","download_url":"https://codeload.github.com/Dabrogost/Chroma-Ad-Blocker/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dabrogost%2FChroma-Ad-Blocker/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32757806,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-07T02:14:30.463Z","status":"ssl_error","status_checked_at":"2026-05-07T02:14:29.405Z","response_time":62,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ad-accelerator","ad-blocker","ad-blocking","ad-stripper","chromium-extension","mv3","mv3-extension","proxy-routing"],"created_at":"2026-04-04T03:00:58.920Z","updated_at":"2026-05-16T05:21:06.753Z","avatar_url":"https://github.com/Dabrogost.png","language":"JavaScript","funding_links":["https://buymeacoffee.com/dabrogost"],"categories":[],"sub_categories":[],"readme":"# Chroma Ad-Blocker\n\n**Chroma Ad-Blocker** is an advanced browser extension built for Manifest V3 (MV3). It combines several local protection layers to maintain functionality across a wide range of websites while aiming to keep resource use low. Chroma is free, open-source (GPLv3), and privacy-focused. For best results, it is recommended to disable other ad-blocking extensions while using Chroma.\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"assets/popup.gif\" alt=\"Chroma Ad-Blocker Popup Preview\" width=\"360\"\u003e\n\u003c/div\u003e\n\n## Index\n\n- [Key Features](#key-features)\n- [Architecture Overview](#architecture-overview)\n- [System Layers](#system-layers)\n- [Privacy \u0026 Transparency](#privacy--transparency)\n- [Media Proxy Router](#media-proxy-router-split-tunneling)\n  - [How This Differs From FoxyProxy](#how-this-differs-from-foxyproxy)\n- [YouTube Ad Stripping](#youtube-ad-stripping)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [Statistics \u0026 Event Tracker](#statistics--event-tracker)\n- [Filter List Subscriptions](#filter-list-subscriptions)\n- [Why Not the Chrome Web Store?](#why-not-the-chrome-web-store)\n\n## Key Features\n\n- **YouTube Ad Stripping**: Chroma's primary defense against YouTube ads. It intercepts and cleans ad-related metadata from JSON payloads before they reach the player, including sponsored Shorts overlay payloads, providing a seamless, high-performance viewing experience without the need for acceleration.\n- **Split-Tunnel Proxy Router**: Allows selected media domains to route through a custom HTTP, HTTPS, SOCKS4, or SOCKS5 proxy server directly in the browser while keeping unrelated traffic direct. This is designed for routing media sites through proxy regions that reduce ad serving or match country-specific media delivery. Includes a **Global Fallback** mode for unmatched browser traffic, domain-specific proxy overrides, Smart-Link Auto-Expansion for supported media/CDN domains, real-time connectivity verification, and local-only proxy credential handling for HTTP/HTTPS proxy authentication.\n- **Source-Generated DNR Network Blocking**: Uses a generated OISD Big static Declarative Net Request (DNR) ruleset, a protected custom static layer, and runtime dynamic rules to block trackers, invasive analytics, and traditional banner ads at the browser engine level.\n- **Tracking URL \u0026 AMP Cleanup**: Removes known tracking query parameters from top-level navigation URLs with DNR redirect rules, and optionally redirects supported AMP viewer pages to publisher URLs.\n- **Live Filter List Subscriptions**: Subscribes to Hagezi Pro Mini, Chroma Hotfix, EasyList, Fanboy Annoyance, and the bundled Chroma Scriptlet Library, with refresh intervals tuned per list. Subscription rules are deduplicated against the static ruleset before allocation to maximize coverage within the dynamic rule budget.\n- **Scriptlet Injection Engine**: A high-performance surgical layer powered by the `userScripts` API. It translates uBlock Origin/AdGuard syntax into native JavaScript and injects matched scriptlets at specific navigation milestones (`document_start`, `document_idle`, `document_end`) to neutralize anti-adblock scripts, prune dynamic JSON payloads, and intercept API calls.\n- **Cosmetic Filtering Layer**: Removes ad slots, placeholders, and unwanted UI elements (Shorts, Merch, Offers) via high-speed CSS injection and DOM mutation monitoring. Optimized for YouTube and Twitch (where server-side ad insertion prevents network blocking).\n- **Element Zapper**: Lets you point-and-click any stubborn page element to hide it with a locally saved cosmetic rule. Rules can be toggled or deleted from settings without editing filter lists.\n- **Local Event Tracker**: The settings page includes a local-only statistics dashboard for Protection Events, top domains, rule sources, timelines, and recent event details. It distinguishes network blocks from allow/whitelist matches and keeps payload details in the tracker instead of promoting platform-specific badges.\n- **Privacy Hardening \u0026 Fingerprint Randomization**: Optional Chrome privacy controls block third-party cookies, keep Do Not Track off, disable supported Privacy Sandbox ad APIs, and block website geolocation access. Optional per-host fingerprint randomization farbles canvas, audio, WebGL, navigator, and language APIs.\n- **Main-World Interceptor Safety Exclusions**: Bypasses Chroma's generic MAIN-world interceptor/bridge on critical infrastructure, including listed financial institutions, authentication providers, and sensitive TLDs (`.gov`, `.mil`, `.edu`, `.int`). Broader network, cosmetic, and scriptlet behavior remains governed by user settings, subscriptions, and per-domain whitelisting.\n- **Security-Hardened Architecture**: Features closure-scoped session state, validated config update pipelines, pristine API caching, and a dead man's switch to prevent host-page interference and script hijacking.\n- **Recipe \u0026 Blog Optimization**: Provides specialized protection for high-clutter recipe and lifestyle sites. It prevents ad scripts from breaking site layouts, preserves recipe card content, and suppresses aggressive anti-adblock overlays and scroll-locks.\n- **Dynamic Ad Acceleration**: Automatically identifies and accelerates video ads at a configurable speed (×4–×16, default ×8) on YouTube and Amazon Prime Video (Twitch uses server-side ad insertion and does not support ad acceleration), serving as a robust fallback when stripping is disabled.\n- **Platform Compatibility**: Fully compatible with **Windows**, **macOS**, and **Linux** versions of **Google Chrome 122+** (and other Chromium-based browsers with engine version 122+). This version is required to support the multi-part static ruleset.\n\n---\n\n## Architecture Overview\n\nChroma utilizes a multi-layered execution model designed to survive the ephemeral lifecycle of Manifest V3 service workers while preserving clear performance and security boundaries.\n\n**Diagram 1 — Page Execution Flow**\n\nHow Chroma operates inside a browser tab. The always-on isolated content script handles cosmetics; MAIN-world logic only runs where the manifest or registered scriptlets match.\n\n```mermaid\ngraph TD\n    classDef ext fill:#e8f5e9,color:#1b5e20,stroke:#1b5e20,stroke-width:2px\n    classDef main fill:#fce4ec,color:#880e4f,stroke:#880e4f,stroke-width:2px\n    classDef page fill:#fff9c4,color:#f57f17,stroke:#f57f17,stroke-width:2px\n    classDef actor fill:#eceff1,color:#263238,stroke:#263238,stroke-width:2px\n\n    LOAD[\"Page load\"]:::actor\n    PAGE[\"Page DOM / Media Player\"]:::page\n    USER[\"User\"]:::actor\n\n    LOAD --\u003e CONTENT[\"content.js\u003cbr/\u003eall URLs, isolated world\"]:::ext\n    CONTENT --\u003e|\"cosmetic CSS + DOM cleanup\"| PAGE\n\n    LOAD --\u003e MEDIA{\"YouTube or Amazon/Prime?\"}:::actor\n    MEDIA --\u003e|\"yes\"| BRIDGE[\"protection.js + interceptor.js\u003cbr/\u003esecure config bridge\"]:::main\n    BRIDGE --\u003e HANDLERS[\"yt_handler.js / prm_handler.js\u003cbr/\u003estrip YouTube JSON or accelerate ads\"]:::main\n    HANDLERS --\u003e PAGE\n\n    LOAD --\u003e RECIPES{\"Recipe/blog allowlist?\"}:::actor\n    RECIPES --\u003e|\"yes\"| RECIPE[\"recipes.js\u003cbr/\u003elayout protection + anti-adblock containment\"]:::main\n    RECIPE --\u003e PAGE\n\n    LOAD --\u003e SCRIPTLETS[\"Registered scriptlets / optional FPR\u003cbr/\u003eMAIN world, matched by rule\"]:::main\n    SCRIPTLETS --\u003e PAGE\n\n    ZAP[\"Element zapper\u003cbr/\u003einjected only from popup\"]:::ext --\u003e|\"saved local cosmetic rule\"| CONTENT\n\n    PAGE --\u003e USER\n```\n\n---\n\n**Diagram 2 — Background \u0026 Network Flow**\n\nHow Chroma manages rules, storage, and network-level blocking from the service worker.\n\n```mermaid\ngraph TD\n    classDef sw fill:#e1f5fe,color:#01579b,stroke:#01579b,stroke-width:2px\n    classDef storage fill:#fff3e0,color:#e65100,stroke:#e65100,stroke-width:2px\n    classDef dnr fill:#ede7f6,color:#311b92,stroke:#311b92,stroke-width:2px\n    classDef browser fill:#fff9c4,color:#f57f17,stroke:#f57f17,stroke-width:2px\n    classDef actor fill:#eceff1,color:#263238,stroke:#263238,stroke-width:2px\n\n    UI[\"Popup / Settings UI\"]:::actor\n    SW[\"Service Worker\u003cbr/\u003ebackground.js + handlers.js\"]:::sw\n    STORE[(\"chrome.storage.local\")]:::storage\n    SUBS[\"subscriptions/manager.js\u003cbr/\u003efetch, parse, dedupe, allocate\"]:::sw\n    SCRIPTS[\"scriptlets/engine.js\u003cbr/\u003eregister userScripts + optional FPR\"]:::sw\n    DNR[\"Declarative Net Request\u003cbr/\u003estatic rules + dynamic rules\"]:::dnr\n    PROXY[\"proxy.js\u003cbr/\u003eoptional PAC routing + auth\"]:::sw\n    REQ[\"Browser Requests\"]:::browser\n    NET[\"Network\"]:::browser\n    TABS[\"Open Tabs\"]:::actor\n\n    UI --\u003e SW\n    SW \u003c--\u003e|\"local storage\"| STORE\n    SW --\u003e TABS\n    SW --\u003e DNR\n\n    SW --\u003e SUBS\n    SUBS --\u003e DNR\n    SUBS --\u003e STORE\n    STORE --\u003e SCRIPTS\n    SCRIPTS --\u003e TABS\n\n    STORE --\u003e PROXY\n    REQ --\u003e|\"DNR policy gate\"| DNR\n    DNR --\u003e PROXY\n    PROXY --\u003e|\"PAC route\"| NET\n```\n\n---\n\n## System Layers\n\n### Layer 1: Network-Level Blocking (extension/rules/, extension/background/background.js, extension/subscriptions/)\nThe primary engine of Chroma, powered by the Declarative Net Request (DNR) API. Chroma partitions its blocking logic into source-owned static rulesets: generated OISD Big rules, a protected custom static layer, and a specialized recipe layer.\n\n#### How Chroma Keeps Large Static Rulesets Practical\nUsers often wonder how static rules can operate without moving every request through extension JavaScript. Chroma relies on three architectural advantages:\n- **Engine-Level Matching**: Unlike legacy ad-blockers that use the `webRequest` API for request decisions, DNR rules are handed off to Chromium's Declarative Net Request implementation before matching.\n- **Browser-Managed Indexing**: Chromium validates and indexes static rulesets when the extension is installed or updated. Chroma does not depend on a specific internal data structure or lookup guarantee.\n- **Low JS Request-Path Overhead**: Because the matching logic lives outside of the extension's execution context, Chroma avoids waking its own service worker for every blocked request.\n- **Deduplication Budgeting**: Subscription rules from Hagezi Pro Mini are automatically deduplicated against the static ruleset on each refresh. This ensures that the dynamic rule budget is reserved only for unique, high-priority threats.\n\n### Layer 1b: URL Cleanup \u0026 De-AMP (defaultDynamicRules.js, content.js)\nChroma can clean common tracking URLs without routing requests through extension JavaScript. **Tracking URL Cleanup** uses dynamic DNR redirect rules to remove known attribution parameters such as `utm_*`, `fbclid`, `gclid`, and similar campaign IDs from top-level navigations. The cleanup rule set is split into small Chrome-compatible matchers so it stays within DNR regex limits while each matched rule still removes the full known tracking-parameter set.\n\n**De-AMP Links** is optional and disabled by default. When enabled, Chroma redirects supported Google AMP viewer and AMP cache URLs to the publisher URL, while respecting current-site and target-domain whitelists.\n\n### Layer 2: Scriptlet Injection (scriptlets/engine.js)\nThe advanced surgical layer of the extension, migrated to the high-performance `chrome.userScripts` API. This engine parses complex scriptlet rules from filter list subscriptions, including uBlock Origin and AdGuard aliases. Key capabilities include:\n- **JSON Pruning**: Uses strict dot-notation path pruning (`json-prune`) to intercept and clean dynamic data payloads in `JSON.parse` calls.\n- **Regex Translation**: Features a built-in pre-processor that translates uBO network-style patterns (e.g., `||example.com^`) into optimized JavaScript RegExp strings for runtime matching.\n- **Flexible Execution Timing**: Supports explicit timing flags (`document_start`, `document_idle`, `document_end`), ensuring scriptlets execute at the optimal lifecycle moment (defaulting to `document_start` for critical API tampering).\n- **Broad Compatibility**: Supports a wide range of scriptlets including `abort-on-property-read`, `set-constant`, `prevent-fetch`, and `no-eval-if`.\n\n### Layer 3: Cosmetic \u0026 Warning Suppression (content.js)\nUtilizes a high-performance MutationObserver and CSS injection via Constructable Stylesheets. This layer hides ad slots, removes unsolicited overlay dialogs that restrict content access based on browser configuration, and cleans up the UI by removing non-video components like Shorts, Merchandise, and Movie/TV offers.\n\n### Layer 3b: Element Zapper (content/zapper.js, background/handlers.js)\nAn on-demand cosmetic rule builder for elements that are too site-specific or personal to belong in a shared filter list. From the popup, click **Zap Element**, choose the page element, and Chroma generates a scoped selector preview before saving it as a local rule. Saved zapper rules are stored locally, applied by the cosmetic layer, and can be enabled, disabled, or removed from settings.\n\n### Layer 4: Universal Protection (protection.js, interceptor.js)\nA proactive security layer that maintains extension integrity across execution contexts. `interceptor.js` runs in the Main World to shadow sensitive browser APIs and expose the secure `__CHROMA_INTERNAL__` bridge. `protection.js` reads stored configuration at page load, dispatches the `__EXT_INIT__` document event to signal the MAIN world handlers, and relays live config updates from the background to the MAIN world handlers via CustomEvent.\n\n### Layer 5: YouTube Ad Stripping (yt_handler.js)\nA specialized platform layer designed specifically for YouTube. It intercepts raw JSON responses from the YouTube API and surgically removes ad metadata (e.g., `adPlacements`, `playerAds`) before the player reads them. This results in a seamless, ad-free experience without pauses or the need for playback acceleration. Session state is fully private to the handler closure — host-page scripts cannot observe or tamper with internal state.\n\n### Layer 6: Recipe \u0026 Blog Protection (recipes.js)\nA specialized defense-in-depth layer optimized for high-clutter recipe and lifestyle blogs (e.g., CafeMedia/Raptive and Dotdash Meredith sites). It implements a multi-pronged strategy to ensure a clean reading experience:\n- **Style Protection**: Prevents aggressive anti-adblock scripts from stripping `\u003cstyle\u003e` and `\u003clink\u003e` elements, ensuring the site's layout remains intact.\n- **Recipe Content Preservation**: Uses semantic and container-based exclusion to ensure that ingredients and instructions are never accidentally hidden by cosmetic filters.\n- **Anti-Adblock Containment**: Neutralizes known anti-adblock recovery payloads in script handlers and redirects, and suppresses intrusive alert/confirm dialogs.\n- **Scroll Lock Recovery**: Dynamically detects and reverses scroll-locks (e.g., `overflow: hidden`) and body-hiding tactics used by ad-block walls.\n- **Site-Specific Rules**: Includes custom cosmetic overrides for major platforms like AllRecipes, Food Network, NYT Cooking, and Serious Eats.\n\n### Layer 7: Dynamic Ad Acceleration (prm_handler.js, yt_handler.js)\nA robust fallback and specialized layer for Amazon Prime Video and YouTube (when stripping is disabled). **Shipped in an OFF state by default**, it detects active ads and accelerates them at a configurable speed (×4–×16, default ×8) while synchronizing with a custom overlay to deliver a seamless transition.\n\n### Layer 8: Browser Privacy \u0026 Fingerprint Hardening (browserPrivacy.js, fingerprintRandomization.js)\nChrome Privacy Hardening is optional and off by default. When enabled, Chroma uses Chrome's `privacy` API to block third-party cookies, keep Do Not Track disabled, and disable supported Privacy Sandbox ad APIs including Topics, Protected Audience, and ad measurement.\n\nGeolocation Protection is also optional and off by default. When enabled, Chroma uses Chrome's `contentSettings.location` API to block sites from accessing your real physical location. It does not spoof or synthesize fake coordinates; turning it off clears Chroma's rule so Chrome returns to the user's normal location setting.\n\nFingerprint Randomization is also optional and off by default because some sites can be sensitive to fingerprint changes. When enabled, Chroma registers a MAIN-world script that randomizes/farbles supported fingerprint surfaces on a per-host basis, including canvas, audio, WebGL, navigator hardware fields, and normalized language APIs.\n\n---\n\n## Privacy \u0026 Transparency\n\nChroma processes everything locally — no data is ever sent to Chroma's servers because there are none. However, to maintain compatibility with certain websites, Chroma includes a small set of **Allow Rules** that permit specific, standard ad-measurement requests to reach their intended destinations. These rules are scoped exclusively to the supported streaming platform as the initiator domain.\n\nChroma does not intercept or store any data from these requests. For a full explanation of this tradeoff, see the [Privacy Policy](docs/PRIVACY_POLICY.md).\n\n### Google My Ad Center Tip\n\nFor another account-level privacy improvement, open [Google My Ad Center](https://myadcenter.google.com) and turn **Personalized Ads** to **OFF**.\n\nThis can reduce ad personalization and tracking activity tied to your Google account.\n\n---\n\n## Media Proxy Router (Split-Tunneling)\n\nChroma includes a built-in split-tunnel proxy router that allows you to route traffic for specific media domains through a proxy server while keeping the rest of your browser traffic on your direct, local connection. It is designed for media-site routing: sending supported services through proxy regions that reduce ad serving, or through country-specific routes for region-specific media delivery. This operates entirely within the browser via dynamic Proxy Auto-Configuration (PAC) scripts, meaning it does not require a system-level VPN installation.\n\n### How This Differs From FoxyProxy\n\nChroma's proxy router is not intended to replace a full general-purpose proxy manager such as FoxyProxy. FoxyProxy is designed around proxy profiles, URL patterns, tab-level routing, quick switching, import/export workflows, and broad user-defined proxy management.\n\nChroma's router is narrower by design. It exists as one layer of Chroma's larger local protection stack: DNR network blocking, scriptlets, cosmetic filtering, media handling, local event tracking, and optional browser-level routing all work together. The proxy layer is focused on split-tunneling selected media domains through user-provided proxies while keeping unrelated browser traffic direct, or optionally sending unmatched browser traffic through a Global Fallback proxy.\n\nThe main difference is that Chroma is media-aware. When a supported streaming or media service is routed, Chroma can automatically include related CDN and delivery domains so the service UI and media stream are less likely to split across different IP paths. For example, adding `youtube.com` can also route related YouTube delivery domains such as `googlevideo.com`, `ytimg.com`, and `youtube-nocookie.com`.\n\nChroma's design principle is:\n\n\u003e DNR is the policy gate. PAC is the transport selector.\n\nNetwork filtering decides what should be blocked or allowed by the browser's DNR engine. Proxy routing decides whether browser traffic that proceeds through Chrome's network stack should go direct or through a selected proxy.\n\n| Feature | Chroma Proxy Router | General Proxy Manager |\n|---|---|---|\n| Primary purpose | Media-aware split tunneling for ad-reducing or country-specific media routes inside Chroma's protection stack | Full proxy profile and rule management |\n| Routing model | Domain-specific rules, Smart-Link CDN expansion, optional Global Fallback | Proxy profiles, URL patterns, tab rules, PAC URLs, quick switching |\n| Scope | Browser-level routing for selected traffic | General-purpose proxy control |\n| Ad-block integration | Works alongside Chroma's DNR, scriptlet, cosmetic, and media layers | Usually separate from ad blocking |\n| Best use case | Route a service like YouTube, Netflix, Prime Video, or Twitch through a chosen media region without routing everything | Manage many proxies and complex user-defined routing rules |\n\nUse FoxyProxy when you want a dedicated proxy manager. Use Chroma's proxy router when you want routing to work as part of Chroma's ad-blocking, media, and privacy stack.\n\n### Supported Protocols\nChroma supports `HTTP`, `HTTPS`, `SOCKS4`, and `SOCKS5` proxies. Choose the protocol from the proxy setup dropdown, then enter the proxy host without a protocol prefix.\n\nSOCKS4/SOCKS5 proxies are supported only when they do not require username/password authentication. Chrome extensions can provide credentials for HTTP/HTTPS proxy authentication challenges, but Chrome does not expose SOCKS username/password authentication to extensions through the proxy/PAC flow. For authenticated SOCKS providers, use provider-side IP allowlisting if available, or choose an HTTP/HTTPS proxy endpoint instead.\n\nThis limitation is specific to browser-level proxy routing in Chromium. It does not mean authenticated SOCKS5 is impossible everywhere: apps that implement their own SOCKS connection can accept SOCKS credentials directly. For example, [NordVPN documents SOCKS5 setup in qBittorrent](https://support.nordvpn.com/hc/en-us/articles/20195967385745-NordVPN-proxy-setup-for-qBittorrent) with a SOCKS5 host, port `1080`, and service username/password. That works because qBittorrent owns the SOCKS connection; Chroma only controls Chrome's PAC/proxy route.\n\n### Security\nYour proxy credentials (username and password) are stored locally in an obfuscated form using a bundled extension key. They are decoded in memory only when the proxy server challenges the browser for authentication. This can reduce casual readability in extension storage, but it is not strong encryption and is not a substitute for operating-system or browser-profile security.\n\n### Connection Verification\nThe Chroma popup includes a live **Connection Verification** system. When a proxy is active, the extension verifies connectivity when the proxy card loads or when you manually refresh it, then displays a status indicator (Connected/Offline) along with the detected proxied IP address when available.\n\n### Global Proxy Fallback\nIn addition to domain-specific routing, Chroma supports a **Global Fallback** mode. Click the **GLOBAL** button on a proxy card to select that proxy as the fallback for browser traffic that does not match a domain-specific rule. This is browser-level proxy routing, not a system VPN, while still allowing you to send specific traffic (e.g., YouTube) to a different proxy server (e.g., Belize) simultaneously.\n\nThe main switch on each proxy card is a per-proxy enabled/disabled control:\n- **Switch ON**: The proxy can route its enabled domain rules, and can act as the selected global fallback if its **GLOBAL** button is active.\n- **Switch OFF**: The proxy routes nothing while disabled. Its domain rows are kept, and if it was selected as **GLOBAL**, that global selection is preserved but inactive until the switch is turned back on.\n- **GLOBAL button**: Selects or clears the global fallback independently from the main switch. The active **GLOBAL** button is highlighted. The selected global card hides its domain add/list controls while it is global; non-global proxy cards keep their domain controls visible.\n\n### Chrome Browser Services Bypass\nWhen Global Proxy Fallback is enabled, Chroma can optionally bypass Chrome-owned browser service traffic so Chrome's own infrastructure can still connect directly. The **Bypass Chrome Browser Services** toggle is enabled by default so the extension does not appear to break Chrome functionality when Global Proxy is enabled.\n\nRecommended: lets Chrome-owned services connect directly while Global Proxy is enabled, helping updates, sign-in, Gemini, and model downloads work. Turning this off is more secure/strict, but may break Chrome AI / Gemini Nano.\n\nWebRTC Leak Protection helps prevent WebRTC/STUN traffic from bypassing proxy routing. WebRTC can discover network candidates through paths that are separate from normal browser page requests, so a page may be able to see a WebRTC public IP even while regular traffic is routed through Chroma's proxy fallback. Chroma controls Chrome's native WebRTC IP handling policy to reduce that bypass risk.\n\nIn **Auto** mode, Chroma applies strict WebRTC protection when Global Proxy Fallback is enabled and configured, and releases the browser setting when it no longer applies. **Balanced** limits WebRTC to the default public interface only. **Strict** disables non-proxied UDP, which offers the strongest protection but may affect browser calls or video chat quality.\n\n### Dynamic Routing Status\nThe Chroma popup provides real-time feedback on your routing state. The status line on each proxy card will dynamically update to show exactly what it is doing:\n- **GLOBAL PROXY ACTIVE**: The server is handling all browser traffic.\n- **ROUTING [X] DOMAINS**: The server is only handling the specific domains you have listed.\n- **CONNECTED**: The server is ready but has no current routing assignments.\n- **DISABLED**: The proxy is saved but paused. Its domain rows and global selection, if any, are preserved.\n\n### Example: Setting up NordVPN\nMany commercial VPN providers (like NordVPN, ExpressVPN, and PIA) operate browser-compatible proxy servers. Here is how to route specific domains through a NordVPN HTTPS proxy server (e.g., Belize #1):\n\n1. **Protocol:** Select `HTTPS` from the dropdown.\n2. **Host:** Enter `bz1.proxy.nordvpn.com`.\n3. **Port:** Enter `89` *(commonly used by NordVPN HTTPS/HTTP SSL proxy endpoints)*.\n4. **Username \u0026 Password:** You **cannot** use your standard NordAccount email/password. You must use your auto-generated **Service Credentials**, which can be found in your NordAccount dashboard under *Services \u003e NordVPN \u003e Manual Setup*.\n5. **Domains:** Add the domains you want to route (e.g., `youtube.com`) to the active list.\n6. Click **Accept Settings**.\n\nAs of May 11, 2026, this NordVPN-specific example may require converting Nord's displayed server address from `bz1.nordvpn.com` to the browser-compatible proxy host form `bz1.proxy.nordvpn.com`. Other proxy providers may use different hostnames, ports, protocols, and credential requirements, so follow your provider's current proxy setup instructions.\n\nProxy-region performance can vary by provider, route, and streaming service. If YouTube buffers above 1080p or struggles in fullscreen, try another nearby proxy region before assuming the extension is at fault.\n\n### Smart-Link Auto-Expansion\nTo prevent \"infinite spin\" and geo-blocking issues caused by IP mismatches between a site's UI and its video delivery network, Chroma includes a **Smart-Link** system. When you add a major streaming service to your proxy list, Chroma automatically identifies and proxies its associated media delivery networks (CDNs).\n\nFor example, adding `youtube.com` automatically proxies `googlevideo.com`, `ytimg.com`, and `youtube-nocookie.com`, ensuring that the video stream itself originates from the same proxy IP as your main session. Supported services include:\n- **YouTube** (`googlevideo.com`, `ytimg.com`, `ggpht.com`, `youtube-nocookie.com`, `youtu.be`, `youtubei.googleapis.com`, `youtube.googleapis.com`)\n- **Netflix** (`netflix.net`, `nflxvideo.net`, `nflxext.com`, `nflximg.com`, `nflximg.net`, `nflxso.net`, `nflxsearch.net`)\n- **Amazon Prime Video** (`amazonvideo.com`, `primevideo.com`, `aiv-cdn.net`, `pv-cdn.net`, `aiv-delivery.net`, `media-amazon.com`, `ssl-images-amazon.com`, + all global TLDs like `.de`, `.co.jp`)\n- **Twitch** (`ttvnw.net`, `jtvnw.net`, `twitchcdn.net`)\n- **Disney+** (`disney-plus.net`, `dssott.com`, `dssedge.com`, `bamgrid.com`, `disney-plus.com`)\n- **Hulu** (`hulumail.com`, `huluim.com`, `hulu.hbomax.com`)\n- **Max (HBO)** (`hbomax.com`, `hbo.com`, `hbonow.com`, `hbogo.com`)\n- **Spotify** (`scdn.co`, `spotify.net`, `audio-ak-spotify-com.akamaized.net`)\n\n---\n\n## YouTube Ad Stripping\n\nChroma features a high-performance **YouTube Ad Stripper** that provides a superior alternative to traditional ad blocking and acceleration. \n\n### How it Works\nInstead of reacting to ads after they appear, the Stripper operates at the data layer. It intercepts communication between your browser and YouTube's internal API (`/youtubei/v1/player`, `/next`, etc.) and surgically removes ad-related metadata before the YouTube player can process it.\n\n- **Upstream Neutralization**: By deleting fields like `adPlacements`, `adSlots`, and `playerAds` from the raw JSON responses, the Stripper makes the YouTube player believe the video is entirely ad-free.\n- **Seamless Viewing Experience**: Because the ads are \"stripped\" before they ever load, there is no \"Ad starting in 5 seconds\" countdown, no black screens, and no need for the acceleration engine to kick in.\n- **Payload Interception**: It utilizes deep hooks into `window.fetch`, `XMLHttpRequest`, and `JSON.parse` to ensure that even batched or worker-side requests are cleaned of ad data.\n- **Feed \u0026 Search Optimization**: Beyond the video player, it strips promoted \"Sparkles\" ads, suggested products, and sponsored results from your home feed and search results.\n- **Sponsored Shorts Blocking**: Sponsored Shorts can arrive as reel payloads with `adsOverlay`, `shortsAdsRenderer`, `sequenceItemInPlayerAdLayoutRenderer`, or `reelWatchEndpoint.adClientParams.isAd`. The Stripper prunes those payloads before the Shorts player renders the sponsored overlay.\n\n\u003e [!TIP]\n\u003e While \"Ad Acceleration\" is still available as a fallback, the **Stripper** is the recommended method for a seamless, \"native\" YouTube experience. The stripper can still have a slight delay while the YouTube player processes cleaned data, and behavior can change when YouTube changes its delivery pipeline. Proxy-side ad-free payloads can reduce delay in supported setups because the payload starts without ad data.\n\n---\n\n## Element Zapper\n\nThe **Element Zapper** is a manual cleanup tool for one-off annoyances that filter lists do not catch: sticky banners, leftover ad containers, newsletter blocks, floating widgets, or site-specific clutter.\n\n1. Open the Chroma popup on an `http://` or `https://` page.\n2. Click **Zap Element**.\n3. Click the unwanted page element. Press `Esc` to cancel.\n4. Review the selector prompt and save it.\n\nZapper rules are local to your browser and are stored as cosmetic rules with a `zapper` source. Chroma rejects invalid selectors and warns when a selector matches too many elements, helping avoid accidental broad hiding. Saved rules can be toggled or deleted from settings at any time.\n\n---\n\n## Permissions\n\nChroma requests the following permissions. Each is required for a specific, documented purpose.\n\n| Permission | Reason |\n|---|---|\n| `declarativeNetRequest` | Enables and manages the static and dynamic DNR rulesets that perform network-level ad and tracker blocking at the browser engine level. |\n| `declarativeNetRequestFeedback` | Allows the service worker to read which DNR rules fired in supported install contexts. Chroma uses this for the local request log and network event classification; DNR matches are not blindly treated as blocked ads. |\n| `storage` | Base API required to persist user configuration and subscription metadata across sessions. |\n| `unlimitedStorage` | Chrome's default `chrome.storage.local` cap is 10 MB — insufficient for Chroma's runtime needs. Storage holds cached subscription rule sets (Hagezi Pro Mini alone can approach this limit), the static deduplication index, blocking statistics, and user configuration. No storage is used to collect or transmit user data. |\n| `tabs` | Required to read the active tab's URL for whitelist matching in the popup and to reload the tab when the whitelist is toggled. |\n| `alarms` | Powers periodic subscription refresh checks. Chrome MV3 service workers are ephemeral and cannot use `setInterval` — `chrome.alarms` is the only reliable timer mechanism available. |\n| `userScripts` | The primary API for the scriptlet engine. Allows registered scriptlets to execute in the page's MAIN world context with optimal performance and native lifecycle management. Chrome 138+ also requires users to enable **Allow User Scripts** on Chroma's extension details page. |\n| `scripting` | Used for supplemental on-demand script injection and legacy compatibility. |\n| `proxy` | Enables the split-tunnel proxy router and PAC script generation for domain-specific routing. |\n| `privacy` | Allows Chroma to apply optional browser-level privacy controls, including WebRTC leak protection and Chrome Privacy Hardening. |\n| `contentSettings` | Allows Chroma to provide an optional Geolocation Protection toggle that blocks website location access through Chrome's native site setting. |\n| `webRequest` | Used to intercept authentication challenges from proxy servers. |\n| `webRequestAuthProvider` | Required to provide credentials to proxy servers via the `onAuthRequired` listener. |\n\n---\n\n## Security Hardening\n\nChroma implements several advanced security measures to ensure extension integrity and prevent bypass by third-party scripts:\n\n- **Closure-Scoped Session State**: All session tracking variables in the acceleration handlers are private to the IIFE closure. Host-page scripts cannot read or modify acceleration state, session flags, or ad counters.\n- **Config Update Validation**: All incoming configuration updates — whether from the popup or a `__CHROMA_CONFIG_UPDATE__` CustomEvent — are validated against a strict key allowlist with type and range checks. Invalid values are silently rejected before reaching the internal config object.\n- **Immutable API Bridge**: Exposes internal utilities via a locked `__CHROMA_INTERNAL__` object. This bridge is protected using `Object.defineProperty` with `writable: false` and `configurable: false`, preventing host pages from hijacking extension logic.\n- **Pristine API Caching**: `interceptor.js` captures and freezes native browser APIs (such as `querySelector`, `setTimeout`, and `Function.prototype.toString`) immediately at `document_start`. This ensures that even if a site attempts prototype pollution, the extension operates using trusted, original functions.\n- **Dead Man's Switch**: If core native APIs fail integrity checks at startup, the interceptor severs its secure port and falls back to safe defaults rather than operating in a potentially compromised environment.\n- **Sentinel Hardening**: Internal activation state is managed via a private `WeakMap` within the handler closure. This prevents host-page scripts from observing or tampering with the extension's lifecycle markers once initialization is complete.\n- **Secure Config Handshake**: A secure, capture-phase handshake establishes a private communication pipeline (`MessageChannel`) between the Main World and the protected background. This allows for the delivery of verified configuration and selector sets via a randomized, per-session port transfer nonce, ensuring that sensitive data remains inaccessible to page scripts.\n- **Origin Authentication**: The Background Service Worker strictly validates the origin and sender context of all incoming messages, rejecting sensitive data or configuration requests from outside the extension's verified context.\n\n---\n\n## Quick Start\n\n1. Get the latest release from [GitHub](https://github.com/Dabrogost/Chroma-Ad-Blocker/releases/latest), and extract the ZIP file.\n2. Open `chrome://extensions` in Chrome.\n3. Toggle on **Developer Mode** in the top-right corner.\n4. Click **Load unpacked** and select the extracted folder that contains `manifest.json`.\n5. Enable User Scripts support:\n   - **Chrome 138+**: On the Chroma extension card, click **Details**, then enable **Allow User Scripts**.\n   - **Chrome 122-137**: The **Developer Mode** toggle from step 3 enables the `userScripts` API.\n6. Done — Chroma is active on all tabs. Pin it from the extensions menu to access the popup.\n\n## Configuration\n\n| Setting | Description | Default |\n|---------|-------------|---------|\n| `enabled` | Global switch for all features. | `true` |\n| `networkBlocking` | Enables DNR ruleset blocking. | `true` |\n| `trackingUrlCleanup` | Removes known tracking query parameters from top-level navigation URLs. | `true` |\n| `deAmpLinks` | Redirects supported AMP viewer pages to publisher URLs. | `false` |\n| `stripping` | Enables YouTube Ad Stripping (the primary blocker). | `true` |\n| `acceleration` | Enables accelerated ad playback (as a fallback). | `false` |\n| `accelerationSpeed` | Playback rate multiplier for accelerated ads (×4, ×8, ×12, or ×16). | `8` |\n| `cosmetic` | Enables hiding ad placeholders via CSS. | `true` |\n| `localCosmeticRules` | Stores locally created Element Zapper cosmetic rules. | `[]` |\n| `hideShorts` | Removes Shorts component modules. | `false` |\n| `hideMerch` | Removes Merchandise panels. | `true` |\n| `hideOffers` | Removes Movie/TV offer modules. | `true` |\n| `suppressWarnings` | Removes unsolicited overlay dialogs that restrict content access. | `true` |\n| `whitelist` | Stores domains where Chroma blocking is disabled. The current-site popup toggle updates this list. | `[]` |\n| `globalProxyEnabled` | Enables browser-level fallback routing through the selected proxy when no domain-specific proxy rule matches. | `false` |\n| `globalProxyId` | Stores the selected global fallback proxy ID. | `null` |\n| `chromeServiceProxyBypass` | Lets Chrome-owned browser services connect directly while Global Proxy Fallback is enabled. | `true` |\n| `webRtcLeakProtection` | Controls Chrome's WebRTC IP handling policy: `off`, `auto`, `balanced`, or `strict`. | `auto` |\n| `fingerprintRandomization` | Enables optional per-host canvas, audio, WebGL, navigator, and language API farbling. | `false` |\n| `browserPrivacyHardening` | Applies Chrome privacy settings for third-party cookies, Do Not Track, and Privacy Sandbox ad APIs. | `false` |\n| `geolocationProtection` | Blocks website access to real physical location through Chrome's native location content setting. | `false` |\n\n## Health Panel\n\nThe settings page includes a **Health** panel for diagnostics. It shows whether each protection layer is active, disabled, degraded, unavailable, or in an error state, including static DNR rulesets, dynamic rules, tracking URL cleanup, De-AMP redirects, subscriptions, cosmetic filtering, scriptlets, fingerprint randomization, browser privacy hardening, proxy routing, whitelists, and request-log/debug availability.\n\nThe panel is diagnostic-only. It reports counts and coarse status information, but does not expose proxy credentials, stored auth data, request URLs, raw filter rules, or request-log contents. DNR match logging is shown separately because `chrome.declarativeNetRequest.onRuleMatchedDebug` is only available in debug/unpacked-style install contexts; when that logging is unavailable, blocking can still work normally.\n\n---\n\n## Statistics \u0026 Event Tracker\n\nThe settings page includes **Protection Intelligence**, a local analytics dashboard backed by the versioned `statsV2` storage record. It upgrades the old single counter into a broader view of Chroma's protection layers without changing blocking behavior or sending telemetry anywhere.\n\nThe popup headline shows **Protection Events**, with a compact breakdown for Network, Cleanup, Scriptlets, and Proxy. This number is intentionally broader than \"ads blocked\": DNR matches can represent network blocks, allow rules, whitelist bypasses, subscription rules, or debug-only matches, so Chroma classifies events before counting them.\n\n### Event Tracker\n\nThe **Events** section in settings shows recent local activity from the protection stack. It can include:\n- Network block, allow, and unknown-match classifications.\n- Cosmetic cleanup and warning-suppression events.\n- Scriptlet hits and sanitized scriptlet errors.\n- Local zapper actions.\n- Payload cleanup or inspection details, including modified payload counts, fields pruned, and ad objects removed.\n- Proxy test and proxy authentication activity.\n\nPayload cleanup remains visible in the Event Tracker for transparency, but it is folded into the broader **Ad Cleanups** stat instead of being promoted as a platform-specific headline badge.\n\n### Privacy Modes\n\nStatistics are stored only in `chrome.storage.local`.\n\n- **Basic**: records totals only going forward. Existing aggregated history is preserved locally unless the user explicitly resets stats.\n- **Aggregated**: totals plus domains, rule sources, resource types, timelines, and recent event summaries.\n- **Debug**: may include recent full request URLs where they are available.\n\nSwitching privacy modes changes future collection behavior and URL visibility; it does not erase saved aggregate intelligence unless a reset action is used.\n\nAggregated mode is the default. Chroma stores domains by default, not full URLs. Full request URLs are only kept when Debug mode is enabled, and the bounded debug request log remains separate from `statsV2`.\n\n### Retention, Reset, and Export\n\nThe stats dashboard enforces hard caps on recent events, sites, rule entries, resource types, and daily history. Settings controls let you reset all stats, reset site stats only, reset the debug request log, or export a local JSON snapshot. Resetting stats does not erase configuration, subscriptions, proxy settings, whitelists, local zapper rules, or filter lists.\n\nThe **Time Saved (est.)** card is deliberately conservative. It uses a tiny sub-second estimate per protection event and floors the displayed value, so ordinary page-load activity does not inflate into unrealistic minutes.\n\n---\n\n## Third-Party Credits\n\nChroma utilizes logic and patterns derived from the following open-source projects:\n\n- **Brave Browser** — The YouTube ad-stripping logic (payload metadata pruning) is derived from Brave's ad-blocking scriptlets ([MPL 2.0](https://mozilla.org/MPL/2.0/)).\n- **Hagezi Pro Mini** by [hagezi](https://github.com/hagezi/dns-blocklists) — [MIT License](https://github.com/hagezi/dns-blocklists/blob/main/LICENSE)\n- **OISD Big** by [oisd](https://oisd.nl) — [License](https://github.com/sjhgvr/oisd/blob/main/LICENSE)\n\n## Filter List Subscriptions\n\nChroma subscribes to the following lists to ensure real-time protection:\n\n- **Chroma Hotfix** — Maintainer-controlled list for platform-specific overrides.\n- **Chroma Scriptlet Library** — Bundled Chroma-maintained scriptlet rules for targeted anti-adblock, recipe/blog, and platform compatibility fixes.\n- **Hagezi Pro Mini** — High-performance DNS and ad-blocking rules.\n- **EasyList** — The primary filter for cosmetic ad-blocking and element hiding.\n- **Fanboy Annoyance** — Blocks social widgets, popups, and other non-ad annoyances through cosmetic rules and supported scriptlets.\n\nThe **Chroma Hotfix** list is intentionally quiet when it has no active rules. It may be enabled internally, but the Filter Lists UI and Health panel hide it from user-facing subscription totals until a maintainer-published hotfix actually contains rules. This keeps normal installs from showing a confusing extra enabled list when there is nothing for users to manage.\n\n\u003e [!NOTE]\n\u003e To maximize performance and respect Manifest V3 rule limits, **EasyList** and **Fanboy Annoyance** are not allocated to network-level DNR blocking. Their cosmetic rules, and any supported scriptlets parsed from enabled lists, feed the cosmetic and scriptlet layers instead. Network-level blocking is handled by the high-efficiency static ruleset and Hagezi Pro Mini.\n\n### Custom Filter List Subscriptions\n\nChroma also supports user-added filter list subscriptions. You can host your own list in a GitHub repository, GitHub Gist, or any HTTPS endpoint that serves raw filter-list text, then paste the raw `https://` URL into Chroma's subscription manager.\n\nCustom subscriptions can include supported Adblock/uBO-style network rules, cosmetic rules, cosmetic exceptions, and scriptlet rules. During refresh, Chroma parses the list into network, cosmetic, and scriptlet buckets, drops unsupported or malformed rules, deduplicates network rules already covered by the bundled static ruleset, and only keeps scriptlets that map to Chroma's shipped scriptlet library.\n\n#### Why Custom Lists Still Work in MV3\n\nManifest V3 does not allow extensions to intercept and decide every request in JavaScript the way MV2 blockers often did. Chroma's subscription design works around that by doing the expensive work at refresh time instead of request time. It fetches and parses the list locally, converts supported network rules into DNR dynamic rules, and lets Chrome's browser engine enforce those rules without waking the extension for every request.\n\nRules that do not belong in DNR are handled by the layers that fit them: cosmetic selectors go to the cosmetic filtering layer, supported scriptlets go to the `userScripts` engine, and unsupported syntax is dropped instead of being guessed at. This is why custom lists can still be useful in MV3 while staying inside Chrome's rule budgets and execution model.\n\nNetwork rules are allocated by Chroma's internal priority score before being applied to DNR. Exception/allow rules are preserved first, `$important` block rules receive a higher score, domain/resource-type-specific rules are favored next, and earlier list position acts as a final tiebreaker. This lets custom lists express urgency while still respecting Manifest V3 dynamic-rule budgets.\n\nCustom subscription URLs must use `https://`, must not include credentials, must use the default HTTPS port, and cannot point to local/private network hosts. New custom lists default to a 24-hour refresh interval unless a different valid interval is supplied by the UI or message API.\n\nExample custom list:\n\n```adblock\n! Higher-priority network block. `$important` receives a stronger Chroma allocation score.\n||example-ad-server.com^$script,third-party,important\n\n! Cosmetic rule: hide sponsored cards on one site.\nexample.com##.sponsored-card\n\n! Cosmetic exception: preserve a subset if the broad cosmetic rule is too aggressive.\nexample.com#@#.sponsored-card.keep-visible\n\n! Scriptlet rule: run a supported Chroma/uBO-style scriptlet on a site.\nexample.com##+js(set-constant, adsEnabled, false)\n```\n\n---\n\n## Why I Made This\n\nMost Chrome ad blockers break often because the ground underneath them changed. Manifest V3 is not a temporary detour; for Chrome and most Chromium-based browsers, it is the platform reality now.\n\nChromium has other browser vendors, but Google still drives the upstream platform that Chrome and most Chromium-based browsers inherit. Brave, Edge, Vivaldi, and others can patch or work around parts of that stack, but they do not make MV2-style Chrome extension blocking the durable default for Chrome users.\n\nChroma exists because I wanted a blocker designed for that reality instead of fighting yesterday's API forever. It leans into MV3-native tools like Declarative Net Request, `userScripts`, local rule subscriptions, targeted scriptlets, and platform-specific handlers. The goal is not to be the biggest blocker or the loudest blocker. The goal is to be more robust when sites change, more transparent about what it does, and easier to hotfix without waiting on a store review.\n\nChroma is my answer to a simple problem: if Chrome ad blocking is going to live inside MV3, then the blocker should be built like it knows that.\n\n---\n\n## Recommended Companion Extensions\n\nChroma already includes network blocking, cosmetic filtering, scriptlets, proxy routing, and platform-specific handling, so I do not recommend stacking it with another ad blocker by default. Layering multiple content blockers can cause overlapping rules, false positives, and broken pages.\n\nExtensions that do something different from ad blocking can still pair well with Chroma. A favorite example is:\n\n- **[SponsorBlock](https://chromewebstore.google.com/detail/sponsorblock-for-youtube-s/mnjggcdmjocbbbhaepdhchncahnbgone)** — Skip sponsor segments and other interruptions on YouTube.\n\n## Recommended Alternatives\n\nChroma is built for users who want a transparent, source-auditable, Chrome/Chromium-focused MV3 extension with integrated proxy routing, YouTube ad stripping, custom subscriptions, and no store-mediated update delay. If that fits your workflow, Chroma is the right tool.\n\nIf you prefer a store-installed extension, a Firefox-first setup, or a dedicated proxy manager, these are the alternatives I trust most:\n\n- **Chrome / Chromium:** [uBlock Origin Lite](https://chromewebstore.google.com/detail/ublock-origin-lite/ddkjiahejlhfcafbddmgiahcphecmpfh?hl=en) + [FoxyProxy](https://chromewebstore.google.com/detail/foxyproxy/gcknhkkoolaabfmlnjonogaaifnjlfnp?hl=en) — Recommended for users who want the Chrome Web Store path. uBlock Origin Lite comes from the uBlock Origin project and is a more reputable choice than most generic store ad blockers. FoxyProxy adds focused proxy management without bundling unrelated ad-blocking behavior.\n- **Firefox:** [uBlock Origin](https://addons.mozilla.org/firefox/addon/ublock-origin/) + [FoxyProxy](https://getfoxyproxy.org/) — Recommended for users who want the strongest traditional content-blocking setup. Full uBlock Origin has more browser API power on Firefox than MV3 Chrome blockers, and FoxyProxy is a mature, dedicated proxy-routing tool.\n\n---\n\n## Why Not the Chrome Web Store?\n\nAd-blocking in the modern web is a high-stakes \"cat-and-mouse\" game where trust is the most valuable currency. Chroma is deliberately **not** hosted on the Chrome Web Store, and it never will be. This is a strategic decision rooted in transparency and technical freedom:\n\n### 1. Conflict of Interest\nGoogle is an advertising company first. As the gatekeeper of the Chrome Web Store, they have an inherent conflict of interest regarding tools that neutralize their primary revenue stream. By remaining independent, Chroma is not subject to arbitrary policy changes, forced feature deprecations, or the risk of sudden removal that \"authorized\" blockers frequently face.\n\n### 2. Full Auditability (Zero Obfuscation)\nWeb Store extensions often arrive as \"black boxes\" with bundled or obfuscated code. Chroma is distributed as raw, human-readable source code. By loading it as an unpacked extension, you (and the community) can audit every single line of JavaScript. There are no hidden analytics, no telemetry backdoors, and no \"Acceptable Ads\" programs that allow paid bypasses.\n\n### 3. Unrestricted API Power\nChroma utilizes advanced MV3 APIs such as the `userScripts` engine and high-volume `declarativeNetRequest` rule-sets. Bypassing the store keeps those capabilities transparent and source-auditable without waiting on store review cycles.\n\n### 4. Zero-Day Hotfixes\nWhen YouTube or other platforms update their ad-delivery algorithms, Chroma can ship a hotfix through GitHub quickly. Web Store reviews can take days or even weeks. In the world of ad-blocking, a three-day delay is an eternity. Staying off the store helps keep the engine responsive to platform changes.\n\n\u003e [!IMPORTANT]\n\u003e Sideloading an extension requires a higher level of trust. Review the [Permissions](#permissions) and [Security Hardening](#security-hardening) sections to understand exactly how Chroma protects your session.\n\n---\n\n## AI Usage \u0026 Quality Assurance Disclosure\n\nPortions of this codebase, including initial logic structures and documentation, were developed with the assistance of agentic AI coding assistants. To ensure project integrity, every AI-assisted component has been manually audited, refactored, and verified to meet strict security and performance standards. This collaborative approach combines the efficiency of advanced tooling with focused oversight and robust test coverage.\n\n---\n\n## Legal Disclaimers\n\n**Trademark Disclaimer:** YouTube, Google, and Chrome are trademarks of Google LLC. Amazon and Amazon Prime Video are trademarks of Amazon.com, Inc. Twitch is a trademark of Twitch Interactive, Inc. Netflix is a trademark of Netflix, Inc. Spotify is a trademark of Spotify AB. Disney+ is a trademark of Disney Enterprises, Inc. Hulu is a trademark of Hulu, LLC. Max and HBO are trademarks of Home Box Office, Inc. NordVPN is a trademark of Nord Security. ExpressVPN and Private Internet Access (PIA) are trademarks of their respective owners. Brave is a trademark of Brave Software, Inc. All other trademarks, service marks, and company names mentioned are the property of their respective owners. Chroma Ad-Blocker is an independent project and is NOT affiliated with, endorsed by, or sponsored by any of these entities or their respective platforms.\n\n**Usage Warning:** Using ad-blockers or ad-acceleration tools may violate the Terms of Service of various platforms. By using Chroma, you acknowledge and assume all risks associated with potential account restrictions or enforcement actions.\n\n---\n\n## Security Policy\n\nFor information on how to report security vulnerabilities, please see the [Security Policy](docs/SECURITY.md).\n\n---\n\n## Support the Project\n\nChroma is a solo project dedicated to restoring the web to its fast, private, and uninterrupted roots. It is 100% free for everyone, forever. If this tool has made your daily browsing a little more colorful, consider supporting this mission.\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://buymeacoffee.com/dabrogost\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Buy_Me_a_Coffee-FFDD00?style=for-the-badge\u0026logo=buy-me-a-coffee\u0026logoColor=black\" alt=\"Buy Me a Coffee\"\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\u003cp align=\"right\"\u003e\n  \u003csub\u003eCopyright 2026 Dabrogost • GPL-3.0-or-later\u003c/sub\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdabrogost%2Fchroma-ad-blocker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdabrogost%2Fchroma-ad-blocker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdabrogost%2Fchroma-ad-blocker/lists"}