VideoAdGuard: an extension that finds embedded ads in Bilibili videos
哔哩哔哩浏览器插件:基于大语言模型,对B站视频中的植入广告进行检测。一键跳过视频中的植入/口播广告。
At a glance
- What is it?
- VideoAdGuard is a browser extension that sends a video's subtitles to a large language model, asks where the embedded advertising starts and stops, and draws a skip button and an editable timeline over the player. It works on Chrome, Edge and Firefox, keeps a 24 hour local cache, and can share results through a Cloudflare Worker.
- Who is it for?
- VideoAdGuard suits a viewer who watches Bilibili videos with sponsor segments and wants to skip them, and who is willing to configure an API key for the model that does the detection. It is the wrong tool if you do not want to send a video's transcript to a third party service, and the wrong choice if you expect the detection to be exact, because the decision is a model's judgement about where an advert starts.
- Can I use it commercially?
- Yes, with conditions. GPL-2.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the extension detects and how you use it
VideoAdGuard is a browser extension that detects embedded advertising inside Bilibili videos using a large language model, and offers a way to skip those segments.
The feature list describes the mechanism plainly. It analyses the video's subtitles with a large language model to locate the embedded advertising accurately, and it supports audio recognition for videos without subtitles, using the free Groq service. When an advert is detected, a skip button appears in the bottom right of the player and can be clicked, and automatic skipping of already detected segments is supported. Results are cached locally, which the README says greatly improves the speed on repeat visits, and a cloud cache lets the community share results and feedback.
The interaction model is the part that goes beyond detection. An interactive marking layer shows the advertising intervals on the video progress bar in red, and you can click a segment to toggle it active or paused, drag its edges to adjust where it starts and ends, or drag the middle to move the whole segment. A feedback button appears once detection finishes, and clicking it without adjusting anything marks the result as inaccurate so the next visit re-detects it, while adjusting the interval and then clicking submits your correction to the shared cloud cache for other users.
The README asks for a star if you find it useful, and there is a demo video on Bilibili itself.
The detection pipeline and the cache design
The technical explanation section describes the pipeline in numbered steps, and the ordering is the interesting part.
First the video's subtitles are obtained, or the audio recognition path is enabled if there are none. Then the video title and the pinned comment are extracted. Then the cache is queried, with the local cache checked first with a 24 hour lifetime, and the cloud cache queried in parallel. If the cloud cache hits, that result is used directly; otherwise the data is sent to the large language model for analysis. The analysis determines the advertising time segments, the result is cached to both the local and the cloud store, and the skip button and the interactive marking layer are shown.
The cloud cache design has a few rules that are worth understanding. Only one record is kept per video, keyed as an ad record with the video identifier, and only records marked as accurate can be queried and used. When a user marks a result as inaccurate, that record is skipped on lookup and the next visit re-runs the detection. When a user submits a correction, the record is stored with a user source flag so that others can use it.
The last rule is the one that matters for trust. If the cloud service fails, the extension degrades silently and local detection still works, so a broken backend does not take the feature down with it.
Choosing a model provider, and the local option
The extension cannot work without a large language model, and the README is direct about the relationship between model quality and detection quality. The detection capability is closely related to the capability of the model, and a stronger model is recommended.
Three access styles are offered, and the choice determines which services you can point it at.
The OpenAI compatible style covers OpenAI itself and a long list of services that speak the same protocol, including Zhipu, MiniMax, Kimi, DeepSeek, SiliconFlow, OpenRouter, Gemini, Grok, Tencent Hunyuan, Alibaba's Bailian, Volcano Ark, StepFun, Baidu Qianfan, 302.AI and Requesty. The Anthropic compatible style covers Claude and a shorter list including Zhipu, MiniMax, Tencent Cloud, Alibaba Cloud, Volcano Engine and Baidu Qianfan. The custom Fetch style covers local models, with Ollama, LM Studio, vLLM, llama.cpp, LocalAI, Xinference, FastChat, Jan and One API named.
The settings page offers presets for these platforms so the configuration is one click rather than a manual endpoint entry.
There is a note specific to the local case: if you hit cross-origin problems with a local model, you need to set an environment variable on the model server, and the example given is the wildcard origin setting for Ollama.
The audio recognition path is a separate, optional API. It is only for videos without subtitles, it currently supports Groq's free Whisper models, and you get a key from the Groq console.
The extension architecture in the source tree
The directory structure in the README describes a project with a background script, a content script, a separate Worker and per-browser builds.
The source directory has background.ts as the background script acting as a cross-origin proxy, content.ts as the content script holding the detection logic, popup.ts and popup.html for the settings interface, and a services/ directory with the business logic. Inside services there is ai.ts for the detection prompt and the parsing of the response, bilibili.ts as the API client, cache.ts for the local cache with a 24 hour TTL, cloud-cache.ts for the Cloudflare KV backed cloud cache, whitelist.ts for the creator whitelist, audio.ts for the browser adapted audio recognition, and an llm/ subdirectory with config.ts for provider parsing, providers.ts covering the OpenAI, Anthropic and custom Fetch backends, and types.ts for the type definitions.
There is also a utils/ directory with the Bilibili WBI signing, error normalisation and a logger, and a types/ directory for the TypeScript definitions including the cloud cache types.
The Worker directory holds the Cloudflare Worker that acts as the cloud cache gateway, with its entry point and API routes, a wrangler.toml configuration, its own package.json and a deployment README. The manifests directory has separate manifest files for Chrome and Firefox, the locales directory holds the i18n resources, and there is a build script for each browser plus a webpack configuration and a TypeScript configuration.
The package.json confirms the stack. The runtime dependencies are the Anthropic SDK, the OpenAI SDK and md5, and the dev dependencies are webpack with ts-loader, vitest for the tests, wrangler for the Worker, and rimraf for cleaning.
Two distributions, and one of them is unmaintained
The extension is distributed in two forms, and the README is unusually clear about the status of one of them.
The browser extension version is the recommended one, with download links for Microsoft Edge, Google Chrome and Firefox, each pointing at the corresponding add-on listing.
The userscript version runs through Tampermonkey and is installed from GreasyFork. The README notes that because of feature limitations the userscript version is not maintained going forward, and that for Chromium based browsers the extension version is recommended.
That is worth pausing on, because a userscript and a browser extension have genuinely different capabilities. A userscript runs in the page context with whatever the page's permissions allow, while an extension with a background service worker can make its own cross-origin requests through a proxy, which is what the background.ts script is for. The detection flow needs to reach the model API from a page on another origin, and the extension has a background script to do that. A userscript cannot do it as cleanly, and the features that depend on it are the ones that were dropped.
The repository still contains the userscript, VideoAdGuard.Tampermonkey.js, with a comment marking it as no longer maintained, and the build outputs are separated per browser into chrome and firefox directories, which is what the manifest differences require.
The release history shows the feature work clearly, with a cloud cache and community sharing added in 1.4.0, a refactored LLM module with support for more models including coding plans in 1.3.0, a Groq proxy service in 1.2.8, Firefox support in 1.2.7, and local Ollama model support in 1.1.3.
Where VideoAdGuard is the wrong choice
The first limitation is the privacy trade, and it is a direct one. The subtitle text of every video you watch is sent to a third party model provider, and if you use the audio path, the audio is transcribed by a hosted service too. The local model option exists, and the README is clear that it is the privacy-respecting route, but it requires a machine that can run a model.
The second is that the detection is a model's opinion. A language model is asked where an advert starts and stops, and the result is a judgement with a plausible but wrong answer when the model is not sure. That is why the interactive marking layer and the feedback button exist, and it means the tool is a prompt for your own correction rather than an oracle. The README does not publish any accuracy figures, so there is no baseline to compare against.
The third is the cost. The README's notes include a reminder that a paid API means you should watch token consumption and the audio recognition cost, and the cache only lasts 24 hours. A heavy viewer of captioned videos who is on a paid model API is paying per uncached video.
The fourth is the detection scope. Subtitles are the primary input, and the README says subtitle detection is preferred because it is more accurate, with audio recognition only as the fallback for videos without subtitles. A video with burned-in text and no subtitle track is a case neither path handles well.
The fifth is the shared cache. A community cache means a result computed for one video is served to everyone, and if a detection is wrong and gets marked inaccurate, the record is skipped and recomputed. That is a reasonable design, but it also means the community's corrections become part of what other people see, which is a governance question the README does not go into.
How VideoAdGuard compares with a local ad filter and with the platform's own controls
The comparison with a local ad filter, such as a hosts file or a DNS blocker that filters by domain, is the one that best frames the value. A domain filter is fast, free, private and completely reliable for the adverts it can match, because the advert is identified by where it was served from. The problem it cannot solve is the embedded advert inside a video, which is not a separate request and has no domain to match.
That is the gap VideoAdGuard fills, and it fills it with a language model reading the words that were said. So the comparison is between a filter that is exact about the adverts it can see and one that is approximate about the adverts it can read. For a video that carries a sponsor segment, a domain filter sees nothing and this extension sees the segment.
The second comparison is with the platform's own controls. Bilibili has a member-only ad-free tier, which removes the advertising it serves itself, and it has settings for some promoted content. Those controls are authoritative for the platform's own adverts and free, and they do not cover the embedded placements that creators sell individually, which is exactly what this extension is aimed at.
The third is with a manual approach, and it is not trivial. Watching and noting the timestamps by hand, or using the browser's own controls, works and requires no key, no model and no upload of a transcript. The extension's argument is convenience, repeated across many videos.
The fourth comparison is with a general purpose script that summarises a video transcript, which would use the same APIs and the same model but would need the user to write the prompt and the interval extraction. The contribution here is the domain specific prompt, the interval parsing, the timeline overlay and the correction workflow.
Licence, project state and what to set up before you use it
The licence field on the repository says GPL-2.0, and the package.json declares GPL-2.0-or-later, so the project is copyleft with the or-later option. That is a deliberate choice for a browser extension that people install, and it means a modified build has to be published in source form.
The project is not archived and the last push was on 2026-10-20, so it is being worked on daily. The recent releases are v1.4.2 from 2026-08-30, v1.4.1 from 2026-05-09 and v1.4.0 from 2026-05-01, and the version in the package.json is 1.4.2. The homepage is a separate site, and the repository carries an English README alongside the Chinese one, plus a docs/ directory and a test/ directory with a vitest configuration.
Four things to set up before the first video.
An API key and a model. The extension cannot detect anything without one, and the README ties detection quality to model quality, so the choice of provider and model is the decision that determines whether it works well.
Which access style to use. The OpenAI compatible and Anthropic compatible paths are the same protocol as the major providers and need a key. The custom Fetch path is for a local model, and it needs the origin setting on the model server to avoid cross-origin failures.
Whether to enable the audio path, which is a separate key and a separate cost, and which is only used for videos with no subtitles.
And the creator whitelist, which is the escape hatch for a creator whose own videos get flagged. It is worth setting before you watch a video from a creator you follow, because a false positive on their video is the most likely complaint about this kind of tool.
Editorial conclusion
VideoAdGuard suits a viewer who watches Bilibili videos with sponsor segments and wants to skip them, and who is willing to configure an API key for the model that does the detection. It is the wrong tool if you do not want to send a video's transcript to a third party service, and the wrong choice if you expect the detection to be exact, because the decision is a model's judgement about where an advert starts. Before you install it, set the timezone question aside and read the cost note, because a paid API means every uncached video is a bill, and remember the users whitelist, which is the escape hatch for creators whose videos are wrongly flagged.
Frequently asked questions
What does the VideoAdGuard extension do?
It sends a Bilibili video's subtitles to a large language model, asks where the embedded advertising segments are, and shows a skip button plus an interactive marker layer over the video timeline that you can drag to correct. Videos with no subtitles are handled through an optional audio recognition path using Groq's Whisper models.
Which browsers and distributions does VideoAdGuard support?
There is a browser extension for Microsoft Edge, Google Chrome and Firefox, plus a Tampermonkey userscript. The README states that the userscript version is not maintained going forward because of feature limitations, and recommends the extension for Chromium based browsers.
Which AI providers can VideoAdGuard use?
Three access styles. The OpenAI compatible one covers OpenAI and a long list of services speaking the same protocol, the Anthropic compatible one covers Claude and several others, and a custom Fetch mode covers local runtimes such as Ollama, LM Studio and vLLM. The settings page provides presets for the listed platforms.
How does the VideoAdGuard cache work?
Results are cached locally for 24 hours, and optionally shared through a Cloudflare Worker backed cache that keeps one record per video. Only records marked accurate are served, a result a user marks as inaccurate is skipped so the next visit re-detects, and a user correction is stored as a user sourced record for others. If the cloud service fails the extension degrades silently and local detection still works.
What licence does VideoAdGuard use?
GPL-2.0-or-later, with the terms in the LICENSE file at the root of the repository, and the package.json declares the same licence.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/zerotang05-videoadguard)Was this useful?