Save any Apple Music playlist or album to a spreadsheet or a plain list: title, artist, album, duration and link. Works on Windows, Mac, Linux and Chromebook through Apple Music for the web. Free, no app to install.
Works on Apple Music for the web (music.apple.com) on Windows, Mac, Linux and Chromebook. Open the playlist, then run the script.
// Responsive Muse · Apple Music Playlist Exporter · v1.0 · 2026-10-22
// Saves any Apple Music playlist or album you can open on music.apple.com (your own library
// playlists or public ones) to CSV or TXT: title, artist, album, duration and link. Useful to
// back up a playlist or move it to Spotify, YouTube Music or Tidal. Long playlists load while
// the script scrolls. It makes no network requests of its own and never reads cookies,
// passwords or tokens.
(async () => {
const TOOL = 'Export Apple Music playlist';
const FORMAT = 'csv'; // 'csv' (Excel, Sheets, playlist converters) or 'txt' ("Artist - Title", one per line)
if (location.hostname !== 'music.apple.com' || !/\/(playlist|album|library)\b/.test(location.pathname)) {
alert('Open a playlist on Apple Music for the web first, for example:\nhttps://music.apple.com/library/playlists');
return;
}
// A small box on the page shows progress and asks before changing anything,
// so you never need to read or edit the console.
const many = (n, word) => `${n} ${word}${n === 1 ? '' : 's'}`; // 1 video, 2 videos
const panel = (() => {
const box = document.createElement('div');
box.style.cssText = 'position:fixed;right:16px;bottom:16px;z-index:2147483647;width:340px;max-width:calc(100vw - 32px);' +
'background:#111318;color:#e6e8ee;font:14px/1.5 system-ui,sans-serif;border-radius:12px;padding:16px;' +
'box-shadow:0 8px 30px rgba(0,0,0,.4);text-align:left';
const head = document.createElement('strong');
head.textContent = TOOL;
const msg = document.createElement('p');
msg.style.cssText = 'margin:8px 0 12px;white-space:pre-line';
const row = document.createElement('div');
row.style.cssText = 'display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-end';
box.append(head, msg, row);
document.body.append(box);
const button = (label, primary, onClick) => {
const b = document.createElement('button');
b.textContent = label;
b.style.cssText = 'font:600 14px system-ui,sans-serif;padding:8px 14px;border-radius:8px;cursor:pointer;' +
(primary ? 'background:#0f766e;color:#fff;border:1px solid #0f766e' : 'background:none;color:#e6e8ee;border:1px solid #3a3f4b');
b.onclick = onClick;
row.append(b);
};
return {
text(t) { msg.textContent = t; },
ask(t, yes) {
msg.textContent = t;
row.replaceChildren();
return new Promise(r => {
button('Cancel', false, () => { row.replaceChildren(); r(false); });
button(yes, true, () => { row.replaceChildren(); r(true); });
});
},
stoppable(onStop) { row.replaceChildren(); button('Stop', false, onStop); },
actions(t, list) {
msg.textContent = t;
row.replaceChildren();
list.forEach(([label, primary, run]) => button(label, primary, run));
},
finish(t) { this.actions(t, [['Close', true, () => box.remove()]]); },
close() { box.remove(); },
};
})();
// Offer the result as a downloaded file or as clipboard text (a real click, so it always works)
const deliver = (summary, body, file) => {
const save = () => {
const a = document.createElement('a');
a.href = URL.createObjectURL(new Blob([/\.csv$/.test(file) ? '\ufeff' + body : body], { type: 'text/plain;charset=utf-8' }));
a.download = file;
a.click();
setTimeout(() => URL.revokeObjectURL(a.href), 5000);
panel.text(`${summary}\nSaved as ${file} (check your Downloads).`);
};
const copy = () => navigator.clipboard.writeText(body)
.then(() => panel.text(`${summary}\nCopied. Paste it into a spreadsheet or a note.`))
.catch(() => panel.text(`${summary}\nThe browser blocked the clipboard: use Download instead.`));
panel.actions(summary, [['Close', false, () => panel.close()], ['Copy', false, copy], ['Download', true, save]]);
};
const sleep = ms => new Promise(r => setTimeout(r, ms));
const tracks = new Map();
// Apple Music scrolls an inner panel, not the window
const scroller = document.querySelector('#scrollable-page') || document.scrollingElement;
const text = (el, id) => (el.querySelector(`[data-testid="${id}"]`)?.textContent || '').replace(/\s+/g, ' ').trim();
// Read the songs currently on screen
const collect = () => {
for (const row of document.querySelectorAll('[data-testid="track-list-item"]')) {
const title = text(row, 'track-title');
if (!title) continue;
const link = row.querySelector('a[href*="/song/"], a[href*="?i="]');
const artist = text(row, 'track-title-by-line') || text(row, 'track-column-secondary');
const key = link?.href || title + '|' + artist;
if (tracks.has(key)) continue;
tracks.set(key, {
n: tracks.size + 1,
title,
artist,
album: text(row, 'track-column-tertiary'),
duration: text(row, 'track-duration'),
url: link?.href || '',
});
}
};
// 1. Scroll to the end, collecting as we go, until nothing new appears three times in a row
let stop = false;
panel.stoppable(() => { stop = true; });
scroller.scrollTo(0, 0);
await sleep(800);
let idle = 0;
while (idle < 3 && !stop) {
const before = tracks.size;
collect();
scroller.scrollBy(0, scroller.clientHeight * 0.8);
await sleep(1000);
idle = tracks.size === before ? idle + 1 : 0;
panel.text(`Collecting songs… ${tracks.size}`);
}
const list = [...tracks.values()];
if (!list.length) {
panel.finish('No songs found. Apple Music may have changed its layout: please report it on responsive-muse.com.');
return 0;
}
// 2. Build the file and offer it
const cell = v => '"' + String(v).replace(/"/g, '""') + '"';
const body = FORMAT === 'txt'
? list.map(t => `${t.artist} - ${t.title}`).join('\n')
: ['#,Title,Artist,Album,Duration,URL', ...list.map(t =>
[t.n, t.title, t.artist, t.album, t.duration, t.url].map(cell).join(','))].join('\n');
const name = (document.title.replace(/^/, '').replace(/ - (Playlist|Album).*$/, '') || 'playlist').replace(/[\\/:*?"<>|]+/g, '_');
deliver(`${stop ? 'Stopped early. ' : ''}Found ${many(list.length, 'song')}.`, body, `${name}.${FORMAT}`);
return list.length;
})();
Bookmarklet: drag the middle button to your bookmarks bar, open music.apple.com and click the bookmark. It runs the same script with the options above.
- Sends nothing anywhere. No fetch, XHR or external scripts. The only network activity is music.apple.com itself loading your list.
- Never touches your login. It doesn't read cookies, passwords, tokens or browser storage.
- Only runs on music.apple.com. Anywhere else it stops before doing anything.
- Short and readable. 130 commented lines, not minified or obfuscated.
- Shows its progress on the page. A small box tells you what it's doing and offers Download or Copy at the end.
- Same code for everyone. SHA-256 of the default version:
937b35c209aac4c8…
Verify it yourself in 30 seconds
- Read it: every line is above, with comments.
- Search the code for
fetch,XMLHttpRequest,cookie,localStorageoreval. None of them appear. - Open the Network tab before running it: you'll only see requests to music.apple.com.
How to use it
- Open the playlist on music.apple.com (sign in for your own library playlists; public playlists and albums work without signing in).
- Open the console: F12 or Ctrl+Shift+J (Cmd+Option+J on Mac). If Chrome asks, type
allow pastingand press Enter. - Pick a format, copy the script, paste it in the console and press Enter. It scrolls the playlist and shows a box: click Download (or Copy).
Move it to Spotify, YouTube Music or Tidal
Use the CSV with a playlist converter that accepts files, or choose TXT to get one Artist - Title per line, the format most “paste your tracklist” importers understand.
FAQ
Doesn't Apple Music have an export button?
Only in the Music app on a Mac (File > Library > Export Playlist). On Windows, iPhone, Android and the web there is none, which is why this script exists.
Can I move the playlist to Spotify or YouTube Music?
Yes. Export it as CSV and import the file with a playlist converter, or use the TXT format ("Artist - Title" per line) and paste it into one.
Does it work with my own library playlists?
Yes. Sign in on music.apple.com, open the playlist from your library and run it. Long playlists load while the script scrolls.
Do I need an Apple Music subscription?
Not for public playlists and albums. Your own library playlists need you to be signed in.
More free tools
YouTube
10 tools- Clear Watch Later
- Unsubscribe from all channels
- Unlike all videos
- Export Watch Later
- Export saved posts
- Delete all comments
TikTok
1 tool- Export profile videos
Amazon
2 tools- Export order history
- Export wishlist
X / Twitter
3 tools- Export bookmarks
- Unlike all posts
- Remove all bookmarks
AI chats
4 tools- Export ChatGPT chat
- Export Claude chat
- Export Gemini chat
- Export Perplexity thread
Google Maps
1 tool- Export Google Maps reviews
Steam
1 tool- Export Steam wishlist
Apple Music
1 tool- Export Apple Music playlist
Spotify
2 tools- Export Spotify playlist
- Export Liked Songs
