A Chrome / Edge extension (Manifest V3) that removes server-side stitched ads (SSAI) from Twitch streams.
Расширение для Chrome и Edge (Manifest V3), убирающее серверную рекламу (SSAI) из стримов Twitch без отдельного плеера и потери качества. Полное русскоязычное описание доступно в README.ru.md.
Twitch stitches ads right into the HLS playlist served from the same CDN as the stream, so classic domain blocking does nothing. This extension rewrites the playlist before the player ever sees it — no separate player, no quality loss, no video re-encoding.
- Three independent blocking layers — a clean master playlist, ad-segment stripping, and a DVR-tail fallback.
- Live counter of blocked ad breaks in the popup.
- On/off toggle that takes effect immediately, no page reload.
- English and Russian UI, picked automatically from the browser language.
- No telemetry, no external servers. Diagnostics stay in
chrome.storage.local.
Twitch does not fetch .m3u8 from the page — the request is made inside a blob Web Worker owned by the player. Page-level fetch/XHR hooks see nothing.
The extension does three things:
- Patches
window.Worker(MAIN world,document_start) and rebuilds the worker source with a small patch prepended. The patch is recursive: if the loader creates a nested worker, that one gets patched too. - Intercepts
fetchinside the worker:- Layer 1 (primary). A request for the master playlist
usher.ttvnw.net/api/v2/channel/hls/<channel>.m3u8is replaced with the same request carrying an access token issued by GQL forplayerType=embed. For non-primary players Twitch serves the stream without ads at all — nothing to strip, no A/V desync. - Layer 2 (fallback). If ad markers still show up (
CLASS="twitch-stitched-ad",CLASS="twitch-ad-quartile"), ad segments are cut out of the playlist body:#EXTINF:2.002,Amazon|...entries with their URIs, ad#EXT-X-DATERANGE, ad#EXT-X-MAP/#EXT-X-DISCONTINUITY, and#EXT-X-TWITCH-PREFETCH. Black-screen guard: if stripping leaves zerolivesegments (a pure preroll), the original playlist is returned — an ad is better than a dead player. - Layer 3 (if layer 1 fails). Twitch records the stream to a DVR playlist on the CDN, and that one has no ads (SSAI is only stitched at the live edge). The extension finds
https://{server}.cloudfront.net/{sha1(base)[:20]}_{base}/{quality}/index-dvr.m3u8(base = {login}_{streamId}_{startUnix}), takes the last 12 segments (2 minutes) and serves them as a live playlist: absoluteMEDIA-SEQUENCE,TWITCH-LIVE-SEQUENCE,ELAPSED/TOTAL-SECS,EXTINF:...,live. The tail is rebuilt on every player request, so the window slides with the live edge. Verified: 120 s of continuous 720p60 video without ads.
- Layer 1 (primary). A request for the master playlist
- Diagnostics are exposed on
window.__adstripin the page console.
- Open
chrome://extensionsand enable Developer mode. - Click Load unpacked and select the folder that contains
manifest.json. - Open Twitch and reload the page.
Works in Chrome, Edge and other Chromium-based browsers. Firefox is not supported (MV3
world: "MAIN"and the worker patch are Chromium-specific).
- Big number — total ad breaks blocked.
- LIVE / OFF — current state.
- this tab: N — blocked in the current tab.
- Turn on / Turn off — toggles blocking instantly.
- download log · v5 — exports diagnostics as JSON (hover shows
checks / ad segments).
The UI language follows the browser (_locales/en, _locales/ru).
cleanMasters: 1 alone proves nothing — maybe there was no ad to begin with. So at the moment of interception the extension also requests the normal (playerType=site) stream from Twitch and counts ad segments in it. That stream is never handed to the player; it is a measurement only.
The result is stored in window.__adstrip.checks and printed to the console:
[Twitch adblock] PROBE somechannel: normal (site) stream has ad segments=6
(variants checked: 2) -> AD WAS SERVED, player never got it
or
[Twitch adblock] PROBE somechannel: normal (site) stream has ad segments=0
(variants checked: 2) -> no ad at this moment
| Field | Meaning |
|---|---|
checks[].adSegs |
how many ad segments Twitch was ready to serve right now |
checks[].liveSegs |
how many regular segments the same playlist had |
checks[].stitched |
whether CLASS="twitch-stitched-ad" was present |
checks[].checked |
how many quality variants were checked |
Full log (every interception and error):
window.__adstripDump()Limitation: this is one probe per channel per session, taken when the player starts. A later midroll will not appear in checks — but layer 2 will still catch it (strippedSegs).
playerType=embedis undocumented Twitch behaviour and can be closed at any moment.- On a pure preroll (ads only, zero live segments) layer 2 deliberately returns the original playlist, so the ad is shown — better than a black screen.
- Layer 3 lags ~1.5–2 minutes behind live and serves a single quality (720p60 when available). That is the price of the fallback.
- The DVR playlist does not exist for every channel (depends on stream settings), so layer 3 is a fallback, not the main path.
- Token requests add ~200–400 ms to playback start.
- The extension is loaded unpacked (no store release yet).
The extension itself has no build step and no dependencies.
git clone https://github.com/Davidson235/twitch-adblock.git
cd twitch-adblockLoad the folder as an unpacked extension. After editing content.js or manifest.json, hit reload on the extension card in chrome://extensions.
Build a store-ready zip:
powershell -File scripts/build.ps1
# -> dist/twitch-adblock-<version>.zipPushing a v* tag triggers .github/workflows/release.yml, which builds the zip and attaches it to the GitHub release.
If this extension has helped you enjoy ad-free Twitch streams and you'd like to support the ongoing development and maintenance, crypto donations are gratefully accepted:
| Network / Ecosystem | Wallet Address | Supported Blockchains & Assets |
|---|---|---|
| EVM (MetaMask) | 0xa9fB203Ce2AA939642a3D53A1dBcb182F21Dd697 |
Ethereum (ETH, ERC-20), BNB Smart Chain (BNB, BEP-20), Polygon (POL), Arbitrum One, Optimism (OP), Base, Avalanche C-Chain (AVAX) |
| Solana | B3c4xrSL4iVAi6t6GadUPJ56iy5586JDansdvur5KpKk |
Solana (SOL) and all SPL tokens (USDC, USDT, etc.) |
- No analytics, no remote config, no third-party requests.
- The only network traffic is the one Twitch itself makes, plus the
playerType=siteprobe used to verify that an ad was really there. - Settings and counters live in
chrome.storage.localand never leave the machine.
- Not Affiliated with Twitch: This project is an independent open-source tool and is not affiliated with, endorsed, sponsored, or supported by Twitch Interactive, Inc. or Amazon.com, Inc. "Twitch" and all related marks and logos are registered trademarks of their respective owners.
- Educational & Research Purpose: This software was created solely for educational and research purposes to demonstrate Web Worker interception, HLS playlist manipulation, and client-side stream processing.
- Terms of Service: Using this extension may conflict with third-party Terms of Service. You use this software at your own risk. The author assumes no responsibility or liability for any actions, account bans, or disruptions resulting from its use.
- No Warranty: The software is provided "as is", without warranty of any kind, under the terms of the MIT License.
