Anghami Scraper - Songs, Albums, Artists & Playlists
Pricing
from $1.70 / 1,000 catalog records
Anghami Scraper - Songs, Albums, Artists & Playlists
Scrape Anghami's public catalog by keyword or player URL. Rows carry their kind (song, album, artist, playlist, tag) with title, artist, plays, followers, podcast flags and artwork. Detail views add the description and a podcast episode list, one per-record toggle.
Pricing
from $1.70 / 1,000 catalog records
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
Anghami Scraper: Songs, Albums, Artists, Playlists and Podcasts
Anghami Scraper turns Anghami, the MENA region's leading music and podcast streaming service, into structured catalog data. Get songs, albums, podcast episodes, audiobooks, artist profiles, curated playlists and the category tags behind genre and chart pages, with every row carrying its own kind alongside a unified core shape (title, artist, plays, likes, followers, artwork). Search by keyword for a catalog-wide sweep, or paste player URLs to walk one artist's discography, a playlist, a tag, or fetch a single song or album, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.
Why This Scraper?
- Full catalog coverage. Songs, albums (including podcast and audiobook objects), artists, curated playlists and category tags, in one unified record shape.
- Every row reports its own kind. A mixed search feed filters cleanly in downstream code, and carries play counts, likes, follower counts, verified and podcast flags straight from the feed.
- Two ways in. Keyword search for catalog-wide sweeps, or paste player URLs to walk one artist's full discography, a playlist, a genre or chart tag, or fetch a single song or album object.
- Detail view on demand. A per-record toggle adds the store page description and, for album objects, the complete song and episode id list, charged once per record.
- Built for recurring monitoring. Incremental mode reports NEW, UPDATED, REAPPEARED and EXPIRED records for scheduled runs, and Resume continues an interrupted or capped run without paying twice.
- MCP connector export. Pipe results into Notion, Linear, Airtable or another app you already use.
- Clean dataset contract. A stable record identity (
kind:id), canonical URL and artwork URL on every row, so downstream systems can join and dedupe reliably.
Use Cases
- Music discovery apps and playlist tools: track new releases, charting songs and curated playlist changes across the MENA catalog.
- Artist and label monitoring: watch one artist's discography, play counts and follower growth over time with incremental mode.
- Podcast and audiobook research: collect podcast episodes and audiobook objects, with their own flags and descriptions, separately from music.
- Market and catalog analytics: build datasets of genres, tags and category collections for streaming trend analysis.
- Data migration and cataloging: pull structured song, album and artist metadata (ids, artwork, duration) into a companion app or database.
Data You Get
Sample shape: values are illustrative placeholders, not from a live record.
| Field | Example |
|---|---|
recordId | "song:0000000" |
kind | "song" (also "album", "artist", "playlist", "tag") |
id | "0000000" |
url | "https://play.anghami.com/song/0000000" |
title / name | "Sample Song Title" (song/album/playlist/tag rows use title, artist rows use name) |
artist / artistId | "Sample Artist" / "000000" |
album / albumId | "Sample Album Title" / "0000000000" |
durationSec | 228 |
year / releasedate | 2026 / "2026-01-01" |
genre | "Pop - Sample" |
plays / likes | 13000000 / 120000 |
followers | 17600000 (artist and playlist rows) |
nbrSongs / itemCount | 100 (album/podcast song count) / 42 (playlist item count) |
isPodcast / isAudiobook | false / false |
isPodcaster | false (artist rows) |
verified / explicit | true / false |
lyrics | true (song rows, lyrics availability flag) |
coverArt / imageUrl | "https://artwork.anghcdn.co/webp/?id=000000000&size=400" |
keywords | ["Sample Song Title", "Sample Artist"] |
description / webTitle / webDescription | detail-view extras (Fetch record details on) |
curator / songIds | "Anghami Editorial" / ["0000000000", "0000000001"] (album objects, detail toggle on) |
changeType / changedFields | "NEW" / [] (incremental mode) |
scrapedAt / firstSeenAt / lastSeenAt | "2026-01-01T00:00:00Z" (incremental mode adds the latter two) |
detailCarriedForward | true (a failed detail re-read repaired from the previous run's snapshot) |
How to Use
- Pick a mode:
search(by keyword) orurl(paste player URLs). - Fill in the search terms or URLs, and narrow with Kinds to keep or Exclude podcasts if needed.
- Turn on Fetch record details for the description and song/episode id list, and set Max items to control run size and cost.
- Click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.
Search by keyword:
{"mode": "search","searchTerms": ["Sample Artist"],"maxItems": 50}
Music only, from a search:
{"mode": "search","searchTerms": ["sample new releases"],"kinds": ["song", "album"],"maxItems": 100}
Walk an artist's catalog (URL mode):
{"mode": "url","urls": ["https://play.anghami.com/artist/000000"],"maxItems": 100}
Paste a playlist, category tag or album URL the same way; each URL decides its own scope. A link Anghami clearly declines (removed, not available in the country, or sign-in only) is logged and skipped, whatever its kind. One known limitation when you paste several URLs together: if a song or album link keeps failing at the connection level after every retry, the run stops reading at that link, and every URL listed after it is not read at all. If earlier URLs already returned records, the run still ends as succeeded with only those records (the log shows "Could not reach the data source" after the last "Source N/M" line); if nothing was collected yet, the run fails with a connection message. Artist, playlist and tag links do not have this limitation: a failing one is recorded and the run moves on to the next URL. To be safe, list song and album links last or run them on their own, and check that every "Source N/M" line appears in the log.
Recurring monitoring (incremental mode):
{"mode": "url","urls": ["https://play.anghami.com/artist/000000"],"incrementalMode": true,"emitUnchanged": false}
Run it on a schedule: the first run marks everything NEW, later runs report only the changes (play counts and follower moves included as UPDATED).
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/anghami-catalog-scraper").call(run_input={"mode": "search", "searchTerms": ["Sample Artist"]})for record in client.dataset(run["defaultDatasetId"]).iterate_items():print(record["kind"], record.get("title") or record.get("name"))
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/anghami-catalog-scraper').call({mode: 'search', searchTerms: ['Sample Artist'],});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
How Max items and Max pages shape a run
Max items is the single cap on a run: the walk stops once that many records have been returned, with the budget split evenly across your search terms and URLs. Max pages is a safety bound on how many pages of one source get walked; leave it at 0 and only Max items decides when to stop. A run that stops before every source ran out of results is incomplete for that source, and Incremental mode will not mark anything EXPIRED off an incomplete run. This cap does not, however, apply to EXPIRED rows themselves: once a run has genuinely scanned a tracked search's whole scope, every previously tracked record found missing is returned as EXPIRED regardless of Max items, so a large monitored scope where many records have disappeared can return, and bill, far more rows in that run than Max items would suggest.
Resume and recurring updates
- Resume (
resumeFromRunId) continues one interrupted or capped run: paste its run or dataset ID and the actor skips every record it already collected there, so you don't pay twice. This only works against a previous run of this same actor: if the pasted id resolves to a dataset whose rows carry norecordIdfield (an unrelated dataset, or a run from a different actor), Resume finds nothing to skip and quietly re-scrapes, and re-bills, everything from zero. Check the run log line "Resume: skipping N record(s)" after a resumed run; if N is 0 and you expected a skip, the pasted id does not match. - Incremental mode (
incrementalMode) is for scheduled runs over the same search or URL. Each record is classifiedNEW,UPDATED(play or follower moves count as changes, withchangedFields),UNCHANGED(suppressed and not billed unlessemitUnchangedis on),REAPPEAREDorEXPIRED(only after a run that scanned the whole tracked scope, and only withemitExpired).stateKeynames or shares the stored state. With incremental mode off, output is exactly as before. - Give incremental runs room: set Max items to
0or well above one page per source. Max items is applied to each page before unchanged records are set aside, so when the remaining budget is smaller than a page (about 15 search results), unchanged records at the top of that page can use it up and new records further down the same page are left out of the run. The run then reports nothing changed, and on the next scheduled run the same layout can hide them again. Watch for this with a small Max items, or with several search terms or URLs sharing one (the budget is split between them). - Resume and Incremental mode together only work on the first run of a campaign: if the state key already has tracked records, the run stops with a message instead. On that first run, records skipped through Resume are tracked without their values, so the next scheduled run reports each of them once as
UPDATED(listing every field as changed) even if nothing moved; from then on they behave normally.
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 > 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 records 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 | search | search (keyword search) or url (paste player URLs). |
searchTerms | array | ["Sherine"] | Keywords to search. Search mode only; each term is scraped independently. |
urls | array | sample | Player URLs: artist, song, album, playlist or category tag pages. URL mode only; each URL decides its own scope. |
kinds | array | (none) | Keep only rows of these kinds (song, album, artist, playlist, tag). Empty keeps all kinds. Applies in both modes; a pasted song or album URL is returned in full regardless. |
excludePodcasts | boolean | false | Drop rows flagged as podcast episodes, in both modes. A pasted song or album URL is returned in full regardless. |
fetchDetails | boolean | false | Fetch each song's or album's own detail view: description, curator and (for albums) the song/episode id list. Charged once per record. |
maxItems | integer | 20 | Stop after this many records across all search terms and URLs. 0 = unlimited. |
maxPages | integer | 0 | Safety bound on pages walked per search term or URL. 0 = no page limit (Max items still applies). |
resumeFromRunId | string | (none) | Continue an interrupted or capped run, skipping records it already collected. |
incrementalMode | boolean | false | Recurring monitoring: return only NEW, UPDATED and REAPPEARED records on later runs of the same search. |
stateKey | string | (none) | Name or share an incremental-mode monitoring campaign. Auto-derived from the search terms, URLs and filters when left empty. |
emitUnchanged | boolean | false | Also return (and bill) unchanged records, marked UNCHANGED. |
emitExpired | boolean | false | Also return (and bill) records no longer found, marked EXPIRED. Only produced after a complete scan of the tracked scope. |
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 record pages are created. |
maxNotifyListings | integer | 50 | Cap on records written to each connector per run. |
proxy | object | Apify Proxy | Connection settings. Leave the default unless a run reports it could not read any results. |
Output Example
Sample shape: values are illustrative placeholders, not from a live record.
{"recordId": "song:0000000000","kind": "song","id": "0000000000","url": "https://play.anghami.com/song/0000000000","coverArt": "https://artwork.anghcdn.co/webp/?id=000000000&size=400","title": "Sample Song Title","artist": "Sample Artist","artistId": "000000","album": "Sample Album Title","albumId": "0000000000","durationSec": 228,"year": 2026,"releasedate": "2026-01-01","genre": "Pop - Sample","plays": 13011686,"likes": 120000,"lyrics": true,"explicit": false,"isPodcast": false,"isAudiobook": false,"keywords": ["Sample Song Title", "Sample Artist"],"scrapedAt": "2026-01-01T00:00:00Z","changeType": "NEW","changedFields": [],"firstSeenAt": "2026-01-01T00:00:00Z","lastSeenAt": "2026-01-01T00:00:00Z"}
Plan Requirement
The default proxy setting works out of the box, and the actor rotates connections automatically when one is refused. For large or frequent runs, the residential proxy group gives more headroom; pick it under Connection.
FAQ
How much does it cost?
You pay per record returned, with the detail view billed only when Fetch record details is on. Incremental mode's EXPIRED rows are billed too, and are not limited by Max items once a run is eligible to detect them (see How Max items and Max pages shape a run). The Pricing tab shows current rates; use Max items to cap the cost of an ordinary run.
Is it legal to scrape Anghami?
This actor collects only publicly available catalog data from Anghami's anonymous, no-login surface. You are responsible for how you use it: follow Anghami's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Track and album metadata are generally facts, but artwork, descriptions and curated playlist text may be subject to third-party rights.
Can I get only new or changed catalog entries on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new, updated and reappeared records, and unchanged ones are not billed by default.
Why did my run return fewer records than the page seemed to have?
Anghami's search feed interleaves songs, albums, artists, playlists and tags in one list, so the Kinds to keep and Exclude podcasts filters are applied after the fact to the rows this run reads; a narrow filter combined with a small Max items can leave a page mostly filtered out. Two more cases return fewer than Max items: with several search terms or URLs, a record cut from one source by its share of the budget is not returned when a later source lists it again; and in Incremental mode, unchanged records can use up a small budget (see Resume and recurring updates). Widen the kinds filter, or raise Max items.
Why did my run fail instead of returning an empty dataset?
If Anghami refuses every request, the run stops with a clear message so "nothing matched" is never confused with "nothing could be read". The same connection message appears if a pasted song or album link keeps failing at the connection level before any record was collected: the run stops at that link instead of moving on to the remaining URLs (see How to Use; if earlier URLs already returned records, the run instead succeeds with only those). Run it again in a few minutes, or put song and album links last or in their own run.
Does Resume always pick up where I left off?
Only when the pasted run or dataset ID is a previous run of this same actor. If it resolves to an unrelated dataset, Resume silently finds nothing to skip and the run re-scrapes, and re-bills, everything; check the "Resume: skipping N record(s)" log line to confirm it actually matched.
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 results into Notion, Linear or Airtable.
π More scrapers you might like
Pair this actor with these related scrapers from the same team:
| π§© TIDAL Scraper Scrape TIDAL tracks, albums, artists, playlists and public mixes by search phrase or URL... | π§© Deezer Scraper Scrape Deezer by keyword or URL. Extract tracks, albums, artists, playlists, lyrics... |
| π€ Suno Scraper Collect public Suno music data: songs with lyrics, style tags, model version, play and... | π§© TuneIn Scraper Scrape TuneIn by keyword, category, genre, location or URL. Extract stations and podcasts... |
| π€ Udio Scraper Collect public Udio tracks with the complete generation prompt, full lyrics, style tags... | π§© PineDrama Scraper Scrape the PineDrama short-drama catalogue: series with watch counts, episode counts... |
π 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.