Suno Scraper - Songs, Playlists, Creators & Lyrics avatar

Suno Scraper - Songs, Playlists, Creators & Lyrics

Pricing

from $1.30 / 1,000 result records

Go to Apify Store
Suno Scraper - Songs, Playlists, Creators & Lyrics

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

Abot API

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

Categories

Share

Suno Scraper: Songs, Playlists, Creators and Lyrics

Pull public music data from Suno (suno.com) into a clean, flat 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, the video and the cover art. Point the actor at the curated discovery sections, at any public playlist, or at a creator handle, and it returns records up to the cap you set.

Why this scraper

  • Four record kinds in one dataset: songs, playlists, creator profiles and contests, told apart by a recordType column, so a single run can map a whole corner of the catalogue.
  • 40+ fields per song, including the complete lyric sheet, the style prompt, duration, model version, remix and stem availability, and the audio, video, cover and preview links.
  • Three ways in: the curated discovery sections, a list of playlist links, or a list of creator handles. Creator mode can optionally follow every playlist linked on that profile.
  • Full depth, not just the first screen: a large playlist or a prolific creator's catalogue comes back complete, up to your record cap, rather than stopping at the first batch.
  • One predictable cap: maxItems is the only limit that stops a run, and it is shared 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 changeType column, so a daily job does not re-deliver the same catalogue.
  • Interrupted runs can be continued: paste the previous run id and the records it already returned are skipped.
  • Pay per result: you are billed for the records you receive, not for time spent.

Data you get

Sample shape: values are illustrative placeholders, not from a live record.

FieldExample
recordTypesong
id00000000-0000-0000-0000-000000000001
urlsuno.com/song/00000000-0000-0000-0000-000000000001
titleSample Song Title
createdAt2026-01-01T00:00:00.000Z
creatorHandlesamplecreator
creatorDisplayNameSample Creator
creatorProfileUrlsuno.com/@samplecreator
creatorIsVerifiedfalse
playCount0
upvoteCount0
commentCount0
durationSeconds180.0
styleTagssynth pop, driving bass, 120 BPM, male vocals
displayTags["synth pop", "dance-pop"]
lyrics[Verse 1]\nSample lyric line here\n\n[Chorus]\n...
modelNamesample-model
modelVersionv6
isInstrumentalfalse
isRemixfalse
canRemixtrue
hasStemsfalse
isExplicitfalse
imageUrlhttps://cdn0.example.com/image_00000000.jpeg
audioUrlhttps://cdn0.example.com/clip/00000000.m4a
videoUrlhttps://cdn0.example.com/00000000.mp4
playlistPosition0
sourceTypeplaylist
sourceTitleSample Playlist
scrapedAt2026-01-01T00:00:00Z

Playlist records add description, songCount, totalDurationSeconds, upvoteCount, playCount and the owning creator. Creator 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

Collect from the curated discovery sections (the default):

{
"mode": "explore",
"maxItems": 50
}

Pin one named section instead of all of them:

{
"mode": "explore",
"exploreFeeds": ["trending"],
"maxItems": 100
}

Collect from two playlists, sharing the cap between them:

