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

8

Total users

0

Monthly active users

9 days ago

Last modified

Categories

Features

Limited permissions

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 recordType column, 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.
  • Comments and lyrics are optional. Turn on includeComments to add each song's public comments, with replies nested inside, to the song record. It adds no extra records and no extra charge: you pay for the same song records, and each song then needs one more request, so the run is slower. 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.

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.

FieldExample
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"
creatorIsVerifiedfalse
playCount1200
upvoteCount85
commentCount4
durationSeconds180.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..."
commentsonly with includeComments: a list of {id, userHandle, userDisplayName, text, createdAt, likeCount, trackTimestamp, replyCount, replies}; commentsComplete is false when the cap cut it short
modelVersion"v6"
isInstrumentalfalse
isRemix, hasStemsfalse
imageUrl"https://cdn0.example.com/image_00000000.jpeg"
audioUrl, videoUrl"https://cdn0.example.com/clip/00000000.m4a"
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

  1. Pick a mode: Explore sections (the curated discovery page), Playlists (paste links or ids), or Creator profiles (paste handles or links).
  2. Fill in the fields for that mode. In Creator profiles, you can also switch on reading every playlist linked on the profile.
  3. Set Max records to control run size and cost, then click Start.
  4. 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 ApifyClient
client = 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 as NEW. Every later run labels each record NEW, UPDATED (with changedFields), UNCHANGED (suppressed and not billed unless emitUnchanged is on), REAPPEARED, or EXPIRED (only after a run that scanned the whole scope, and only with emitExpired). stateKey names 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 as UPDATED. To stop chosen fields (for example playCount) from triggering UPDATED, list them in ignoreFieldsForChanges; they stay in every returned row. A playlist's description, visibility flags, creator avatar and engagement counts are not compared, because the same playlist is described differently depending on where it was reached.

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.

An EXPIRED row is rebuilt from the record stored on the earlier run, which keeps only a digest of the song lyrics and raw metadata to stay small. So on EXPIRED rows lyrics and metadataRaw are null, and changedFields is empty. Every other field shows its last known value.

Set mode to urls and paste any mix of these links into startUrls. Default changed: startUrls now ships pre-filled with one example of shapes 1 to 6, so a URL mode run with the field untouched scrapes those examples (bounded by Max records) instead of nothing. Clear the field and add your own links to scrape only those.

#Link shapeExampleWhat you get
1Playlist pagesuno.com/playlist/<id>Playlist header plus every song
2Playlist page, paginatedsuno.com/playlist/<id>?page=2Same, starting at that page
3Creator profilesuno.com/@sunoProfile record plus the creator's songs
4Creator profile with sortsuno.com/@suno?sort=created_atSame, ordered by upvote_count, created_at or play_count
5Explore pagesuno.com/exploreEvery curated Explore section
6Song pagesuno.com/song/<id>One song record
7Old app linkapp.suno.ai/playlist/<id>Read like the suno.com equivalent

Row 7 exists so links from old bookmarks keep working. Short links (suno.com/s/...), the home page and any other shape are skipped with a warning naming the link, and a run where nothing could be read fails loudly, with the reason for each skipped link (up to 10, then a count of the rest) in the failure message (a run whose links were all skipped is never reported as a connection problem). A plain handle such as suno is accepted as a profile; an unknown handle is reported as an error.

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.

  1. Authorize a connector once under Apify, Settings, API & Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
  3. For Notion, also set notionParentPageUrl to 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

ParameterTypeDefaultDescription
modestringexploreexplore, playlists, profiles, or urls. Each mode reads only its own fields below.
exploreFeedsarrayemptyExplore mode only. Section ids to read, such as trending, editorial-best-of or contests. Empty covers every curated section the discovery page currently offers.
playlistUrlsarraysamplePlaylists mode only. Playlist page links or bare playlist ids.
profileUrlsarraysampleProfiles mode only. Creator page links, @handle or a bare handle.
startUrlsarray6 samplesURL mode only. Any mix of Suno links, see the table below.
profileSortBystringupvote_countOrder of a creator's songs and playlists: upvote_count (most liked), created_at (newest first), or play_count (most played).
followProfilePlaylistsbooleanfalseProfiles mode only. After a creator's own songs, also include every public playlist listed on that profile.
includeLyricsbooleantrueInclude the full lyric sheet on every song record. Turn off for a much smaller dataset.
styleTagstringemptyKeep only songs whose style tags contain this text (case-insensitive). Filtering happens after reading, so a narrow filter reads more pages.
modelVersionstringemptyKeep only songs made with this model version (for example v4).
minPlayCountintegeremptyKeep only songs with at least this many plays.
createdAfterstringemptyKeep only songs created on or after this date (YYYY-MM-DD).
isInstrumentalstringanyyes keeps instrumentals, no keeps songs with vocals. Songs without the flag are dropped when set.
Filters apply to song rows only; playlist, profile and contest rows are not filtered. Songs removed by a filter are not returned and not billed, and they do not count toward the record cap.
includeCommentsbooleanfalseAdd each song's public comments (replies nested) as a comments list on the song record. No extra records or events.
maxCommentsPerSonginteger20Comments kept per song when comments are on (1 to 200), newest first.
maxItemsinteger20Stop after this many records across the whole run (0 = no limit). Songs, playlist headers, creator profiles and contests all count.
maxPagesinteger0Optional limit on pages read for any single playlist, profile or section (0 = no limit). A hard cap of 200 pages per source always applies, so Max records is the real limit.
resumeFromRunIdstring(none)Continue one interrupted run: its run id or dataset id. Records it already returned are skipped.
incrementalModebooleanfalseRecurring updates. Later runs of the same setup return only what changed, labelled in changeType.
stateKeystring(none)Optional name for a recurring-updates campaign, so its memory stays stable or is deliberately shared.
emitUnchangedbooleanfalseAlso return (and bill) records that did not change, labelled UNCHANGED.
ignoreFieldsForChangesarrayemptyRecurring updates only. Field names whose changes do not count as UPDATED.
emitExpiredbooleanfalseAlso return (and bill) records that are no longer found, labelled EXPIRED. Only produced by a complete run.
mcpConnectorsarray(none)Optional: send a summary of each record to apps you authorized under Integrations.
notionParentPageUrlstring(none)Notion connector only: page under which item pages are created.
maxNotifyListingsinteger50Cap (1 to 1000) on items written to each connector per run. Does not affect the dataset.
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",
"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. If your plan has no proxy access, the run continues on a backup connection and says so in the log; if no page can be loaded at all, the run ends as failed with a connection message instead of reporting an empty result.

FAQ

How much does it cost?

Billing has two events, both listed with their current rates on the Pricing tab: apify-actor-start is charged when a run starts, one event per GB of run memory with a minimum of one, and apify-default-dataset-item (shown as "Result record") is charged once for each record written to the dataset. Records that are suppressed (unchanged in recurring updates unless you ask for them), skipped or failed are not charged, and nested comments add no charge. Use Max records to cap the cost of any run.

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...
๐Ÿงฉ Deezer Scraper
Scrape Deezer by keyword or URL. Extract tracks, albums, artists, playlists, lyrics...
๐Ÿงฉ 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...
๐Ÿ“ฑ Universal Media Extractor
Extract videos, audio, and metadata from 1000+ websites including YouTube, TikTok...

๐Ÿ‘‰ Browse all abotapi scrapers

๐Ÿ’ฌ Support

  • ๐Ÿž 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 contact@abotapi.com.
  • โญ Enjoying it? A quick review on the actor page helps other users find it.
⌂ ๆข็ฝ‘ๅ€