Anghami Scraper at a glance
Anghami Scraper is a ready-to-run Apify actor from abotapi for collecting web data. Its documented output includes id, kind, title, name and artist, which you can export as JSON, CSV or Excel or read through the Apify API. It costs $2.00 per 1,000 results on the Apify Free plan and from $1.70 on paid plans, with smaller per-run or optional feature charges listed on Apify.
- Runs on
- Apify cloud: console, API, schedules and integrations
- Data type
- Web data
- Pricing
- $2.00 per 1,000 results (Free plan), from $1.70 on paid plans
- Output
- Documented below · JSON, CSV, Excel
- Inputs
- 22 options
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.
What Anghami Scraper can do
- 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.
Choose what to collect
These inputs let you configure Anghami Scraper - Songs, Albums, Artists & Playlists. Open the actor on Apify to enter your values and review the current options.
| Input | What it controls |
|---|---|
modestring · required | How to start the scrape. 'search' runs catalog searches. 'url' processes the player URLs you paste: each URL's own kind decides the scope, paginated kinds walk forward, and a pasted song or album URL is the one exception and returns that single object in full. The kind filter below applies to the rows this run reads in both modes. |
searchTermsarray | One or more things to search Anghami's catalog for, for example 'Sherine', 'Amr Diab', a podcast name or an audiobook title. Each term is scraped independently. Search mode only: in URL mode the scope is read out of each pasted URL instead. |
urlsarray | Paste player URLs: artist pages (https://play.anghami.com/artist/000000, the /artist// form works too), song pages, album pages, playlist pages (https://play.anghami.com/playlist/-), category tag pages (https://play.anghami.com/tag/, the curated collections behind genre and chart tags), and search pages (https://play.anghami.com/search/, read as a keyword search). A pasted URL decides its own scope. Add &page=3 to start a paginated walk further in; songs and albums are single detail objects and ignore paging. |
kindsarray | Only keep records of these kinds (song, album, artist, playlist, tag), one per line. Leave empty for all kinds. Applied to the rows this run reads, in BOTH search mode and URL mode. A pasted song or album URL is the one exception: the object you pasted is returned in full regardless of this filter. |
excludePodcastsboolean | Off by default. On: rows flagged as podcast episodes are dropped from the results, in BOTH search mode and URL mode. Podcast episodes arrive both as song rows carrying the podcast flag and as the podcast object itself (an album-kind row with its own podcast flag); this filter drops both. A pasted song or album URL is the one exception: the object you pasted is returned in full regardless of this filter. |
excludeAudiobooksboolean | Off by default. On: song and album rows flagged as audiobook content are dropped. Applied to the rows this run reads, in BOTH search mode and URL mode; every other row (artists, playlists, category tags, and songs or albums not flagged as audiobooks) is kept. A pasted song or album URL is the one exception: the object you pasted is returned in full regardless of this filter. |
explicitOnlyboolean | Off by default. On: only rows flagged explicit are kept. Applied to the rows this run reads, in BOTH search mode and URL mode; rows that do not carry the field are dropped when the filter is set. A pasted song or album URL is the one exception: the object you pasted is returned in full regardless of this filter. |
Show 15 more inputs
| Input | What it controls |
|---|---|
yearFrominteger | Keep rows with a release year at or after this year (songs and albums carry a year). Applied to the rows this run reads, in BOTH search mode and URL mode; rows that do not carry the field are dropped when the filter is set. A pasted song or album URL is the one exception: the object you pasted is returned in full regardless of this filter. |
yearTointeger | Keep rows with a release year at or before this year. Applied to the rows this run reads, in BOTH search mode and URL mode; rows that do not carry the field are dropped when the filter is set. A pasted song or album URL is the one exception: the object you pasted is returned in full regardless of this filter. |
genrestring | Keep rows whose genre text contains this value, case-insensitive (song rows carry a genre). Applied to the rows this run reads, in BOTH search mode and URL mode; rows that do not carry the field are dropped when the filter is set. A pasted song or album URL is the one exception: the object you pasted is returned in full regardless of this filter. |
fetchDetailsboolean | Fetch each song's or album's own detail view: the store page title and description, the curator of a playlist-style album object, and for an album object the full song/episode id list (a podcast object's episodes). Slower, and charged once per record. One exception: a pasted song or album URL in URL mode is NOT charged this fee, since its object's own page was read because you pasted it. Leave off for a fast crawl: the listing fields are included either way. |
maxItemsinteger | The single cap on this run: stop after collecting this many records across all search terms and URLs. Set 0 for unlimited. |
maxPagesinteger | Safety bound on how many result pages to walk per search term or URL. Leave empty (0) for no page limit: the run then stops at Max items, not here. Does not impose a separate cap below Max items. |
resumeFromRunIdstring | Paste a previous run ID or dataset ID to continue a large crawl without returning or charging for records already collected there. Use this after an interrupted or capped run. For recurring monitoring of the same search, use Incremental mode below instead. |
incrementalModeboolean | Turn this on for daily or weekly recurring monitoring of the same search, for example a new-release watch. The first run returns everything matching as NEW. Later runs normally return only NEW, UPDATED and REAPPEARED records. Every output field except scrapedAt and detailCarriedForward is compared, so play count, like and follower moves ARE reported as UPDATED (list them under Ignore fields when detecting changes to stop that). Turn on Emit unchanged or Emit expired only when you also want those rows returned (and billed). State is kept separately per search, URL and filter setup; use State key to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above. |
stateKeystring | Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently configured runs. Leave empty to let the actor derive a key automatically from the search terms, URLs and filters, so two different searches never mix state. |
emitUnchangedboolean | Off by default. Turn on to also return records that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have, so leave it off unless you specifically want a full snapshot every run. |
emitExpiredboolean | Off by default. Turn on to also return records that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search: not when Max items capped it, not when Resume was used, and not when the run was refused. This returns, and bills, extra synthetic rows, so leave it off unless you need expiry tracking. |
ignoreFieldsForChangesarray | Optional. Field names to leave out of UPDATED change detection (the fields stay in the output). Built in: only scrapedAt and detailCarriedForward are always ignored. Everything else is compared, including plays, likes, followers, followerCount, itemCount, nbrSongs, coverArt, imageUrl and songIds. Add names such as plays, likes, followers or artist_plays to stop counter moves alone from producing an UPDATED row. Dotted names reach nested values. Changing this list never causes a one-time wave of UPDATED rows, because stored records are re-compared with the current list. |
mcpConnectorsarray | Optionally send results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify, Settings, API & Integrations, then select it here. Notion gets a page per record; other connectors get a best-effort write or digest. Each connector receives a condensed summary per record, not the full record; the complete record always stays in the dataset. Leave empty to skip; this never changes the dataset output. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com). |
notionParentPageUrlstring | URL or id of the Notion page under which record pages are created. Required to enable the Notion export; ignored by other connectors. |
maxNotifyListingsinteger | Cap on records written to each connector per run. Does not affect the dataset. |
Fields in the output
The documented dataset includes the fields below. Availability can depend on the source page and selected mode.
recordIdID (text)kindKind (text)titleTitle (text)nameName (text)artistArtist (text)artistIdArtist id (text)albumAlbum (text)albumIdAlbum id (text)durationSecDuration (s) (number)yearYear (number)releasedateRelease date (date)genreGenre (text)Show 21 more fields
playsPlays (number)likesLikes (number)followersFollowers (number)nbrSongsSongs / episodes (number)isPodcastPodcast (text)isAudiobookAudiobook (text)isPodcasterPodcaster (artist) (text)verifiedVerified (text)explicitExplicit (text)descriptionDescription (text)curatorCurator (text)songIdsSong / episode ids (array)keywordsKeywords (array)coverArtArtwork (image)urlURL (link)changeTypeChange type (incremental mode) (text)changedFieldsChanged fields (incremental mode) (array)firstSeenAtFirst seen (incremental mode) (date)lastSeenAtLast seen (incremental mode) (date)webTitleWeb title (text)webDescriptionWeb description (text)Example output
An example from this actor’s documentation. Values are illustrative; this is not a fresh live result.
{
"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"
}Ways to use this data
- 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.
Before you run
Start with a small input and check the resulting records against your expected fields. Source content and actor options can change; the current Apify listing is the reference for availability and pricing.
Questions about this actor
What data does Anghami Scraper return?
The documented output for Anghami Scraper includes id, kind, title, name, artist, artist id, album and album id. Availability of each field depends on the source page and the selected mode.
How much does Anghami Scraper cost?
It costs $2.00 per 1,000 results on the Apify Free plan and from $1.70 on paid plans, with smaller per-run or optional feature charges listed on Apify. The Apify listing shows the current rate for every plan.
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.
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.
