A Chrome extension that converts YouTube videos to high-quality MP3 files using a fully local Flask server powered by yt-dlp and ffmpeg. No third-party APIs, no cloud services, no rate limits — everything runs on your own machine.
-
Three ways to convert:
- Paste any YouTube URL into the extension popup
- Right-click a YouTube video link/thumbnail → Download as MP3
- Click the injected Download MP3 button below any playing video
-
Live job tracking panel — see all conversions in real time with status badges (
converting,queued,done,error,cancelled) -
Conversion queue — multiple requests are processed one at a time to avoid YouTube rate-limiting; queued jobs show a "Waiting in queue..." status and can be cancelled before they start
-
Stop individual jobs mid-conversion (works on both
convertingandqueuedjobs) -
Save individual MP3s via native Windows Save As dialog
-
Save All as ZIP — bundle all completed conversions into a single
.zipand choose where to save -
Clear List — remove finished jobs and clean up temp files instantly
-
Auto-start server — clicking Convert auto-launches the backend in a visible terminal window via Chrome Native Messaging (no manual start needed after one-time setup)
-
Auto-shutdown — server shuts itself down after 3 minutes of inactivity (active conversions keep it alive)
-
Kill button — stop the server from inside the extension popup at any time
-
Window mode — clicking "click here to download" on the in-page toast opens the extension in a properly scaled popup window with a close button
-
Server health indicator — green/red dot showing whether the backend is running
┌───────────────────────────────────────────────────────┐
│ Chrome Browser │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ content.js │ │ background.js│ │ popup.js │ │
│ │ (YouTube │◄──►│ (service │◄──►│ (popup │ │
│ │ page) │ │ worker) │ │ UI) │ │
│ └─────────────┘ └──────┬───────┘ └──────────┘ │
│ │ Native Messaging │
└────────────────────────────┼──────────────────────────┘
│
┌──────────▼─────────┐
│ native_host.py │
│ (launches server │
│ in new terminal) │
└─────────┬──────────┘
│
┌─────────▼──────────┐
│ server.py │
│ Flask :5000 │
│ │
│ yt-dlp + ffmpeg │
│ → MP3 @ 192kbps │
└────────────────────┘
| Requirement | Notes |
|---|---|
| Windows 10/11 | Native Messaging requires Windows registry |
| Chrome (or Chromium) | Manifest V3 |
| Anaconda / Miniconda | For environment management |
| Internet connection | For downloading from YouTube |
⚠️ FFmpeg is installed automatically inside the conda environment — no separate installation needed.
E:\EAG V3\audio_format_converter\
Open Anaconda Prompt and run:
conda create -n yt-mp3-api python=3.10 -y
conda activate yt-mp3-api
pip install flask yt-dlp flask-cors
conda install -c conda-forge ffmpeg -y- Open Chrome and navigate to
chrome://extensions - Enable Developer mode (toggle in the top-right)
- Click Load unpacked
- Select the
audio_format_converterfolder - Copy the Extension ID shown on the extension card (looks like
abcdefghijklmnopqrstuvwxyzabcdef)
Double-click install_native_host.bat and paste your extension ID when prompted.
This registers the host in the Windows registry under HKCU (no admin rights needed).
Close and reopen Chrome so it picks up the new native messaging registration.
After completing the one-time setup, just use the extension — it will automatically launch the server in a new terminal window when you request a conversion.
| Action | How |
|---|---|
| Start server | Double-click start_server.bat |
| Stop server | Double-click stop_server.bat, or click Kill in the popup |
| Server auto-stops | After 3 minutes of no activity |
┌─────────────────────────────────────┐
│ YouTube to MP3 │
│ Paste a YouTube link to download │
├─────────────────────────────────────┤
│ YOUTUBE URL │
│ [ https://youtube.com/watch?v=...] │
│ [Convert] │
│ │
│ CONVERSIONS ● Server running [Kill]
│ ┌───────────────────────────────┐ │
│ │ Song Title [DONE] [Save]│ │
│ │ Ready to save │ │
│ ├───────────────────────────────┤ │
│ │ Another Song [CONVERTING][Stop] │
│ │ 12s elapsed │ │
│ ├───────────────────────────────┤ │
│ │ Third Song [QUEUED] [Stop]│ │
│ │ Waiting in queue... │ │
│ └───────────────────────────────┘ │
│ [ Save All (2 .zip) ] [Clear List] │
├─────────────────────────────────────┤
│ Powered by yt-dlp · :5000 │
└─────────────────────────────────────┘
| Button | Action |
|---|---|
| Convert | Start a new conversion from the URL input |
| Save | Opens Windows Save As dialog for one MP3 |
| Stop | Cancels a converting or queued conversion |
| Save All (.zip) | Bundles all completed MP3s into a ZIP, opens Save As dialog |
| Clear List | Removes all finished jobs and deletes temp files |
| Kill | Shuts down the local server immediately |
audio_format_converter/
│
├── manifest.json # Chrome extension manifest (v3)
├── background.js # Service worker — message routing, server management
├── content.js # Injected into YouTube — button + toast notifications
├── content.css # Styles for injected button and toasts
├── popup.html # Extension popup UI
├── popup.js # Popup logic — jobs, bulk actions, health polling
│
├── server.py # Flask backend server (localhost:5000)
├── native_host.py # Chrome Native Messaging host
├── native_host.bat # Wrapper to invoke native_host.py
├── native_host_manifest.json # Native messaging manifest (generated by installer)
│
├── start_server.bat # Manually start the server
├── stop_server.bat # Manually kill the server
├── install_native_host.bat # One-time setup — registers native host in registry
│
├── icons/
│ ├── icon16.png
│ ├── icon48.png
│ └── icon128.png
│
└── downloads/ # Temp MP3 storage (auto-cleaned)
The Flask server exposes the following endpoints on http://localhost:5000:
| Endpoint | Method | Body / Params | Description |
|---|---|---|---|
/health |
GET | — | Server status, idle time, shutdown countdown |
/convert |
POST | {"url": "..."} |
Start a conversion; returns job_id |
/jobs |
GET | — | All active and recent jobs |
/cancel |
POST | {"job_id": "..."} |
Cancel a converting or queued conversion |
/download |
GET | ?token=... |
Download a completed MP3 |
/download-zip |
POST | {"tokens": [...]} |
Download multiple MP3s as a ZIP |
/clear-jobs |
POST | — | Remove all finished jobs and temp files |
/shutdown |
POST | — | Gracefully shut down the server |
User submits URL
│
▼
[queued] ───────────────────────────────► [cancelled]
"Waiting in queue..." (user stops)
│
Previous job finishes; lock acquired
│
▼
[converting] ──────────────────────────► [cancelled]
"Fetching..." (user stops)
│
yt-dlp downloads single video (noplaylist)
+ ffmpeg encodes to MP3 @ 192kbps
│
┌────┴────┐
▼ ▼
[done] [error]
│
│ Token valid for 5 minutes
│ File stays in downloads/
▼
User saves MP3 or ZIP
│
▼
Job cleared (manual or auto after 60s)
File deleted
When the server is running you'll see live output:
==================================================
YT-MP3 Local Server running on :5000
Auto-shutdown after 3 min of inactivity
Status updates every 30 seconds
==================================================
[CONVERT] Starting: https://www.youtube.com/watch?v=...
[CONVERT] Done: Never Gonna Give You Up
[STATUS] Uptime: 00h 02m 30s | Conversions: 3 | Errors: 0 | Active: 0 | Ready: 2
[IDLE] Shutting down in 20s (convert something to stay alive)
[AUTO-SHUTDOWN] No activity for 180s. Shutting down...
| Resource | Idle | During conversion |
|---|---|---|
| RAM | ~20–30 MB | ~50–100 MB |
| CPU | ~0% | Brief spike (ffmpeg encoding) |
| Disk | ~0 MB | ~3–8 MB per track (auto-cleaned) |
| Network | 0 | Same as watching the video |
Total install size: ~250 MB (conda environment with ffmpeg)
Cost: $0 — fully local, no API keys, no rate limits.
Run install_native_host.bat again and make sure the extension ID matches exactly. Restart Chrome after installing.
- Make sure the conda env
yt-mp3-apiexists with all dependencies - Check the server terminal for error details
- Try running
start_server.batmanually to see full output
The context menu only appears when right-clicking links (anchor elements) that point to YouTube watch/shorts URLs, not on every thumbnail image.
YouTube sometimes appends &list=...&start_radio=1 to a video URL when you click it from search results or autoplay. The extension strips this automatically — only the single video (v= param) is downloaded. If you're pasting a URL manually, make sure it points to a single video (watch?v=) rather than a playlist or channel page.
Completed files are only kept for 5 minutes. Start a new conversion if the token has expired.
Re-run install_native_host.bat — the registry entry may need refreshing.
- Remove from Chrome:
chrome://extensions→ Remove - Delete registry entry:
reg delete "HKCU\Software\Google\Chrome\NativeMessagingHosts\com.ytmp3.server" /f - Remove conda environment:
conda env remove -n yt-mp3-api
- Delete the project folder
| Component | Technology |
|---|---|
| Extension | Chrome Manifest V3, Vanilla JS |
| Backend | Python 3.10, Flask, Flask-CORS |
| Downloader | yt-dlp |
| Audio encoder | FFmpeg (via conda-forge) |
| Environment | Conda (yt-mp3-api) |
| Native bridge | Chrome Native Messaging |
MIT — free to use, modify, and distribute.