A+BPolicy

Privacy

Your music stays on your Mac. In plain words first: what leaves your Mac when you use Open DJ, what never does, and what changes if you run it from source. The detail below is from a read of the code on main at 487fa677d7, Fri 2 Oct 2026.

ADeck A / The app

What the app keeps, and what leaves.

Stays on your Mac by default, with the installed app: your audio files and your settings. Your library and its playlists stay on your Mac unless you run your own sync hub (below). Making stems from the installed app is not yet proven (STEM-39 open), so today stems come from a source checkout; where stems are made, and what that sends, is below. Google sign-in is optional; what it sends is under Signing in with Google.

Leaves your Mac on its own: three small lookups. Lyrics for your library (artist, title and duration, to LRCLIB), cover art when a track loads onto a deck (title and first artist, to MusicBrainz, then a release id to the Cover Art Archive), and a check for a newer version at every start (a request to GitHub with nothing about you or your library).

Leaves only if you agree: error reports and a screen recording with all text masked, after you accept the test-user terms. They are held while a deck is playing, and track titles, artists, playlist names and file paths are stripped out.

Changes only from a source checkout: developer tools can upload whole audio files, to a GPU service for stems or to a storage bucket for sync, and can copy the library database to a bucket, but only to services you configure yourself. Listed below.

This describes the code at that commit. The launch build is checked against it before release (download page).

Your library

Open DJ reads your DJ library and keeps its own state in a database file on your machine. The app's engine listens on 127.0.0.1, so it is reachable only from your own computer. Your music library and listening history are not collected by the project.

Stems and your audio

The code to make stems from the installed app is in but not yet proven: STEM-39 stays open until a signed build separates a track on a clean Mac. When stems are made, a remote GPU you have configured may receive the whole audio file of each track: the project's stems relay (which needs a relay address and your Google sign-in) or Modal, a GPU cloud, with your own Modal account. Remote processing is allowed by default; with no route configured, or with MUSIC_DJ_CLOUDSYNC_MODE=local, separation stays on your Mac.

Signing in with Google

Sign-in is optional and the app works without it; it is required for the stems relay route and to enroll a machine in a CloudSync hub. Signing in opens Google's own sign-in page, so Google sees your Google login and that Open DJ asked for it; the app then trades a one-time code with Google for your identity and sign-in tokens. Nothing about your library is sent. Open DJ requests only the three standard identity scopes, openid, email and profile, and no access to Gmail, Drive, contacts, calendar or any other Google service. When you sign in, these are stored on your own computer: your Google account identifier (the stable sub value), your email address, your display name, the URL of your profile picture, and sign-in tokens that keep you signed in, including a refresh token. The session token itself is stored only as a SHA-256 hash, so the stored copy cannot be replayed as a login.

Error reports

The desktop app reports crashes and uncaught errors to the project's Sentry account, hosted in Sentry's EU region, so a tester does not have to dig out a log file. The reporting key is built into the app, and sending is held until you accept. The rules, from docs/telemetry.md:

  • Nothing leaves until you agree. The app asks once, with the test-user terms. Until you accept, every report stays in a local log. Declining is remembered as an opt-out.
  • Held mid-set. Reports are held while any deck is playing or audible; if the app cannot tell whether a deck is playing, it sends.
  • Sent: the error type, message and stack frames; an allowlist of technical context such as the route, error code, engine version, deck number and sample rate; runtime, OS and device details; the build version.
  • Never sent: track titles, artists, album or playlist names or any other library content; file paths, which are cut down to their extension; local variables; request bodies, cookies and headers; your identity. The reporting library is told not to attach personal data such as your IP address, although Sentry, like any server, sees the connection's IP address when a report arrives. If the scrubber itself fails, the report is not sent at all.
  • Session replay, after you accept: a recording of the app's screen with all text masked, so track names show as blocks, and no media or waveforms. It stops, and discards what it had buffered, the moment a deck starts playing, and starts again a few seconds after every deck is idle. The replay recorder is loaded from Sentry's servers only after you accept.
  • Off switch: decline the terms, or create a file named telemetry-opt-out in the engine's data directory. There is no in-app toggle yet. Running from source, error reporting is off unless you turn it on.

