/install beatport-dl-with-browser-tool
Beatport Download via Browser Tool
Download purchased Beatport tracks through the openclaw headless browser using CDP (Chrome DevTools Protocol).
Prerequisites
- openclaw browser running on
127.0.0.1:9222 - Beatport credentials (username + password)
wsmodule at/opt/homebrew/lib/node_modules/openclaw/node_modules/ws- Node.js runtime
Authentication Flow
Beatport uses a dual-auth system:
- account.beatport.com — Django session (
sessionidcookie) - www.beatport.com — NextAuth (
__Secure-next-auth.session-tokencookie)
Login Steps
- Navigate to
https://account.beatport.com/via CDPPage.navigate - Fill username/password via
Runtime.evaluate(use native input setters to bypass React controlled inputs) - Submit the login form
- On the www.beatport.com tab, sign in via NextAuth:
// In browser context on www.beatport.com
fetch("/api/auth/csrf").then(r => r.json()).then(csrf => {
const fd = new URLSearchParams();
fd.append("csrfToken", csrf.csrfToken);
fd.append("username", "USER");
fd.append("password", "PASS");
fd.append("callbackUrl", "https://www.beatport.com/");
// Create hidden form and submit (fetch redirect fails cross-origin)
const form = document.createElement("form");
form.method = "POST";
form.action = "/api/auth/signin/beatport";
form.style.display = "none";
for (const [k, v] of Object.entries(Object.fromEntries(fd))) {
const inp = document.createElement("input");
inp.type = "hidden"; inp.name = k; inp.value = v;
form.appendChild(inp);
}
document.body.appendChild(form);
form.submit();
});
- Verify login:
Account menubutton should appear in navbar (noCreate Account or Log Inbutton)
Key URLs
| Page | URL | Purpose |
|---|---|---|
| Cart | https://www.beatport.com/cart |
Items pending purchase |
| Library | https://www.beatport.com/library |
Purchased tracks (may show Upgrade for free accounts) |
| Downloads | https://www.beatport.com/library/downloads |
Download queue |
| Checkout | https://www.beatport.com/checkout |
Payment page |
Note: /my-beatport/downloads and /my-beatport/collection return 404. The correct paths are /library and /library/downloads.
Enabling Downloads in Headless Chrome
Headless Chrome cancels downloads by default. Enable via CDP on the browser-level WebSocket:
// Browser-level WS: ws://127.0.0.1:9222/devtools/browser/\x3Cid>
ws.send(JSON.stringify({
id: 1,
method: "Browser.setDownloadBehavior",
params: {
behavior: "allowAndName",
downloadPath: "/path/to/download/dir/",
eventsEnabled: true
}
}));
Get browser ID from http://127.0.0.1:9222/json/version → webSocketDebuggerUrl.
Downloading Tracks
Step 1: Add tracks to download queue
On /library, each track has a re-download icon (svg[data-testid='icon-re-download']). Click each one to add to the download queue:
var icons = document.querySelectorAll("svg[data-testid='icon-re-download']");
icons.forEach(function(icon, i) {
setTimeout(function() { icon.closest("button, div").click(); }, i * 500);
});
Step 2: Download from queue page
Navigate to /library/downloads. All queued tracks appear with a "Download All" button.
Step 3: Click Download All
Enable browser downloads first (see above), then click:
var btn = [...document.querySelectorAll("button")].find(b => b.innerText.includes("Download All"));
if (btn) btn.click();
The download arrives as a zip file (e.g. beatport_tracks_2026-04.zip).
Step 4: Unzip and clean up
cd /path/to/download/dir
unzip -o beatport_tracks_*.zip -d tmp/
mv tmp/*.mp3 .
rm -rf tmp/ beatport_tracks_*.zip
Download URL Format
https://zips.beatport.com/v1/download?token=\x3CJWT_TOKEN>
The token is single-use and expires quickly. Always capture fresh from events.
Download URL Format
https://zips.beatport.com/v1/download?token=\x3CJWT_TOKEN>
The token is single-use and expires quickly. Always capture it fresh from the Page.downloadWillBegin event.
API Access
Access Token
curl -s -H "Cookie: \x3Ccookies>" \
"https://www.beatport.com/_next/data/\x3CbuildId>/en/library/downloads.json" \
| jq -r '.pageProps.accessToken'
Library Data
curl -s -H "Cookie: \x3Ccookies>" \
"https://www.beatport.com/_next/data/\x3CbuildId>/en/library.json" \
| jq '.pageProps.dehydratedState.queries[].state.data.results[] | {name, id, artists}'
Build ID
curl -s "https://www.beatport.com/" | grep -o '"buildId":"[^"]*"' | head -1
Current buildId (subject to change): PWoDyRo_P5V8lNYu_92bX
Common Pitfalls
- Cross-domain navigation fails with
Page.navigate— Uselocation.href = "..."viaRuntime.evaluateinstead - React controlled inputs don't respond to
.value =— Use native input value setter:var input = document.querySelector("input[name=username]"); var nativeSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value").set; nativeSetter.call(input, "username"); input.dispatchEvent(new Event("input", { bubbles: true })); - Node.js string escaping in
-e— UseString.raw\...`template literals, or write code to a file and run withnode file.js` - Free account download limit — 20 downloads per track. "Unlimited re-downloads" requires Beatport Streaming subscription
- CDP exec timeout — openclaw kills long-running node processes (~10s). Keep CDP operations short; use
background: true+process pollfor longer waits curlpath — Use/usr/bin/curl, not/opt/homebrew/bin/curl(may not exist)
CDP Helper Pattern
Write scripts to files to avoid shell escaping issues:
// scripts/beatport-cdp.js
const WS = require("/opt/homebrew/lib/node_modules/openclaw/node_modules/ws");
const http = require("http");
function getPage(filter) {
return new Promise((resolve) => {
http.get("http://127.0.0.1:9222/json", (res) => {
let body = "";
res.on("data", (c) => body += c);
res.on("end", () => {
const pages = JSON.parse(body).filter(p => p.type === "page");
resolve(filter ? pages.find(filter) || pages[0] : pages[0]);
});
});
});
}
function cdpEval(ws, expression) {
return new Promise((resolve) => {
ws.send(JSON.stringify({ id: Date.now(), method: "Runtime.evaluate", params: { expression, returnByValue: true } }));
ws.on("message", (m) => {
const d = JSON.parse(m.toString());
if (d.id && d.result) { resolve(d.result); }
});
});
}
async function screenshot(ws, path) {
return new Promise((resolve) => {
ws.send(JSON.stringify({ id: Date.now(), method: "Page.captureScreenshot", params: { format: "png" } }));
ws.on("message", (m) => {
const d = JSON.parse(m.toString());
if (d.id && d.result && d.result.data) {
require("fs").writeFileSync(path, Buffer.from(d.result.data, "base64"));
resolve();
}
});
});
}
module.exports = { getPage, cdpEval, screenshot };
Format Compatibility
- CDJ-2000: MP3 or WAV
- Beatport download options: MP3, WAV, AIFF, FLAC
- Default is MP3; select WAV/AIFF on cart page or account settings if needed for CDJ compatibility
- Make sure OpenClaw is installed (local or Docker)
- Run the install command in chat:
/install beatport-dl-with-browser-tool - After installation, invoke the skill by name or use
/beatport-dl-with-browser-tool - Provide required inputs per the skill's parameter spec and get structured output
What is Beatport Download via Browser Tool?
Download purchased tracks from Beatport using the openclaw headless browser tool (CDP). Handles login, authentication via NextAuth, enabling downloads in hea... It is an AI Agent Skill for Claude Code / OpenClaw, with 56 downloads so far.
How do I install Beatport Download via Browser Tool?
Run "/install beatport-dl-with-browser-tool" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.
Is Beatport Download via Browser Tool free?
Yes, Beatport Download via Browser Tool is completely free, licensed under MIT-0. You can download, install and use it at no cost.
Which platforms does Beatport Download via Browser Tool support?
Beatport Download via Browser Tool is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).
Who created Beatport Download via Browser Tool?
It is built and maintained by esanle (@esanle); the current version is v1.0.0.