Suno Scraper - Songs, Playlists, Creators & Lyrics
Pricing
from $1.30 / 1,000 result records
Suno Scraper - Songs, Playlists, Creators & Lyrics
Collect public Suno music data: songs with lyrics, style tags, model version, play and like counts, audio, video and cover art links, plus playlist and creator records. Choose the curated Explore sections, specific playlists, or a creator's full public catalogue.
Pricing
from $1.30 / 1,000 result records
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
2
Monthly active users
7 days ago
Last modified
Categories
Share
Suno Scraper: Songs, Playlists, Creators and Lyrics
Suno Scraper turns Suno into a clean music-catalogue dataset. Every song record carries the title, the full lyric sheet, the style prompt, the model version, play and like counts, the creator identity, and direct links to the audio, video and cover art. Point it at the curated Explore sections, at specific playlist links, or at creator handles, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.
Why This Scraper?
- Three ways in. Read the curated Explore sections, paste playlist links or ids, or paste creator handles. No need to build URLs by hand.
- Four record kinds in one dataset. Songs, playlists, creator profiles and contests share one dataset, told apart by a
recordTypecolumn, so a single run can map a whole corner of the catalogue. - 40+ fields per song. The complete lyric sheet, the style prompt, duration, model version, remix and stem availability, and the audio, video and cover art links.
- Full depth, not just the first screen. A large playlist or a prolific creator's whole public catalogue comes back complete, up to your record cap, rather than stopping at the first batch.
- One shared cap. Max records is the only limit that stops a run, and it is split fairly across the sources you asked for, so the last playlist in your list is never starved by the first.
- Lyrics are optional. Turn them off for a dataset that is a fraction of the size when you only need titles, styles and counts.
- Built for schedules. Turn on recurring updates and later runs return only what is new, updated or reappeared, each labelled in a
changeTypecolumn, so a daily job does not re-deliver the same catalogue.
Use Cases
- Music data researchers and ML teams: build lyric, style-tag and prompt datasets for text and audio generation research.
- Trend watchers: monitor the trending and editorial sections to see which styles, prompts and model versions are rising.
- Playlist archivists: export a whole playlist, songs and stats included, to catalogue or back it up.
- Creator analytics: track a creator's public catalogue, play and upvote counts, and follower growth over time.
- Contest followers: watch community contest windows, submission playlists and the base songs they remix.
Data You Get
Sample shape: values are illustrative placeholders, not from a live record.
| Field | Example |
|---|---|
recordType | "song" (also "playlist", "profile", "contest") |
id | "00000000-0000-0000-0000-000000000001" |
url | "suno.com/song/00000000-0000-0000-0000-000000000001" |
title | "Sample Song Title" |
createdAt | "2026-01-01T00:00:00.000Z" |
creatorHandle | "samplecreator" |
creatorDisplayName | "Sample Creator" |
creatorProfileUrl | "suno.com/@samplecreator" |
creatorIsVerified | false |
playCount | 1200 |
upvoteCount | 85 |
commentCount | 4 |
durationSeconds | 180.5 |
styleTags | "synth pop, driving bass, 120 BPM, male vocals" |
displayTags | ["synth pop", "dance-pop"] |
lyrics | "[Verse 1]\nSample lyric line here\n\n[Chorus]\n..." |
modelVersion | "v6" |
isInstrumental | false |
isRemix | false |
hasStems | false |
imageUrl | "https://cdn0.example.com/image_00000000.jpeg" |
audioUrl | "https://cdn0.example.com/clip/00000000.m4a" |
videoUrl | "https://cdn0.example.com/00000000.mp4" |
sourceType | "playlist" (also "section", "profile") |
scrapedAt | "2026-01-01T00:00:00Z" |
Playlist records add description, songCount, totalDurationSeconds, upvoteCount, playCount and the owning creator. Creator profile records add followersCount, followingCount, totalPlays, totalUpvotes, profileDescription and a playlists array you can feed straight back into playlists mode. Contest records add startTime, endTime, judgingStart, judgingEnd, winnersAnnouncedDate and the submissions playlist link.
How to Use
- Pick a mode: Explore sections (the curated discovery page), Playlists (paste links or ids), or Creator profiles (paste handles or links).
- Fill in the fields for that mode. In Creator profiles, you can also switch on reading every playlist linked on the profile.
- Set Max records to control run size and cost, then click Start.
- Download the dataset as JSON, CSV or Excel, or read it through the API.
Collect from the curated Explore sections (the default):
{"mode": "explore","maxItems": 50}
Pin one named section instead of every section:
{"mode": "explore","exploreFeeds": ["trending"],"maxItems": 100}
Collect from two playlists, sharing the cap between them:
{"mode": "playlists","playlistUrls": ["suno.com/playlist/0d597d0c-cdb2-4f9c-b4da-57931929f0d0","990fd5fe-70d2-449b-8a4d-3cb0a7d3e805"],"maxItems": 500}
Pull a creator's whole public catalogue plus every playlist on their profile, without lyrics:
{"mode": "profiles","profileUrls": ["@samplecreator"],"profileSortBy": "play_count","followProfilePlaylists": true,"includeLyrics": false,"maxItems": 0}
Playlist links and bare ids are both accepted, and so are @handle, a bare handle and a full creator page link.
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/suno-music-scraper").call(run_input={"mode": "explore", "maxItems": 50})for record in client.dataset(run["defaultDatasetId"]).iterate_items():print(record["recordType"], record.get("title"))
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/suno-music-scraper').call({ mode: 'explore', maxItems: 50 });const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
How the record cap is shared across sources
Max records is one budget for the whole run. When a run reads several sources (several pinned sections, several playlists, several profiles), the remaining budget is split evenly across the sources still to come, and an exhausted source hands its unused share to the ones after it. A source's own container record (a playlist or profile header) never eats the whole share of a source, so even a source whose share is one record still returns a song rather than only its own header. Raise Max records, or set it to 0, to collect everything a source holds.
Resume and recurring updates
Two separate features, and they are not interchangeable.
- Continue a previous run (
resumeFromRunId): paste an earlier run id or dataset id. Every record that run already returned is skipped, so an interrupted large collection can finish without paying for the same rows twice. - Recurring updates (
incrementalMode): for a scheduled job over the same scope. The first run returns everything asNEW. Every later run labels each recordNEW,UPDATED(withchangedFields),UNCHANGED(suppressed and not billed unlessemitUnchangedis on),REAPPEARED, orEXPIRED(only after a run that scanned the whole scope, and only withemitExpired).stateKeynames or shares the stored state; leave it empty and the memory is keyed on the run setup automatically. Play, like and comment counts move constantly on an active catalogue, so a record whose only difference is a counter still counts asUPDATED.
Once recurring updates already holds a baseline for a setup, a run that also sets resumeFromRunId is refused with a clear message: use one or the other, or pick a different stateKey.
A record is only ever reported EXPIRED after a run that reached the natural end of every source it read. A run stopped by Max records, a run that continued a previous one, a run where a source failed or was cut short, and a run that collected nothing all skip gone-record detection entirely (with emitExpired on, the run log says why), because absence proves nothing when the scan was incomplete.
Send results into your apps (MCP connectors)
Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.
What gets written to the connector: a condensed, human-readable summary of each record, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.
- Authorize a connector once under Apify, Settings, API & Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
- For Notion, also set
notionParentPageUrlto the page where items should be created.
The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | explore | explore, playlists, or profiles. Each mode reads only its own fields below. |
exploreFeeds | array | empty | Explore mode only. Section ids to read, such as trending, editorial-best-of or contests. Empty covers every curated section the discovery page currently offers. |
playlistUrls | array | sample | Playlists mode only. Playlist page links or bare playlist ids. |
profileUrls | array | sample | Profiles mode only. Creator page links, @handle or a bare handle. |
profileSortBy | string | upvote_count | Order of a creator's songs and playlists: upvote_count (most liked), created_at (newest first), or play_count (most played). |
followProfilePlaylists | boolean | false | Profiles mode only. After a creator's own songs, also include every public playlist listed on that profile. |
includeLyrics | boolean | true | Include the full lyric sheet on every song record. Turn off for a much smaller dataset. |
maxItems | integer | 20 | Stop after this many records across the whole run (0 = no limit). Songs, playlist headers, creator profiles and contests all count. |
maxPages | integer | 200 | Runaway guard: an upper bound (1 to 200) on how much is read for any single playlist, profile or section. Leave at the maximum so Max records is the only real limit. |
resumeFromRunId | string | (none) | Continue one interrupted run: its run id or dataset id. Records it already returned are skipped. |
incrementalMode | boolean | false | Recurring updates. Later runs of the same setup return only what changed, labelled in changeType. |
stateKey | string | (none) | Optional name for a recurring-updates campaign, so its memory stays stable or is deliberately shared. |
emitUnchanged | boolean | false | Also return (and bill) records that did not change, labelled UNCHANGED. |
emitExpired | boolean | false | Also return (and bill) records that are no longer found, labelled EXPIRED. Only produced by a complete run. |
mcpConnectors | array | (none) | Optional: send a summary of each record to apps you authorized under Integrations. |
notionParentPageUrl | string | (none) | Notion connector only: page under which item pages are created. |
maxNotifyListings | integer | 50 | Cap (1 to 1000) on items written to each connector per run. Does not affect the dataset. |
proxyConfiguration | object | Apify Proxy | Connection used for every request. |
Output Example
Sample shape: values are illustrative placeholders, not from a live record.
{"recordType": "song","id": "00000000-0000-0000-0000-000000000001","url": "suno.com/song/00000000-0000-0000-0000-000000000001","title": "Sample Song Title","createdAt": "2026-01-01T00:00:00.000Z","status": "complete","creatorHandle": "samplecreator","creatorDisplayName": "Sample Creator","creatorProfileUrl": "suno.com/@samplecreator","creatorIsVerified": false,"playCount": 1200,"upvoteCount": 85,"commentCount": 4,"durationSeconds": 180.5,"styleTags": "synth pop, driving bass, 120 BPM, male vocals","displayTags": ["synth pop", "dance-pop"],"lyrics": "[Verse 1]\nSample lyric line here\n\n[Chorus]\nSample chorus line here","modelName": "sample-model","modelVersion": "v6","isInstrumental": false,"isRemix": false,"canRemix": true,"hasStems": false,"isExplicit": false,"imageUrl": "https://cdn0.example.com/image_00000000.jpeg","videoUrl": "https://cdn0.example.com/00000000.mp4","audioUrl": "https://cdn0.example.com/clip/00000000.m4a","sourceType": "playlist","sourceTitle": "Sample Playlist","sourceUrl": "suno.com/playlist/00000000-0000-0000-0000-000000000003","scrapedAt": "2026-01-01T00:00:00Z"}
Plan Requirement
The actor runs on any Apify account. Suno's public catalogue answers ordinary connections, so the default proxy setting shipped in the input works without changes. Adjust it under Connection only if you have a specific reason to route requests differently.
FAQ
How much does it cost?
You pay per record returned. The Pricing tab shows the current rates. Use Max records to cap the cost of any run.
Is it legal to scrape Suno?
This actor collects only publicly available music catalogue data. You are responsible for how you use it: follow Suno's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Lyrics, audio and cover art may carry their own copyright even though the catalogue listing is public.
Can I get only new or changed songs on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Recurring updates (incrementalMode). Each run then returns only new, updated and reappeared records, and unchanged ones are not billed unless you ask for them.
Why did my run return fewer records than a playlist or profile actually holds?
Max records caps the whole run, not each source, and the remaining budget is split across every source you asked for. Raise Max records, or set it to 0, to collect a source in full.
Why did my run fail instead of returning an empty dataset?
If every requested source refused to answer, the run stops with a clear message so "this playlist is empty" is never confused with "nothing could be read". Run it again in a few minutes. If the requested sources answered but hold no public records, the run also stops, with a different message saying so, so check the playlist links, handles or section ids. The one exception is a recurring-updates run where every record was unchanged: that is a normal, successful run with nothing new to return.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration or MCP client, and use the connector field to push a summary of each record into Notion, Linear or Airtable.
🔗 Want more AI data?
Pair this actor with these related scrapers from the same team:
| 🤖 Udio Scraper Collect public Udio tracks with the complete generation prompt, full lyrics, style tags... | 🧩 Anghami Scraper Scrape Anghami's public catalog by keyword or player URL. Rows carry their kind (song... |
| 📱 TikTok Profile, Hashtag, Search, Video & Trending Scraper Scrape TikTok without login. Extract profiles, bios, follower stats and videos; search by... | 🧩 TIDAL Scraper Scrape TIDAL tracks, albums, artists, playlists and public mixes by search phrase or URL... |
| 📱 Google Play Reviews Collect Google Play reviews and ratings for any app across country storefronts. Search by... | 📱 ViewStats Scraper Scrape YouTube channel analytics from ViewStats. Look up channels by handle, URL, or... |
💬 Support & custom scrapers
- 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
- 🛠️ Need another site, extra fields or a private build? Email abotapi@proton.me or message Telegram @abotapi.
- ⭐ Enjoying it? A quick review on the actor page helps other users find it.