Silently skip Spotify ads on Windows — automatically, or with a single hotkey.
Tired of Spotify ads interrupting your flow?
This lightweight Windows utility runs in the background, intelligently detects when an advertisement is playing, and restarts Spotify to skip it — all without stealing focus or interrupting your workflow.
✨ Features • ⚡ Quick Start • 🔧 How It Works • 📖 Usage • 🏗️ Architecture • 🤝 Contributing
Watch the Spotify Ad Skipper in action — automatically detecting and skipping an ad.
| Feature | Description |
|---|---|
| 🎯 Automatic Ad Detection | Monitors Spotify's window title — when an ad plays, the title loses the "Song — Artist" dash pattern. The utility detects this and triggers a restart. The title "Spotify Free" is never treated as an ad (it also appears when music is paused). |
⌨️ Global Hotkey (Ctrl+Shift+R) |
Manually restart Spotify at any time with a system-wide hotkey — works even when the terminal is minimised. |
| 🪟 Minimal & Focus-Friendly | Spotify is relaunched minimised to the taskbar — no window stealing your focus, no disruption to your workflow. |
| 🔊 Auto-Resume Playback | After restarting, the utility sends a virtual media Play/Pause key press so your music resumes automatically. |
| 🛡️ Administrator Auto-Elevation | Automatically requests UAC elevation if needed (required for process termination when Spotify runs as admin). |
| 🧩 Modular & Extensible | Clean separation of concerns: process management, window detection, hotkey listening, and media key simulation are all independent modules. |
| 📝 Verbose Logging | Run with --verbose to see detailed logs of every detection, restart, and media key event. |
- Windows 10 or 11 (uses Win32 API — not cross-platform)
- Python 3.10+ (Download)
- Spotify (free or premium tier — ad detection works on both)
# 1. Clone the repository
git clone https://github.com/Tasmetime/spotify_ad_skipper.git
cd spotify_ad_skipper
# 2. Install dependencies
pip install -r requirements.txt
# 3. Run it!
python main.pyNote: The first time you run it, Windows may show a UAC prompt asking for administrator privileges. This is required to terminate Spotify's process reliably. Click "Yes" to proceed.
For convenience, double-click start.bat — it launches the utility with verbose logging enabled and pauses on error so you can see what went wrong.
python main.py # Run with default settings (hotkey + auto ad skip)
python main.py --no-auto-skip # Disable automatic ad skipping (manual hotkey only)
python main.py --verbose # Enable detailed debug logging
python main.py --help # Show full help text| Action | Result |
|---|---|
Press Ctrl+Shift+R |
Immediately restarts Spotify (if running) |
Press Ctrl+C in the terminal |
Gracefully shuts down the utility |
| Let it run in the background | Ads are detected and skipped automatically every ~2 seconds |
14:32:01 [INFO] spotify_restarter: ==================================================
14:32:01 [INFO] spotify_restarter: Spotify Restarter — running in background.
14:32:01 [INFO] spotify_restarter: Press Ctrl+Shift+R to restart Spotify.
14:32:01 [INFO] spotify_restarter: Press Ctrl+C in the terminal to exit.
14:32:01 [INFO] spotify_restarter: ==================================================
14:32:05 [INFO] spotify_restarter.ad_detector: Ad detected! Window title: 'spotifyad123'
14:32:05 [INFO] spotify_restarter.orchestrator: Spotify Restarter — starting cycle.
14:32:06 [INFO] spotify_restarter.launcher: Launched Spotify from: C:\Users\...\Spotify.exe
14:32:08 [INFO] spotify_restarter.media_keys: Sent media Play/Pause via keybd_event (VK 0xB3).
The core insight is how Spotify's window title changes during different states:
Normal song: "Bohemian Rhapsody — Queen" ✅ Contains a dash (—)
Paused / Free: "Spotify Free" ✅ Never an ad (exception)
Advertisement: "spotifyad123" ❌ No dash at all
The AdDetector uses these rules, evaluated in order:
- Spotify Free Exception — If the title is exactly
"Spotify Free", it is never considered an ad, regardless of any other condition. This title appears both when the free tier is active and when music is paused, so treating it as an ad would cause false-positive restarts. - Dash Check — If the window title does not contain a
-, the content is classified as an ad.
Important: The detector locates Spotify windows by process ID (not by title), so it can always find the window regardless of whether the title is a song name or an ad placeholder.
When an ad is detected (or the hotkey is pressed), the SpotifyRestarter orchestrates:
1. CLOSE → Send WM_CLOSE to Spotify windows
2. DISMISS → Send Enter key to dismiss any "Are you sure?" dialog
3. WAIT → Poll until Spotify process exits
4. FORCE → If still running, escalate to terminate/kill
5. LAUNCH → Start Spotify minimised (no focus steal)
6. MINIMISE→ Safety net: minimise any windows that opened normally
7. PLAY → Send virtual media Play/Pause key (VK_MEDIA_PLAY_PAUSE)
Some Spotify installations run with elevated privileges, meaning a non-admin Python process cannot terminate them. The utility automatically detects this and relaunches itself via UAC using ShellExecuteW with the runas verb.
The project is organised into a clean, modular package:
spotify_ad_skipper/
├── main.py # CLI entry point & argument parsing
├── pyproject.toml # Project metadata & dependencies
├── requirements.txt # Pinned dependencies
├── start.bat # Convenience launcher (double-click)
├── .gitignore
│
└── spotify_restarter/ # Core Python package
├── __init__.py # Public API exports
├── config.py # Config dataclass (paths, timeouts, thresholds)
├── process_manager.py # Process discovery & termination via psutil
├── window_manager.py # Win32 window enumeration & interaction
├── launcher.py # Spotify executable discovery & launch
├── media_keys.py # Virtual media key simulation (keybd_event)
├── ad_detector.py # Window title analysis & ad detection
├── hotkey.py # Global hotkey registration (Win32)
├── orchestrator.py # Full restart cycle orchestration
└── utils.py # Admin check, UAC escalation, dependency guard
| Module | Responsibility |
|---|---|
config.py |
Central Config dataclass — all tunable parameters in one place. |
process_manager.py |
Wraps psutil to find, inspect, and terminate Spotify processes with a polite → force escalation strategy. |
window_manager.py |
Uses EnumWindows / GetWindowText / GetWindowThreadProcessId to enumerate top-level windows and interact with them (close, minimise, send keys). |
launcher.py |
Searches known install paths for Spotify.exe, falls back to shell resolution, and launches with SW_SHOWMINNOACTIVE to avoid focus steal. |
media_keys.py |
Sends VK_MEDIA_PLAY_PAUSE (0xB3) via keybd_event — the most reliable method for triggering Spotify playback. |
ad_detector.py |
Implements the dash-check and exact-match heuristics on window titles. Runs in a daemon thread, polling every 2 seconds. |
hotkey.py |
Registers Ctrl+Shift+R as a global hotkey via RegisterHotKey. Creates a hidden Win32 window to receive messages, then runs the message pump. |
orchestrator.py |
SpotifyRestarter class that ties everything together — close → launch → play. |
utils.py |
is_admin(), relaunch_as_admin() (UAC via ShellExecuteW), and check_dependencies(). |
All tunable parameters live in the Config dataclass:
| Parameter | Default | Description |
|---|---|---|
spotify_process_names |
("Spotify.exe", "Spotify") |
Process names used by psutil to identify Spotify. |
spotify_window_titles |
("Spotify", "Spotify Premium", "Spotify Free") |
Window title substrings for matching Spotify windows. |
close_attempts |
3 |
How many times to try closing Spotify before force-killing. |
close_delay |
1.5 |
Seconds to wait after sending a close signal before checking again. |
launch_timeout |
15.0 |
Max seconds to wait for Spotify to appear after launching. |
launch_check_interval |
0.5 |
Poll interval when waiting for Spotify to start. |
ad_polling_interval |
2.0 |
Seconds between ad-detection checks. |
ad_skip_enabled |
True |
Whether to automatically skip ads when detected. |
launch_minimized |
True |
Launch Spotify minimised to avoid focus steal. |
media_key_delay |
2.0 |
Seconds to wait after launch before sending the play command. |
spotify_known_paths |
(see config) | Common Spotify install paths checked in order. |
| Package | Version | Purpose |
|---|---|---|
psutil |
≥ 6.0.0 | Cross-platform process discovery and termination. |
pywin32 |
≥ 310 | Windows API bindings — win32gui, win32api, win32con, etc. |
| Package | Purpose |
|---|---|
pycaw |
Audio control (experimental scripts) |
keyboard |
System-wide media key events |
pyautogui |
GUI automation |
Contributions are welcome! Here's how you can help:
- 🐛 Report Bugs — Open an issue with reproduction steps.
- 💡 Suggest Features — Open an issue with the
enhancementtag. - 🔀 Submit PRs — Fork the repo, create a feature branch, and open a pull request.
git clone https://github.com/Tasmetime/spotify_ad_skipper.git
cd spotify_ad_skipper
pip install -r requirements.txt
python main.py --verbose- Python 3.10+ type annotations (
from __future__ import annotations) - NumPy-style docstrings
- Clean separation of concerns — each module has a single responsibility
- Logging via
logging.getLogger(__name__)in every module
This project is licensed under the MIT License — see the LICENSE file for details.
Made with ❤️ for uninterrupted listening