{
"mode": "playlists",
"playlistUrls": [
"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.

Input parameters

ParameterTypeDefaultDescription
modestringexploreexplore, playlists or profiles. Each mode reads only its own fields.
exploreFeedsarrayemptyExplore mode only. Section ids to read. Empty means every section the discovery page currently offers.
playlistUrlsarrayemptyPlaylists mode only. Playlist page links or bare playlist ids.
profileUrlsarrayemptyProfiles mode only. Creator page links, @handle or a bare handle.
profileSortBystringupvote_countOrder of a creator's songs and playlists: upvote_count, created_at or play_count.
followProfilePlaylistsbooleanfalseProfiles mode only. After the creator's own songs, also include every public playlist listed on that profile.
includeLyricsbooleantrueInclude the full lyric sheet on every song record.
maxItemsinteger50The single record cap for the whole run. 0 means no limit.
maxPagesinteger200Runaway guard: an upper bound on how much is read for any one playlist, profile or section.
resumeFromRunIdstringemptyRun id (or dataset id) of an earlier run of this Actor to continue. Records that run returned are skipped.
incrementalModebooleanfalseRecurring monitoring. Later runs of the same setup return only what changed, labelled in changeType.
stateKeystringemptyOptional name for a monitoring campaign, so its memory stays stable or is deliberately shared.
emitUnchangedbooleanfalseAlso return records that did not change, labelled UNCHANGED. Returns and bills extra rows.
emitExpiredbooleanfalseAlso return records that are no longer found, labelled EXPIRED. Only produced by a complete run.
mcpConnectorsarrayemptyOptional. Send results into your apps after the scrape.
notionParentPageUrlstringemptyOptional. Notion page under which item pages are created.
maxNotifyListingsinteger50Optional. Cap on items written to each connector.
proxyConfigurationobjectApify ProxyConnection 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",
"entityType": "song_schema",
"creatorHandle": "samplecreator",
"creatorDisplayName": "Sample Creator",
"creatorUserId": "00000000-0000-0000-0000-000000000002",
"creatorProfileUrl": "suno.com/@samplecreator",
"creatorAvatarImageUrl": "https://cdn0.example.com/00000000.jpeg",
"creatorIsVerified": false,
"playCount": 0,
"upvoteCount": 0,
"dislikeCount": null,
"commentCount": 0,
"flagCount": 0,
"durationSeconds": 180.0,
"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,
"generationType": "gen",
"isPublic": true,
"isExplicit": false,
"allowComments": true,
"hasHook": false,
"isContestEntry": false,
"imageUrl": "https://cdn0.example.com/image_00000000.jpeg",
"imageLargeUrl": "https://cdn0.example.com/image_large_00000000.jpeg",
"videoUrl": "https://cdn0.example.com/00000000.mp4",
"audioUrl": "https://cdn0.example.com/clip/00000000.m4a",
"mediaUrls": [
{ "url": "https://cdn0.example.com/clip/00000000.m4a", "content_type": "m4a-opus" }
],
"albums": [],
"playlistCaption": null,
"playlistAddedAt": "2026-01-01T00:00:00.000Z",
"playlistPosition": 0,
"sourceType": "playlist",
"sourceId": "00000000-0000-0000-0000-000000000003",
"sourceTitle": "Sample Playlist",
"sourceUrl": "suno.com/playlist/00000000-0000-0000-0000-000000000003",
"metadataRaw": { "duration": 180.0, "tags": "synth pop, driving bass" },
"scrapedAt": "2026-01-01T00:00:00Z"
}

Recurring updates and continuing a run

Two separate features, and they are not interchangeable.

Continue a previous run. Paste an earlier run id (or dataset id) into resumeFromRunId. Every record that run already returned is skipped, so an interrupted large collection can finish without paying for the same rows twice.

Recurring updates. Turn on incrementalMode for a scheduled job. The first run returns everything as NEW. Every later run of the same setup compares against what it saw last time and labels each record:

changeTypeMeaning
NEWFirst time this record has been seen for this setup.
UPDATEDSeen before, and something on it changed. changedFields names what.
UNCHANGEDSeen before and identical. Withheld by default; set emitUnchanged to receive it.
REAPPEAREDWas reported gone, and is back.
EXPIREDWas there before and is no longer found. Set emitExpired to receive it.

Two things worth knowing before you schedule it:

  • Play, like and comment counts move constantly on an active catalogue, so a record whose only difference is a counter still counts as UPDATED. Records are compared on their content; the collection time and which section they were reached through are ignored.
  • Records are only ever reported as EXPIRED by a run that covered its whole setup. A run stopped by the record cap, a run that continued a previous one, a run where a source did not finish, and a run that collected nothing all skip gone-record detection entirely, and say so in the log. That is deliberate: absence proves nothing when the run was cut short.

Set stateKey to name a campaign. Leave it empty and the memory is keyed on the run setup automatically, so two differently configured schedules never overwrite each other.

Send results into your apps (MCP connectors)

Results can optionally be piped into apps you already use, through Model Context Protocol connectors, as a delivery step after the scrape. Authorize a connector under Apify, Settings, API and Integrations, then select it in the mcpConnectors field of the input. For Notion, also set notionParentPageUrl to the page under which item pages should be created; maxNotifyListings caps how many items are written to each connector.

What arrives in the connector is a condensed, human readable summary per item: a title plus the key fields flattened to plain text. Nested objects collapse to their main value and arrays are trimmed to a few entries. The complete record always stays in the Apify dataset, which is never changed by this step. Leaving mcpConnectors empty skips the export entirely.

Plan requirement

The actor runs on any Apify account. It uses the standard Apify Proxy setting shipped in the input, which is available on every plan; you can change it if you have a reason to.