Skip to content
Client
Server

Sample apps ​

The repository has one small app, Vinyl Collector Simulator, written once per way of using the SDK. You flip through crates of Apple's catalog, play the previews, sign in with Apple Music, and send your own crate of songs to your library as a playlist. It's a demo: there are no accounts, your crate lives in the tab, and nothing is built to be deployed.

Each sample runs on your machine against the live Apple Music API, with your own MusicKit key and Apple Account. The guides show code from them, and every sample is in the repository's samples folder.

Run one ​

You need Node 24, pnpm, a MusicKit key, and an Apple Account with an Apple Music subscription.

Pick the client and the server to run. Either Vite page runs with either server, and the Next app is both: it's its own server.

Client
Server

1. Get the repository ​

Clone it, and install from its root:

sh
git clone https://github.com/open-music-sdk/js.git open-music-sdk
cd open-music-sdk
pnpm install

2. Add your key ​

Copy samples/.env.example to the server you run, and fill it in:

sh
cp samples/.env.example samples/express-server/.env
sh
cp samples/.env.example samples/worker-server/.env

The Worker reads .env rather than Wrangler's usual .dev.vars. The page's dev server refuses to serve a file named .env, and would serve a .dev.vars to any page that asked for it.

sh
cp samples/.env.example samples/web-nextjs/.env.local

The file holds your private key. The repository ignores it, and neither the Vite pages' dev server nor Next serves it. Never commit it.

3. Run the pair ​

From the repository's root. Turborepo builds the packages first:

sh
pnpm turbo dev --filter=web-vanilla --filter=express-server
sh
pnpm turbo dev --filter=web-vanilla --filter=worker-server
sh
pnpm turbo dev --filter=web-react --filter=express-server
sh
pnpm turbo dev --filter=web-react --filter=worker-server
sh
pnpm turbo dev --filter=web-nextjs

Every page sample serves on localhost:2728, so only one runs at a time.

The build writes the generated files under packages/types/src and packages/validate/src again, with LF line endings. On a checkout with CRLF endings, git then shows them changed with nothing in them changed; git checkout -- packages/types/src packages/validate/src puts them back.

4. Open it ​

Open http://localhost:2728 in your browser. Use localhost, not 127.0.0.1: the developer token is bound to that origin.

5. Stop it ​

Sign out before you stop. Apple's script keeps a copy of your Music User Token in the storage of localhost:2728, which any other app you later serve on that port could read.

Then press Ctrl+C in the terminal. On Windows, Turborepo can stay at "tasks shutting down…" after the first one, with a Terminate batch job (Y/N)? line for each task: pnpm's own command is a batch file there, and the question it leaves waits for an answer nobody can give. Press Ctrl+C again, and Turborepo ends the tasks. The ELIFECYCLE … -1073741510 beside each question is Windows' code for a program that Ctrl+C ended, not an error.

On Windows, Wrangler's workerd can outlive the run. If 127.0.0.1:8787 is still taken, end it in PowerShell:

powershell
Get-Process workerd -ErrorAction SilentlyContinue | Stop-Process

The Worker keeps the tokens it took in samples/worker-server/.wrangler/state, in plain text, after it stops. Delete that folder when you're done.

The server forgets the tokens it took when it stops.

The samples ​

SampleRuns onShows
express-serverNode 24 and Express 5createServerClient, tokenEndpoint mounted on Express, acceptUserToken behind Express's body parser, MemoryUserTokenStore, forUser
worker-serverCloudflare Workers, through Wrangler on your machinetokenEndpoint, userTokenIntake, KvUserTokenStore, forUser
web-vanillaA page built with Vite, with no frameworkcreateBrowserClient, createConnect, previewPlayer, the catalog, the listener's library, and the playlist tools
web-reactA React page built with Vite, with TanStack QueryMusicProvider, useConnect, usePreviewPlayer, useMusicQueries with useQuery and useInfiniteQuery, useMutation over useMusic
web-nextjsNext.js 16, its own serverServer components and server actions through forUser, tokenEndpoint and userTokenIntake as routes, musicQueries prefetched, "use cache", next/image with artworkUrl

The two servers answer the same routes. Each page sample has the same crates and screens, and the two Vite pages keep them in files of the same names, so two samples side by side show what a framework changes. Each file starts with a comment that names the exports it shows and the guide it pairs with.

Every pair, for reference:

PageServerKey fileCommand, from the repository's root
VanillaExpresssamples/express-server/.envpnpm turbo dev --filter=web-vanilla --filter=express-server
VanillaWorkerssamples/worker-server/.envpnpm turbo dev --filter=web-vanilla --filter=worker-server
ReactExpresssamples/express-server/.envpnpm turbo dev --filter=web-react --filter=express-server
ReactWorkerssamples/worker-server/.envpnpm turbo dev --filter=web-react --filter=worker-server
Next.jsNext.jssamples/web-nextjs/.env.localpnpm turbo dev --filter=web-nextjs

How a page and its server talk ​

Both servers listen on 127.0.0.1:8787 and answer the same routes. The page's dev server forwards /api to whichever one runs, so the page and its server share one origin, and the page's tokenUrl stays relative.

RouteWhat it doesGuide
GET /api/music/tokenHands the page a developer token, bound to the page's originServe a developer token to a page
POST /api/music/user-tokenTakes the listener's Music User Token after Apple's sign-in, checks it with Apple, and keeps itKeep a listener's token on your server
GET /api/me/recentWhat the listener played lately, asked by the server with the token it keptKeep a listener's token on your server

A listener is a random id in a cookie the server gives with its first answer. A real app uses its own sessions.

The Next app answers the first two routes under its own src/app/api, and needs no third: its pages ask Apple for the listener on the server, with the token the second route kept.

MIT licensed. Not affiliated with, endorsed by, or sponsored by Apple Inc. Apple Music and MusicKit are trademarks of Apple Inc.