Convert any track or whole playlist between Spotify and YouTube, in either direction, straight from a global hotkey.
Tauri v2 · Rust · Svelte 5 · Windows tray app · Zero idle CPU
spoti2yt is a Windows system tray app that bridges Spotify and YouTube. Copy a link from either platform, press a hotkey, and the matching link for the other platform lands on your clipboard, complete with a sound cue and a tray toast. It works both ways with equal care: Spotify to YouTube and YouTube to Spotify.
A normally hidden window adds Settings, History, and Playlist tabs, plus a full width now playing bar that controls Spotify playback live.
It started life as a small Python script and was rewritten in Rust for reliable matching, near zero idle CPU, and a real interface.
- Both directions, one keypress. Spotify to YouTube and YouTube to Spotify, no window needed. spoti2yt detects which kind of link is on your clipboard and converts accordingly.
- Whole playlists, not just single tracks. Expand a Spotify playlist into all of its track links at once, or batch convert an entire playlist to YouTube from the Playlist tab, watching each track resolve one by one.
- A matcher that actually works. It handles non official uploads (lyric channels, fan uploads, sped up or slowed versions, remixes, transliterated titles) by scoring title, artist, and duration together and gating on precision rather than raw string overlap.
- Instant repeats. A persistent SQLite cache makes reconverting a known song free, in either direction, because one match covers both ways.
- Live now playing bar. Play, pause, next, previous, shuffle, repeat, seek, volume, and like. Transport controls require Spotify Premium; free accounts get a read only bar.
- Zero idle CPU. Event driven hotkeys, no polling while the window is hidden.
- Local and private. Sign in runs under your own Spotify app via OAuth PKCE. The refresh token lives in the Windows Credential Manager. No telemetry, no servers.
flowchart TD
HK["Global hotkey pressed"] --> CLIP["Read the clipboard"]
CLIP --> TYPE{"What kind of URL?"}
TYPE -->|"Spotify link"| SP["Spotify to YouTube"]
TYPE -->|"YouTube link"| YT["YouTube to Spotify"]
TYPE -->|"Neither"| NOOP["Do nothing, stay silent"]
SP --> CACHE{"Seen before?\n(cache hit)"}
YT --> CACHE
CACHE -->|"Yes"| OUT["Write matched URL\nto the clipboard"]
CACHE -->|"No"| SEARCH["Search the other platform\nScore title + artist + duration"]
SEARCH --> GATE{"Confident match?"}
GATE -->|"Yes"| STORE["Cache the pair\nboth directions"]
STORE --> OUT
GATE -->|"No"| FAIL["Error sound + notification"]
OUT --> DONE["Success sound + tray toast"]
style DONE fill:#22c55e,color:#fff
style FAIL fill:#ef4444,color:#fff
style OUT fill:#1e3a5f,color:#cfe3ff
The matcher is the core of the project. In both directions it computes a composite score of
title + artist + duration, adds a bonus for official "Artist - Topic" audio channels, and
subtracts a penalty for junk uploads. For YouTube to Spotify it gathers artist candidates
from the channel name, the uploader, YouTube Music metadata, and both halves of a dashed
title, then takes the best fit. That is what lets lyric and fan uploads resolve to the right
Spotify track. Matches at or above a confidence floor are cached, so the next conversion of
that song is instant.
| OS | Windows 10 or 11 (x64) |
| Runtime | WebView2, preinstalled on current Windows |
| Account | A free Spotify account. Premium is needed only for the playback transport controls. |
| Your own Spotify app | A free developer app you register once. The in app wizard walks you through it. |
Download the latest spoti2yt_<version>_x64-setup.exe (about 24 MB) from the
Releases page and run it. The installer is self contained: it bundles the
yt-dlp engine and pulls in the WebView2 runtime if your system does not already have it, so
there are no separate downloads to chase.
After installing, launch spoti2yt from the Start menu. It runs in the system tray, and the first launch opens the guided Spotify setup described below.
Prefer to compile it yourself? See Build from source.
spoti2yt signs in through your own free Spotify app, so nothing is routed through a shared third party app. On first launch it opens a short guided wizard that walks you through it. For reference, the steps are:
- Open the Spotify Developer Dashboard and sign in.
- Click Create app, name it anything, and tick Web API.
- In Redirect URIs, add this exact value and save it:
http://127.0.0.1:51789/callback - Copy the app's Client ID and paste it into the wizard.
- Click Sign in to Spotify. Your browser opens once to authorize. Future sign ins are silent.
You never need the Client secret. PKCE does not use one.
All hotkeys are rebindable in Settings. Clear a chord to disable it.
| Hotkey | Action |
|---|---|
Ctrl+Shift+Y |
Spotify to YouTube (clipboard) |
Ctrl+Shift+U |
YouTube to Spotify (clipboard) |
Ctrl+Shift+T |
Track stats plus matched YouTube link |
Ctrl+Shift+P |
Expand a playlist URL to the clipboard |
Ctrl+Shift+L |
Add the clipboard track to Liked Songs |
Ctrl+Shift+K |
Copy the currently playing Spotify URL |
Ctrl+Shift+J |
Convert the currently playing track to YouTube |
Pressing a hotkey that does not match what is on the clipboard does nothing, on purpose.
- Rust (stable, 1.82 or newer) with the MSVC toolchain
- Node.js 18 or newer, with npm
- Tauri v2 prerequisites (Visual C++ Build Tools and WebView2). See the Tauri Windows setup guide.
- yt-dlp, the search and metadata engine spoti2yt shells out to (see below)
yt-dlp.exe is not committed (it is about 18 MB and updates often). Download it into
src-tauri/binaries/ with the platform triple name spoti2yt looks for:
# from the repo root
curl -L -o src-tauri/binaries/yt-dlp-x86_64-pc-windows-msvc.exe `
https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exeYou can keep it current later with the Update yt-dlp button in Settings.
npm install # JS dependencies
npm run tauri dev # hot reloading dev build
# or
npm run tauri build # release build, NSIS installer in src-tauri/target/release/bundleOn Windows you can also use the helper scripts dev.bat (kills any stale instance, then runs
tauri dev) and build.bat.
Everything lives under %APPDATA%\spoti2yt\:
| File | Contents |
|---|---|
config.toml |
Hotkeys, behavior, cache settings, your Spotify Client ID |
history.json |
Rolling history of conversions |
cache.sqlite |
Bidirectional Spotify to YouTube match cache |
*.log |
Rotating logs |
The Spotify refresh token is stored separately in the Windows Credential Manager, never on disk in plain text.
npm run check # svelte-check (one preexisting @types/node note is expected)
# from src-tauri (use a shell with cargo on PATH)
cargo test --lib # unit and matcher regression testssrc-tauri/src/bin/ holds standalone harnesses for tuning the matcher against the real
Spotify and yt-dlp pipeline (test_sp2yt, test_yt2sp, analyze_match, eval_yt2sp). They
authenticate with Spotify's client credentials flow, which needs an app Client ID and secret
supplied through a .env file at the repo root:
cp .env.example .env # then fill in SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET
cargo run --bin test_sp2yt -- "https://open.spotify.com/track/<id>".env is gitignored. These dev tools are the only consumer of the secret. The shipped app
uses PKCE and never touches it.
| Layer | Choice |
|---|---|
| Shell | Tauri v2 |
| Frontend | SvelteKit (static adapter), Svelte 5 runes, TypeScript |
| Backend | Rust |
| Spotify | Custom Web API client, OAuth Authorization Code with PKCE |
| Token storage | Windows Credential Manager (keyring) |
| YouTube | yt-dlp sidecar (search and metadata) |
| Cache | rusqlite (bundled SQLite) |
| Audio | rodio (embedded sound effects) |
- No shared credentials. You sign in through your own Spotify app via OAuth PKCE. There is no client secret in the app and no spoti2yt server in the loop.
- Tokens stay local. The refresh token is held in the OS credential vault. Access tokens live in memory only.
- No telemetry. Network calls go only to Spotify's API and, through yt-dlp, to YouTube.
- When reporting issues, please do not paste real tokens, Client secrets, or
%APPDATA%contents into public threads.
PolyForm Noncommercial License 1.0.0. Free to use, study, modify, and share for any noncommercial purpose (personal, hobby, educational, research, nonprofit). Commercial use is not granted.
Uses yt-dlp and Tauri, which carry their own licenses. Not affiliated with or endorsed by Spotify or YouTube. Please respect their Terms of Service.