A browser extension that declutters YouTube — hide Shorts, ads, and sidebar items, simplify the player and feed, and add handy controls like a playback speed slider, all toggled from a side panel.
Install from the Chrome Web Store
Manifest V3 · React 19 · TypeScript · Tailwind CSS
- Hide Shorts sections, mixes, and playlists across the feed
- Remove sponsored videos and promotional banners
- Clean up the search bar, masthead, and player controls
- Playback speed slider for videos and a dedicated one for Shorts
- Auto-advance to the next Short
- Trim the sidebar (You, Explore, More from YouTube, …) item by item
- Channel page cleanup (banner, trailer)
Every feature is opt-in and persists in chrome.storage.local. A master
toggle enables or disables the whole extension at once.
Requires Node.js (>= 20.19), which includes npm.
npm install
npm run dev # watch build into ./distThen load the unpacked extension:
- Open
chrome://extensions - Enable Developer mode
- Load unpacked → select the
distfolder
npm run build # one-off chrome build into ./dist
npm run build:chrome # bumps version, outputs release/build-chrome-<version>.zip
npm run build:opera # Opera-specific manifestnpm run lint
npm run typecheck
npm test
npm run formatCopy .env.example to .env and set VITE_POSTHOG_PROJECT_TOKEN to your
PostHog public project token. Set VITE_POSTHOG_HOST to the HTTPS ingestion
host for that project (defaults to https://eu.i.posthog.com). Rebuild after
changing either value. These Vite-compatible names match ai-usage-extension;
this project's webpack build loads them using dotenv. Environment variables
override .env; .env.example is never loaded as runtime configuration.
For GitHub Actions, add repository secrets under Settings → Secrets and
variables → Actions: VITE_POSTHOG_PROJECT_TOKEN (required for releases) and
VITE_POSTHOG_HOST (optional; the EU ingestion host is the default). CI and
release workflows pass these directly to the build environment. Release checks
for an empty token before building Chrome and Opera archives. CI can still
build without feedback configuration, including pull requests from forks.
The feedback button beside “View on GitHub” opens a problem / feature request
form. The background worker sends problem_reported or feature_requested
through the PostHog Capture API, only
when the user presses Send. Find reports in PostHog Events and inspect the
message, feedback_type, app_version and app: youtube-clean properties.
Successful submission requires an acknowledged HTTP response; errors preserve
the draft in the open panel and offer a GitHub issue link. Drafts are not
persisted after the panel closes. No token means sending is unavailable, with
the same GitHub fallback. Requests use ordinary CORS with credentials omitted;
PostHog Cloud allows the extension origin, POST and the Content-Type header.
No PostHog host permission is added to the Chrome or Opera manifest. A custom
ingestion host must also allow these CORS requests and expose its response.
No analytics SDK, automatic events, session recordings, browsing history, account details or settings are collected. Each report has a new random ID; person profiles and GeoIP enrichment are disabled. The message, its type and the extension version are sent with basic event metadata. PostHog receives the network request (including the sender's IP address at the transport layer). Users should not include sensitive information in their message. Store descriptions disclose this optional feedback; keep any published privacy policy and store data-use disclosures consistent when releasing this feature.
Everything is driven by a declarative feature config — you describe what a feature does, and the build/runtime turn that into UI, CSS, and DOM behavior.
The three entry points (webpack.config.js):
| Entry | Source | Role |
|---|---|---|
content |
src/content/ |
Applies features on the page |
sidebar |
src/sidebar/ |
Settings UI (Chrome side panel) |
worker |
src/worker/index.ts |
Opens the side panel on toolbar click |
Settings are a single source of truth: the Storage
singleton mirrors chrome.storage.local in memory and feeds both the imperative
DOM layer and the React UI (via StorageProvider).
CSS-only features (hide / styles) cost nothing at runtime — they are
compiled into content.css and switched on by a per-feature body attribute.
Only behavioral features (custom, component) run JavaScript.
A typical "hide element X" feature is a small diff: one declarative config entry and one translation key per locale. Storage, defaults, CSS, and sidebar UI are generated.
- Adding a feature - step-by-step implementation
- Selector guide - how to pick stable YouTube selectors
- Feature catalog - current features and config areas
- Contributing - PR workflow and required checks
MIT © lenadweb