No analytics, profiling or usage-metrics service is used; the only recording of what you do is the consent-gated session replay above. The app keeps its own logs, performance samples and a page-view log in its data directory, for troubleshooting; they stay on your machine unless you send them yourself.

Lyrics

The app fills in lyrics for your library in the background, one track at a time, and also when you ask for them for a track. For each track it asks LRCLIB (lrclib.net), a free public lyrics service, for line-synced lyrics, sending the track's artist name, title and duration. The answer is cached on your machine. There is no in-app switch for the background fetch yet; it can be turned off with MUSIC_DJ_COVERAGE_DRAIN=off or the coverage-drain command line, and it never runs while a deck is playing.

Cover art

When a track loads onto a deck and has no artwork in rekordbox, in the audio file or beside it, the app asks MusicBrainz (musicbrainz.org) for the recording, sending the track's title and first artist (the duration is used on your Mac to pick the match), then fetches the cover image from the Cover Art Archive (coverartarchive.org). Results, including misses, are cached on your machine, and a track with no online cover is looked up again at most once a week. Nothing is written into your library or audio files. There is no in-app switch yet; the environment variable ODJ_ARTWORK_ONLINE=0 turns the lookup off.

Update check

Each time the app starts, it checks GitHub for a newer release by downloading a small public file (latest.json). The request carries no account, library or device identifier; GitHub sees your IP address, as with any download. Updates install only when you click Install, and each download is signature-checked. There is no switch to turn the check off yet.

Optional AI helpers

The setup assistant and the settings search can use an AI service (OpenRouter or xAI) only if you provide your own API key. They send what you type, not your library.

Optional cloud sync

The code includes optional sync of your own library data between your own machines, through a hub you run yourself on your private network (Tailscale). Without a hub you have configured it does nothing; the performance screen only shows its status. What it copies includes track and playlist details and the file paths of your music on each machine. Stem and lyrics files may also be fetched from a Cloudflare R2 bucket, through links the hub signs. From a source checkout with storage-bucket credentials set, CloudSync can also upload and download whole audio files to and from a bucket you configure. It is off unless you configure a hub.

Source checkout and operator tools

Some tools run only from a source checkout, not from the installed app, and each sends data when you run it: the Spotify importer (to Spotify), a Spotify-to-SoundCloud transfer tool (to SoundCloud, and track titles and artists of uncertain matches to OpenRouter, an AI service), a lyrics evaluation tool that can query Musixmatch with your own key, direct stem separation on Modal, speech-to-text for voice commands through Groq (only with STT_BACKEND=groq and a GROQ_API_KEY), and Litestream copying the library database to a storage bucket you configure. The installed app does none of these by default.

Deleting your data

Signing out deletes the stored session; it does not revoke access at Google, so use the Google permissions page below for that. Because everything is held locally, deleting the application's data directory removes all stored account information. You can also revoke Open DJ's access from your Google account permissions page, which invalidates the stored tokens.

BDeck B / This website

What this website does.

  • Body fonts load from Google Fonts, so your browser contacts Google's font servers when a page opens. The display face is served from this site.
  • This site loads no analytics script. Cloudflare, which serves it, keeps its own request logs.
  • Static pages: no cookies, no tracking pixels, no advertising and no fingerprinting.
  • The crossfader remembers its position in your browser's local storage, under the key odj.two-decks.fader.v1, so the next page opens on the same mix. It never leaves your browser. Clearing site data removes it.

Who runs this

Open DJ is a personal project by Alex Foster. Questions or requests: alex-foster-personal on GitHub. The project address, hello@open-dj.com, works once its forwarding is verified; see the contact box on the Press page.

Children

Open DJ is not directed at children under 13 and does not knowingly collect their data.

Changes

If what the app or this website collects changes, this page changes with it, and the commit it describes changes too.

A / Parity
Beyond / B { type: 'crossfader', value: 0.50 }