Nixie is a desktop client for YouTube Music. It plays your account's music through a native app instead of a browser tab: loudness normalization you can actually set, time-synced lyrics, and a session that comes back exactly where you left it.
It is an independent project. There is no Nixie account, no backend and no telemetry. Everything it knows stays on your computer.
Important
Nixie is an independent, unofficial client and is not affiliated with, endorsed by, or sponsored by Google or YouTube. It is not a YouTube Music product, it does not copy or imitate one, and nothing here speaks for Google. YouTube and YouTube Music are trademarks of Google LLC. It was written because I wanted a desktop client I liked better for my own listening, and it is shared in case anyone else wants the same thing.
Important
Nixie is beta software. Things move, and some of them break. It runs on macOS, Windows and Linux. The macOS builds are signed and notarized by Apple for Apple silicon and Intel; the Windows installer is not signed yet, so Windows warns about it the first time (see Install); Linux ships as an x64 AppImage.
Important
Nixie requires a YouTube Music Premium subscription. It plays without advertisements, in the background, and through its own audio engine, and those are the things YouTube sells a subscription for. It checks when you link an account and refuses one that does not hold a subscription. Nixie is not a way to get Premium features without Premium, and it is not affiliated with or authorized by YouTube.
Grab the latest build from the releases page:
| File | For |
|---|---|
Nixie-<version>-applesilicon.dmg |
Macs with Apple silicon, M1 and later, on macOS 13 Ventura or later |
Nixie-<version>-intel.dmg |
Intel Macs on macOS 13 Ventura or later |
Nixie-<version>-setup.exe |
Windows 10 and 11, 64-bit |
Nixie-<version>-x64.AppImage |
Linux, 64-bit |
Whichever one you take, the app then checks for updates on its own, downloads them in the background, and asks nothing of you beyond a restart. If you never restart, the update installs the next time you quit.
macOS. Every release is signed and notarized by Apple, the disk image as well as the app inside it, so it opens on a double click with no right-click trick and no Gatekeeper warning at either step.
Windows. The installer is not signed, because a code signing certificate is an annual bill this project does not have. Windows notices: SmartScreen shows a blue "Windows protected your PC" box on the first download, and you get past it with More info and then Run anyway. That warning is about the absence of a certificate and not about anything found in the file, and it fades as more people install the same build. Read docs/signing.md if you want the detail, and check the file against the releases page if you did not download it from there. Installation is per-user and needs no administrator, and updates install themselves the same way they do everywhere else.
Linux. An AppImage is a single file. Mark it executable with chmod +x and run it. It
carries a static runtime, so it needs no libfuse2 on Ubuntu 24.04 and later. Updating
itself only works when it is run as the AppImage, which is the ordinary way to run it.
Sign-in reads browsers installed the traditional way, under ~/.config (or
$XDG_CONFIG_HOME) and ~/.mozilla. A browser installed as a snap or a flatpak keeps its
profile elsewhere, so Nixie does not find it, and its confinement also stops it launching
the Nixie Link native host, so the extension does not reach it either. On a stock Ubuntu,
whose Firefox and Chromium are snaps, install a browser from its vendor's own repository
instead: Firefox from Mozilla's apt repository, or Chrome, Edge, Brave or Vivaldi from
theirs. Reading a Chromium browser whose cookies sit under the desktop keyring needs
libsecret-tools installed and the keyring unlocked; Firefox needs neither. One more thing
worth knowing: on a system that restricts unprivileged user namespaces (Ubuntu 24.04 does,
through AppArmor) the AppImage launcher starts the app with Chromium's sandbox off, because
the alternative is an app that does not start. That is the launcher's doing, not the app's,
and a system that allows them runs the same file sandboxed.
On Windows, a Chromium browser that has moved to app-bound cookie encryption (Chrome 127 and later today) needs one extra step to sign in. docs/extension.md covers it, and How signing in works below says why.
![]() |
![]() |
| Your home feed, mood chips and all | Explore, with charts, moods and new releases |
![]() |
![]() |
| Lyrics that follow the playhead, and seek when you click a line | Loudness normalization, with a target you pick |
I use YouTube Music every day and the official web app kept getting in the way. Three things in particular, and each one is why a specific piece of this app exists.
There is no loudness normalization you can set. One track arrives mastered loud, the next one quiet, and you spend the evening on the volume key. Nixie normalizes to a target you choose: -19, -14 or -11 LUFS, the same three levels Spotify publishes, with -14 as the default because that is what YouTube itself aims for. It reads the integrated loudness YouTube already measured for each stream, so there is no analysis pass and no delay before a track starts. Loud tracks are pulled all the way down; quiet ones are lifted, but never by more than 6 dB, because YouTube publishes a loudness and not a true peak, and a quiet master that is already peaking near full scale would clip if you lifted it blind.
Nothing is where you left it. Close the tab, come back, start over. Nixie saves the queue, the current track, the exact position in it, the volume, and whether repeat and shuffle were on. Reopen it and everything is there, paused, with the stream already resolved so the first press of Space starts instantly. It comes back paused on purpose: an app that starts making noise before you have asked it to is not a feature.
Lyrics are plain text, when they are there at all. Nixie asks three sources in order, LRCLIB, then NetEase, then YouTube Music itself, and prefers a time-synced result over a plain one regardless of which source it came from. Synced lyrics highlight the line you are on, scroll to keep it in view, and seek when you click one. It stops at the first source good enough, so most tracks never get past the first request.
Beyond those three, it is simply nicer to use: a real track table with sortable columns of information, a persistent player, a queue you can see, keyboard shortcuts, media keys, and Now Playing in Control Center. It is a desktop app, not a web page in a frame.
Playback
- Loudness normalization at -19, -14 or -11 LUFS, or off.
- A volume slider that behaves like your ears do, not like a gain multiplier.
- Queue with play next, add to queue, reorder and remove. Repeat off, all or one. Shuffle.
- Radio from any track, album, artist or playlist.
- Autoplay that extends an exhausted queue a full track before the end, so the music never stops to wait for a network request.
- Three audio quality levels: data saver, balanced, or highest available.
Lyrics
- Time-synced when a source has them, plain text when it does not, and an explicit "instrumental" when the track has none to find.
- Click any line to seek to it.
- Lyric requests carry no cookie and identify neither you nor the account, except to YouTube Music, which is asked over the session already streaming the audio.
Library and browsing
- The home feed with its mood chips and infinite scrolling.
- Explore, including charts per country.
- Search with live suggestions, and filters for songs, albums, artists and playlists.
- Album, artist and playlist pages.
- Create, rename, describe, reorder, edit privacy on and delete playlists. Add and remove tracks. Like, dislike, save to library, subscribe to artists.
Desktop integration
- Now Playing in Control Center on macOS, the media transport controls on Windows, with artwork, and hardware media keys everywhere they exist.
- A quiet notification naming the next track when the queue moves on by itself. Never while the window is focused, and never with a sound, because the only sound this app makes is the music.
- One window per install: launching Nixie again brings back the one you have rather than opening a second copy over the same saved session.
- Automatic updates on all three platforms.
- In English and Italian. It opens in your system's language and can be changed in Settings, and YouTube Music's own shelves and genres follow the same choice.
- Keyboard shortcuts follow the platform: Cmd+K to search and the app menu's playback items on macOS, Ctrl+K and Ctrl+Left / Ctrl+Right on Windows and Linux.
Privacy and security
- No account, no backend, no telemetry, no analytics, no crash uploader.
- Sandboxed renderer, context isolation, a strict content security policy, and validated IPC. Media and artwork are served through a restricted custom protocol, so the renderer never holds a signed URL or a filesystem path.
- See PRIVACY.md for exactly what is stored and what leaves the machine, and SECURITY.md for how to report a vulnerability.
Google refuses sign-in from an embedded browser window, and refuses OAuth tokens on the endpoints this app talks to. So Nixie does not ask for your password at all. Instead it adopts the session from a browser you are already signed in to on the same machine.
Pick a browser profile on the sign-in screen and Nixie reads that profile's YouTube cookies. They go into a dedicated Electron session partition and nowhere else. They are never logged, never sent anywhere except YouTube, and never exposed to the app's interface. Google expires the session every few minutes and only the browser holds the current value, so Nixie reads that profile again while it runs, at most once a minute, for as long as the account stays linked. There is no password field, and no way to paste a session by hand.
Which browsers it can read from depends on how each one stores its cookies:
| Browser | macOS | Linux | Windows |
|---|---|---|---|
| Firefox | Yes | Yes | Yes |
| Chrome | Yes | Yes | Extension (127 and later) |
| Edge, Brave, Vivaldi, Chromium | Yes | Yes | Yes, until they adopt app-bound encryption |
What decides the Windows column is not the browser's name but how its cookie store is encrypted, which Nixie reads off the store itself. A profile still under the older DPAPI scheme is read from disk like any other; Chrome 127 and later wrap the cookie key so that only the browser's own signed binary can unwrap it, and the other Chromium browsers will land there too when they take that change. Getting at it means pretending to be Chrome, which this project will not do, so those profiles are not offered at all rather than offered and then failing. The Nixie browser extension is the way in there: it reads its own cookies through the API the browser gives every extension, authenticates Nixie's request with a private pairing code, and encrypts the cookie payload before native messaging carries it. Nothing is worked around, and no cookie is pasted. docs/extension.md is the walkthrough. It is a Chromium extension, for Chrome, Edge, Brave, Vivaldi and Chromium: Firefox has no extension and needs none, since its profile is read from disk on every platform. The extension is optional everywhere else, where reading the profile from disk already works, and it does not reach a snap or flatpak browser on Linux (see Install).
Two smaller things worth knowing. On Windows, a browser that is running holds its cookie file locked, so a profile can be missing from the list until you quit that browser (the extension has no such problem). And on macOS the first read asks for your Keychain password, which is macOS asking whether Nixie may read that browser's key. Recent macOS versions also keep one app out of another app's data until you allow it: when that blocks the read, Nixie opens on a screen asking you to turn it on under System Settings, Privacy & Security, Full Disk Access, and to restart it. Nixie Link reads nothing off disk and needs neither.
Nixie reaches YouTube through the private interface the YouTube Music apps use, which Google does not publish or support. Nothing about you leaves this device to anyone else, but the account you link is talking to YouTube through an unofficial client, and it carries whatever risk that brings.
Once the session is adopted, Nixie checks that the account holds a Music Premium subscription, by asking YouTube what audio tiers it is willing to offer: the 256 kbps tiers are offered to a subscriber and to nobody else. An account without one is refused and nothing is stored for it. If that check cannot reach YouTube at all it lets you through, because a network failure is not evidence about anybody's subscription.
Signing out clears the session and the parser cache.
Nixie is free, MIT licensed, and has no paid tier or premium build. Nothing in the app asks for money, and nothing is ever kept behind a donation.
What it costs is time: reading upstream responses that changed overnight, chasing a race in the audio engine, keeping three lyric providers working, and keeping all three platforms building from one tag.
If Nixie is what you listen to and you want to give something back, a donation is welcome and entirely optional. Any amount helps, and it is the difference between this being a project I maintain and a project I get to work on. A donation supports the person writing Nixie. It buys no feature, no priority and no entitlement to anything on YouTube.
- Node 24 and pnpm 12.8.1, both exactly.
enginesis strict and.node-versionis there for anyone using a version manager. - macOS, Windows or Linux. All three work, and
pnpm checkruns on Ubuntu and Windows in CI. On macOS you also need the Xcode command line tools (xcode-select --install) and the headers included with Node. They build the small native trackpad bridge and prepare the development app. These steps do nothing on Windows and Linux.
You do not need an Apple Developer account to build and run the app. That is only for producing signed, notarized macOS releases, and docs/signing.md covers it. Windows and Linux releases are unsigned, so they need nothing at all.
git clone https://github.com/NixiePlayer/NixieDesktop.git
cd NixieDesktop
pnpm install
pnpm devOn macOS the app opens with a blue icon and calls itself Nixie (Dev). Elsewhere it is the stock Electron window with its own icon, since there is no bundle to rename. Sign in by picking a browser profile, the same as the released app.
A few things happen on the way there that are worth knowing about, because they look strange if you meet them by surprise:
- On macOS,
pnpm installrunsscripts/dev-app-name.mjs. It renames the bundled Electron app toNixie.app, sets its display name to "Nixie (Dev)", paints its icon blue, and then re-signs it ad hoc. That last step matters: editing an Electron bundle'sInfo.plistbreaks the signature it ships with, and macOS silently refuses notifications from an app whose signature does not validate. The same script runs again on everypnpm dev, since anything that re-extractsnode_modules/electronputs the stock bundle back. pnpm devstarts Vite on port 3000 for the renderer and compiles the main process and preload intodist-electron/, then launches Electron against them. All three reload on save.- The dev build stores its data under
Nixie (Dev), separate from the released app. Its linked account, settings and playback state are its own, and you can run both at once.
pnpm checkThat is the whole gate, and it is what CI runs on every pull request, on Ubuntu and on
Windows. In order it does formatting (oxfmt), linting (oxlint), type checking
(tsc --noEmit), unit tests (vitest), route generation (tsr generate), and a
production build. Run one test file on its own with
pnpm vitest run src/lib/audio-engine.test.ts, or pnpm vitest to watch.
To build an installable app for the platform you are on:
pnpm package:mac # an app directory, ad-hoc signed
pnpm package:win # the NSIS installer, unsigned
pnpm package:linux # the AppImageEach one has to run on the platform it names. The Windows and Linux builds print a "skipping afterSign hook as no signing occurred" warning from electron-builder, which is expected: those hooks are the macOS notarization steps, and there is nothing for them to do.
| Path | What lives there |
|---|---|
electron/ |
Main process: the YouTube adapter, the secure protocols, cookie import, lyrics, state, logging |
electron/native-host/ |
The relay the browser launches for the extension sign-in path |
src/routes/ |
Pages, as TanStack Router file routes with hash history. Data loading is loaders, there is no query client |
src/components/ |
The shell, player bar, panels and dialogs. ui/ is generated shadcn source |
src/lib/ |
Renderer logic. audio-engine.ts owns playback and is framework-free and unit tested |
src/shared/ |
Contracts and pure logic used on both sides of the process boundary |
scripts/ |
Dev setup and release hooks |
build/ |
Icons that electron-builder packages |
AGENTS.md is the architecture and conventions guide, including several places where the obvious approach is the broken one. Read it before touching the code.
Bug reports, fixes and features are all welcome. Open an issue before starting anything large, so nobody spends a weekend on a direction that was never going to land.
CONTRIBUTING.md has the conventions, the verification loop, and the short list of things that will get a pull request turned down.
Nixie is MIT licensed. See also PRIVACY.md, SECURITY.md and THIRD_PARTY_NOTICES.md. Every build also ships the full licence text of every open source package inside it, generated from the dependency tree and readable in Settings, under About.
Nixie is an independent, unofficial client. It is not affiliated with, endorsed by, or sponsored by YouTube, Google, Spotify, LRCLIB, or NetEase Cloud Music. YouTube and YouTube Music are trademarks of Google LLC, used here only to say what Nixie connects to, and no name, logo or interface of theirs is copied or imitated. You need your own YouTube Music account to use it, and your use of that account remains subject to YouTube's terms. Nothing in this project is meant to disparage YouTube Music, YouTube or Google: it exists because I wanted a different desktop client for my own listening, not as a replacement for or a criticism of theirs. If Google or YouTube would like anything here changed, please open an issue and it will be dealt with.




