Download and tag SoundCloud tracks unlocked via Hypeddit, Droploud, GateRush, DownloadGater, StillHype, PumpYourSound, MyPressKit, Bandcamp, or a direct download link.
- 🎵 Automatically download audio from Hypeddit, Droploud, GateRush, DownloadGater, StillHype, PumpYourSound, MyPressKit, Bandcamp, and direct file links (e.g. Dropbox
dl=1) - ⚡ Browserless fast path that skips the browser for gates that don't need real verification (see How It Works)
- 🔄 Handles multiple gate types (see How It Works)
- 📝 Fetches metadata from the provided SoundCloud link
- 🎨 Manual metadata correction before finalizing
- 🎧 Extracts audio from ZIP downloads, prefers lossless files, and converts them to the selected format
- 🏷️ Tags MP3 files with metadata and artwork from SoundCloud
- 🧹 Optional cleanup of the SoundCloud account (unfollow, unlike, delete comments/reposts)
- 🧩 Userscript (Violentmonkey) that opens the Web UI in a floating panel next to SoundCloud store/buy links
- Bun - JavaScript runtime and package manager
- ffmpeg - Must be installed and available in your
PATH - unzip - Required when a gate provides its audio inside a ZIP archive
- yt-dlp - Required for Bandcamp purchase/download links and for downloading a SoundCloud track directly when no gate is found. Bandcamp support requires the optional
curl_cffibackend (python-curl-cffion Arch Linux oryt-dlp[default,curl-cffi]with pip) for Chrome impersonation. - curl-impersonate (optional but recommended) - Chrome-TLS curl binary (
curl_chrome131,curl_chrome116, orcurl-impersonateon yourPATH). Used for SoundCloud engagement writes (repost GraphQL /me/track_reposts) that DataDome often blocks when done with Bun's normal TLS. Without it the tool falls back to Bunfetch, which may get a 403. Pair with a residential proxy viaSC_API_PROXY,CLOAKBROWSER_PROXY, orPROXY_URLwhen your IP is hard-blocked. - SoundCloud account - It is recommended to create a throwaway account for this. Even though there were no reports of accounts getting banned I can't guarantee it. Also most gate downloads require reposts/likes/follows which you might not want to do with your main account
- Spotify account (optional) - Required when a Hypeddit post has an unskippable Spotify gate. I also recommend creating a throwaway account as most Hypeddit downloads require saving playlists/songs to your library or following artists which you might not want on your main account.
Clone the repository
git clone https://github.com/D3SOX/sc-gate-dl
cd sc-gate-dlInstall dependencies
bun installIf you want to use the Web UI you also need to install the dependencies for it
cd webui
bun installCreate a .env file in the project root by copying the .env.example file and filling in the values.
For HYPEDDIT_NAME and SC_COMMENT currently everything works (I use just asd)
For HYPEDDIT_EMAIL you can enter any valid email address (For example grab one from temp-mail.org)
- Go to soundcloud.com and log in (skip if you are already logged in)
- Open up the developer tools (Right click → Inspect or press F12) and go to the Network tab
- Navigate to soundcloud.com (refresh the page if needed), and you should see a bunch of requests in the network tab
- Find the request that has the name
session(you can filter by typingsessionin the filter box) and click on it - Go to the Payload tab
- You should see your client id in the Query String Parameters section, and your oauth token (
access_token) in the Request Payload section - Copy these values to your
.envfile asSC_CLIENT_IDandSC_OAUTH_TOKEN
If you want to export data from a separate SoundCloud account, add that account's credentials as MANAGED_SC_CLIENT_ID and MANAGED_SC_OAUTH_TOKEN.
For Firefox-based browsers: Install the EditThisCookie2 extension
For Chromium-based browsers (Chrome, Edge, Brave, Helium, etc.): Install the EditThisCookie (fork) extension
Used for SoundCloud API/session automation and for yt-dlp when downloading a SoundCloud track directly (so downloadable tracks can fetch the original upload, not only the 128k stream).
You can omit soundcloud-cookies.json and use Initialize Logins in the Web
UI instead. Sign in through the visible or remote browser; after SoundCloud's
Library page opens, sc-gate-dl saves the browser cookies to
soundcloud-cookies.json with owner-only permissions. A blank file and [] are
also treated as an empty cookie set. The exported cookies are reused by browser
gate jobs and yt-dlp.
Steps:
- Go to soundcloud.com and log in
- Open the extension and click on the export button
- Save what was copied to the clipboard to a file called
soundcloud-cookies.jsonin the project root
If you plan to download tracks that require Spotify gates, you'll also need Spotify cookies:
Steps:
- Go to accounts.spotify.com and log in
- Open the extension and click on the export button
- Save what was copied to the clipboard to a file called
spotify-cookies.jsonin the project root
If you want to use the CLI and not be prompted for values every time, you can create a config file by copying the example config and filling in the values:
cp config.example.json config.jsonSet xvfb to true to keep the browser window invisible while running
CloakBrowser in headed mode. This avoids Chromium's detectable headless rendering
path. Install xorg-server-xvfb on Arch Linux (xvfb on Debian/Ubuntu) first.
For anti-bot sites, configure a residential proxy with
CLOAKBROWSER_PROXY (SOCKS5 is preferred when available). Proxy GeoIP matching
and humanized browser input are enabled automatically; set
CLOAKBROWSER_GEOIP=false only to opt out. The Web UI also exposes Xvfb mode
next to its headful-browser option.
Run the tool and follow the prompts.
bun startYou can also pass a SoundCloud track URL directly.
bun start https://soundcloud.com/artist/trackThe final MP3 file will be saved in the ./downloads directory with proper metadata and artwork embedded.
To export the followed users, liked tracks, reposted tracks, and playlists from the separate managed SoundCloud account in your .env, run:
bun manage-accThe export will be written to a timestamped directory inside ./exports and includes playlists.json with playlist track data. reposted-playlists.json is also included as an extra export.
There is now also an experimental (vibe-coded) web UI for the tool. You can start it by running
bun webuiWait for Astro to be started. It will then tell you the address it's available on, most likely http://localhost:4321.
The Web UI also listens on the local network and automatically calls the API on
port 3000 of the same host. For example, a Web UI opened at
http://192.168.1.50:4321 uses http://192.168.1.50:3000. Set
PUBLIC_API_BASE_URL when the public API uses a different host or port. If a
reverse proxy gives the Web UI a different origin, add it to the comma-separated
SC_GATE_DL_ALLOWED_ORIGINS environment variable.
Set SC_GATE_DL_DELETE_AFTER_DOWNLOAD=true on the server to remove completed
MP3, FLAC, and original files after their HTTP response has been transferred in
full. This applies to headless, Xvfb, and visible-headed jobs. Interrupted or
failed transfers retain the file so the download can be retried.
For a remotely hosted headed browser, set BROWSER_VIEW_URL to an HTTP(S)
viewer such as noVNC. The Web UI then shows a View Browser button next to
Initialize Logins. Virtual displays without GPU device access can set
SC_GATE_DL_DISABLE_GPU=true. Containers with a constrained /dev/shm can
separately set SC_GATE_DL_DISABLE_DEV_SHM=true.
This setup lets a headless server open Chromium in headed mode while you view and control it inside the sc-gate-dl Web UI. It is useful for Initialize Logins, OAuth consent, and captchas.
- A Linux host with systemd user services and a stable hostname or IP address.
- Bun and the sc-gate-dl dependencies installed for the service user.
- Xvfb,
xauth, x11vnc, and noVNC. - LAN or reverse-proxy access to the API (
3000), Web UI (4321), and noVNC (6080) ports. Keep the raw VNC port (5900) bound to localhost. - A VNC password. Traditional VNC authentication uses only the first eight password characters and does not encrypt the connection.
On Arch Linux / Arch Linux ARM, install the native packages:
sudo pacman -S --needed xorg-server-xvfb xorg-xauth x11vncInstall noVNC from your distribution, or use an upstream release in your user account:
mkdir -p ~/.local/share/sc-gate-dl
git clone --depth 1 --branch v1.7.0 https://github.com/novnc/noVNC.git \
~/.local/share/sc-gate-dl/noVNC
mkdir -p ~/.vnc
x11vnc -storepasswdInstall both dependency sets before creating the services:
cd ~/sc-gate-dl
bun install --frozen-lockfile
cd webui
bun install --frozen-lockfileCreate a private Xauthority file once. Xvfb, x11vnc, and the app service must use this same file:
mkdir -p ~/.local/state/sc-gate-dl
sh -c 'umask 077; touch "$HOME/.local/state/sc-gate-dl/xauthority"; chmod 600 "$HOME/.local/state/sc-gate-dl/xauthority"; xauth -f "$HOME/.local/state/sc-gate-dl/xauthority" add :99 . "$(mcookie)"'Add the runtime environment to the project .env. The {host} placeholder
makes the noVNC URL follow the hostname or IP address used to open the Web UI,
so the same server works through both a LAN address and Tailscale:
DISPLAY=:99
XAUTHORITY=/home/YOUR_USER/.local/state/sc-gate-dl/xauthority
XDG_SESSION_TYPE=x11
OZONE_PLATFORM=x11
SC_GATE_DL_DISABLE_GPU=true
SC_GATE_DL_DISABLE_DEV_SHM=true
BROWSER_VIEW_URL="http://{host}:6080/vnc.html?autoconnect=true&resize=scale"A fixed noVNC hostname or IP address is still supported when the viewer is reachable through only one address.
SC_GATE_DL_DISABLE_DEV_SHM is mainly useful for containers or constrained
hosts. It may be omitted when Chromium can use /dev/shm normally.
Create the following files under ~/.config/systemd/user/. Replace
YOUR_USER and /home/YOUR_USER/sc-gate-dl where shown. The examples use the
encrypted ~/.vnc/passwd produced by x11vnc -storepasswd.
sc-gate-xvfb.service:
[Unit]
Description=sc-gate-dl virtual X server
PartOf=sc-gate-dl.target
[Service]
Type=simple
ExecStart=/usr/bin/Xvfb :99 -screen 0 1920x1080x24 -nolisten tcp \
-auth /home/YOUR_USER/.local/state/sc-gate-dl/xauthority
Restart=on-failure
RestartSec=2sc-gate-x11vnc.service:
[Unit]
Description=sc-gate-dl VNC server
Requires=sc-gate-xvfb.service
After=sc-gate-xvfb.service
PartOf=sc-gate-dl.target
[Service]
Type=simple
ExecStart=/usr/bin/x11vnc -display :99 \
-auth /home/YOUR_USER/.local/state/sc-gate-dl/xauthority \
-forever -shared -localhost -usepw -rfbport 5900 -noxdamage -repeat
Restart=on-failure
RestartSec=2sc-gate-novnc.service:
[Unit]
Description=sc-gate-dl noVNC web gateway
Requires=sc-gate-x11vnc.service
After=sc-gate-x11vnc.service
PartOf=sc-gate-dl.target
[Service]
Type=simple
ExecStart=/home/YOUR_USER/.local/share/sc-gate-dl/noVNC/utils/novnc_proxy \
--listen 6080 --vnc localhost:5900
Restart=on-failure
RestartSec=2sc-gate-app.service:
[Unit]
Description=sc-gate-dl API and Web UI
Requires=sc-gate-xvfb.service
Wants=sc-gate-novnc.service
After=sc-gate-xvfb.service sc-gate-novnc.service
PartOf=sc-gate-dl.target
[Service]
Type=simple
WorkingDirectory=/home/YOUR_USER/sc-gate-dl
Environment=PATH=/home/YOUR_USER/.bun/bin:/usr/local/bin:/usr/bin
Environment=DISPLAY=:99
Environment=XAUTHORITY=/home/YOUR_USER/.local/state/sc-gate-dl/xauthority
Environment=XDG_SESSION_TYPE=x11
Environment=OZONE_PLATFORM=x11
# Comma-separated hostnames used to open the Vite-powered Web UI:
Environment=__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS=SERVER_NAME,SERVER_NAME.TAILNET.ts.net
ExecStart=/home/YOUR_USER/.bun/bin/bun webui
Restart=on-failure
RestartSec=3sc-gate-dl.target:
[Unit]
Description=sc-gate-dl remote headed browser stack
Requires=sc-gate-xvfb.service sc-gate-x11vnc.service \
sc-gate-novnc.service sc-gate-app.service
After=sc-gate-xvfb.service sc-gate-x11vnc.service \
sc-gate-novnc.service sc-gate-app.service
[Install]
WantedBy=default.targetValidate the units, enable user services at boot, and start the stack:
systemd-analyze --user verify ~/.config/systemd/user/sc-gate-*.service \
~/.config/systemd/user/sc-gate-dl.target
sudo loginctl enable-linger "$USER"
systemctl --user daemon-reload
systemctl --user enable --now sc-gate-dl.targetThe lingering user manager is required for startup before the user logs in. Check the complete stack and follow the app logs with:
systemctl --user status sc-gate-dl.target
journalctl --user -u sc-gate-app.service -fFor future application updates, only the app service needs restarting:
cd ~/sc-gate-dl
git pull --ff-only
bun install --frozen-lockfile
cd webui && bun install --frozen-lockfile && cd ..
systemctl --user restart sc-gate-app.serviceTo restart the complete display/VNC/application stack, stop and start the
target so PartOf= cleanly stops every service:
systemctl --user stop sc-gate-dl.target
systemctl --user start sc-gate-dl.targetKeep the application available on its LAN addresses and add private tailnet listeners for the API, Web UI, and noVNC gateway:
tailscale serve --bg --http=3000 http://127.0.0.1:3000
tailscale serve --bg --http=4321 http://127.0.0.1:4321
tailscale serve --bg --http=6080 http://127.0.0.1:6080
tailscale serve statusWhen Tailscale itself runs in Docker with userspace networking, run those
commands inside its container, for example docker exec tailscaled tailscale serve .... The 127.0.0.1 targets above work only when that container uses
host networking. For a bridge-mode container, add
host.docker.internal:host-gateway as an extra host and replace each target
with the container-reachable host name, for example:
extra_hosts:
- "host.docker.internal:host-gateway"docker exec tailscaled tailscale serve --bg --http=3000 http://host.docker.internal:3000
docker exec tailscaled tailscale serve --bg --http=4321 http://host.docker.internal:4321
docker exec tailscaled tailscale serve --bg --http=6080 http://host.docker.internal:6080The host services must listen on an interface reachable from the Docker bridge. Use Tailscale Serve, not Funnel: Serve is restricted to the tailnet, while Funnel publishes the service to the internet.
Vite rejects unlisted DNS hostnames even when they are private. Add the short
MagicDNS name and fully qualified tailnet name to the app service as shown
above, or place the same setting in the root .env:
__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS=SERVER_NAME,SERVER_NAME.TAILNET.ts.netDo not use server.allowedHosts: true; an explicit allowlist retains Vite's
DNS-rebinding protection. After changing the environment, reload the systemd
configuration and restart the app:
systemctl --user daemon-reload
systemctl --user restart sc-gate-app.serviceWith BROWSER_VIEW_URL using {host}, both addresses can be used without
changing the server again:
http://192.168.1.50:4321
http://SERVER_NAME:4321
If you intentionally keep a plaintext password file instead of
~/.vnc/passwd, protect it with mode 600 and use x11vnc's -passwdfile
option. Do not pass a plaintext file to -rfbauth; that option expects
x11vnc's encrypted password-file format.
The monitor icon in the top-right opens a floating browser panel without
blocking the Web UI behind it. The panel is draggable, resizable proportionally
from its corners, defaults to the remote desktop's native view size (scaled down
to fit), remembers its geometry, and automatically opens once a visible headed
gate browser has actually started or login initialization starts. Selecting
visible headed mode alone does not open it. Leaving that browser flow or
switching to another browser mode closes, disconnects, and hides the viewer.
On the first
connection, enter the VNC password and optionally select Remember on this
device. The password is stored only in that browser profile's localStorage,
never in an API request, URL, or server log. Use Forget credentials to
remove it. The remember choice itself is persisted, and turning it off removes
any saved password immediately. Closing and reopening the panel keeps the
established VNC connection. Use the header controls to zoom, disconnect, or
maximize/restore the viewer. Double-clicking the header also toggles maximized
mode, while dragging a maximized header restores the floating window.
On touchscreens, drag with one finger to move the remote pointer, tap to
left-click, hold without moving to right-click, and drag with two fingers to
pan the local view while zoomed in.
VNC authentication does not encrypt the connection. Keep port 6080 on a
trusted LAN, or put the Web UI, API, and noVNC behind an authenticated HTTPS
reverse proxy. When the Web UI uses HTTPS, BROWSER_VIEW_URL must also use
HTTPS so the embedded client connects over wss://.
If it's the first time you're running it you will need to initialize the logins by clicking the button in the footer.
You can deep-link a track with ?url= (also accepted as ?soundcloudUrl=), optional outputFormat (mp3-320, flac, or original), and optional browserMode (headless, xvfb, or headed), which pre-fills the form and starts the job. FLAC output preserves lossless sources; converting a lossy source to FLAC changes the container but cannot restore lost quality.
http://localhost:4321/?url=https://soundcloud.com/artist/track&outputFormat=mp3-320
Adds a download icon next to SoundCloud store/buy links (feed and track pages). Clicking it opens the exact Web UI in a floating, movable panel on the right (resizable from all edges) — the page behind stays usable (no dimmed overlay). Choose both output format and browser mode from the panel toolbar, or from Violentmonkey's Choose output format… and Choose browser mode… menu commands. Both choices are remembered and passed to the Web UI. Enable Always open downloads in new tab from Violentmonkey's userscript menu to bypass the modal for every download; the choice is remembered. Auto-close after the browser file download (Download MP3/Original) or Start New Download is on by default — toggle via Auto-close after browser download. Closing the panel (× / Escape) or Cancel download in the Web UI stops an in-progress job and exits the browser cleanly.
Recommended: Violentmonkey (Firefox / Chrome / Edge). Tampermonkey also works.
Or open the raw file: userscript/sc-gate-dl.user.js
- Install Violentmonkey
- Click Install userscript above (Violentmonkey will prompt to confirm)
- Start the Web UI locally:
bun webui - Browse SoundCloud — use the download icon beside the store/cart button
Chrome may ask once to allow the page to access your local network (localhost). If the panel iframe is blocked, use open in tab in the panel toolbar.
To point the userscript at another machine without developer tools, click the gear button in its panel header or choose Configure server… from Violentmonkey's userscript menu. Enter one or more complete Web UI addresses (one per line), for example:
http://192.168.178.57:4321
http://100.x.y.z:8123
Addresses are tried in order before a download opens: the first reachable server
wins, then the script falls back to the next. Reachability is checked through the
userscript bridge (GM_xmlhttpRequest), so LAN / Tailscale hosts work even when
the browser blocks page fetch to private networks (Chrome / Cromite Private
Network Access). After updating the userscript, approve the new network
permission prompt if Violentmonkey asks. Leaving the field empty resets to
localhost. The list is remembered across browser restarts.
The same setting can also be changed from the SoundCloud tab console:
localStorage.setItem(
'sc-gate-dl-webui-base',
'http://192.168.178.57:4321\nhttp://100.x.y.z:8123',
)Panel size/position is remembered in localStorage (sc-gate-dl-panel-geom).
Browserless fast path: Most Hypeddit gates (email and the social follow/like/comment/repost buttons for SoundCloud, Instagram, TikTok, YouTube and Facebook) are only verified client-side, so the tool first tries to satisfy them with plain HTTP requests and downloads the file directly, without launching a browser. This is much faster and shows live download progress in both the CLI and Web UI. If a post has a gate that needs real verification (e.g. an unskippable Spotify gate), it automatically falls back to the browser-based flow below.
Gate Handling: When the browser flow is used, the tool automatically detects and handles different Hypeddit gates:
- Email gate: Enters your name and email
- SoundCloud gate: Handles the follow/like/comment/repost buttons (This gets bypassed as Hypeddit does not actually verify the actions). The legacy OAuth "connect" flow is still handled as a fallback
- Facebook gate: Clicks the next button (Does not require any action)
- Instagram gate: Handles Instagram follow requirements (This gets bypassed as it does not actually require a follow)
- TikTok gate: Handles TikTok follow requirements (This gets bypassed as it does not actually require a follow)
- YouTube gate: Handles YouTube subscribe requirements (This gets bypassed as it does not actually require subscribing)
- Spotify gate: Authorizes Spotify access
- Download gate: Triggers the audio download
Droploud, GateRush, DownloadGater, StillHype, PumpYourSound, and MyPressKit gates are handled via their own downloaders with similar email / social unlock flows. StillHype, PumpYourSound, and MyPressKit require a real SoundCloud OAuth connection (follow / like / repost / comment are verified server-side). Traditional gate URLs in the track description are preferred over Bandcamp/SoundCloud store links in purchase_url.
Bandcamp / yt-dlp: When a SoundCloud track’s purchase URL (or description) points at Bandcamp instead of a gate, the file is downloaded with yt-dlp (browserless). For Bandcamp album links, the matching track is selected from the SoundCloud title; if auto-match fails, the CLI and Web UI let you pick a track from the album. Traditional unlock gates still take priority if both are present. If no gate or Bandcamp URL is found, the CLI and Web UI can fall back to downloading the SoundCloud track itself via yt-dlp.
Direct download: Paste a file URL (Dropbox with dl=1, Google Drive file links, or any http(s) URL ending in a common audio/archive extension). The file is fetched browserlessly — useful when a gate is unsupported but you already have the download link.
File Processing:
- Lossless (WAV/AIFF/FLAC) files: Converted to MP3 (320kbps) with metadata and artwork
- MP3 files: Retagged with metadata and artwork (no re-encoding)