JioHotstar Scraper - Movies, Shows, Sports & Episodes avatar

JioHotstar Scraper - Movies, Shows, Sports & Episodes

Pricing

from $1.70 / 1,000 catalog records

Go to Apify Store
JioHotstar Scraper - Movies, Shows, Sports & Episodes

JioHotstar Scraper - Movies, Shows, Sports & Episodes

Scrape the JioHotstar catalog by content type or URL. Extract shows, movies, episodes, sports, clips and live content, with one structured record per catalog URL including title, show name, content IDs and source URL.

Pricing

from $1.70 / 1,000 catalog records

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

1

Bookmarked

3

Total users

0

Monthly active users

a day ago

Last modified

Categories

Features

Limited permissions

Share

JioHotstar Scraper: Catalog URLs, Titles, Show & Episode IDs

JioHotstar Scraper turns the hotstar.com catalog into a clean dataset of shows, movies, episodes, sport pages, clips, channels, genres and languages. It reads the catalog dataset the platform itself publishes (the sitemap URL lists linked from its own robots.txt), so it needs no login and no session of any kind. Walk a whole catalog type page by page, or paste content URLs one at a time, then export to JSON, CSV or Excel, or pull the results straight into your app through the API. Recurring change tracking (what got added or removed) is built in.

Why This Scraper?

  • One record per catalog URL. The row kind, humanized title, parent show title, show id and content id are all read straight from the URL the platform itself publishes for its index, so there is no guessing about what a page might contain.
  • Walk the catalog by type. Episodes, shows, movies, sport landings, live pages, clips, channels, genres and languages are all selectable, and the episode surface alone carries hundreds of thousands of rows.
  • Anonymous by design. The catalog list is public: no account, no session, no cookie jar. What sits behind a login (playback, descriptions, durations, reviews) is out of scope on purpose, so a run never fails because a session expired.
  • Stable, resolvable identity. Every record is a real URL you or your own systems can revisit, join against, or fetch again later.
  • Built for change tracking. Incremental mode remembers a previous walk of the same catalog scope: the first run returns everything as new, later runs return only what the platform added or dropped.
  • Resume a capped or interrupted walk. Point a new run at a previous run id and it skips everything already collected there, so a very large catalog type does not have to be paid for twice.
  • Optional MCP export. Pipe a summary of each record into Notion, Linear, Airtable or Apify without changing what lands in the dataset.

Use Cases

  • Streaming catalog monitoring: track what the platform adds or removes, by show, movie or episode, on a recurring schedule.
  • App and index builders: power your own search or deep-link feature with a lightweight id and title index instead of maintaining your own catalog crawl.
  • Content research and archiving: build a historical record of what was listed, and when a title disappeared from the catalog.
  • Catalog QA teams: confirm that a newly published show or episode URL is actually listed in the site's own catalog before announcing it elsewhere.
  • Data pipelines and joins: feed stable show and content ids into a downstream system that already tracks the same titles by name.

Data You Get

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

FieldExample
recordId"1000200000" (the episode, show or movie's own numeric id)
recordId (no numeric segment)"slug:cricket" (sport, genre, language and channel landing pages)
urlthe catalog URL itself, kept exactly as published
kind"episode" (also "show", "movie", "sport", "sport_match", "clip", "live_tv", "category", "channel", "genre", "language"). News live /watch pages stay "episode". The CHANNELS, GENRES, LANGUAGES and HOME_PAGE_TRAYS catalog types return "category" rows (see below)
title (episode row)"Sample Episode Title"
title (show or movie row)"Sample Show Name" (the show's or movie's own title)
showTitle (episode row)"Sample Show Name" (the parent show)
showTitle (show or movie row)same value as title, no separate parent
showId (episode row)"500000" (the parent show's numeric id)
showId (show or movie row)same value as contentId, no separate parent
contentId"1000200000" (the row's own numeric id, same value as recordId)
scrapedAt"2026-01-01T00:00:00Z"
changeType"NEW" (also "UPDATED", "UNCHANGED", "REAPPEARED", "EXPIRED"; incremental mode only)
changedFields[] (incremental mode only)
firstSeenAt"2026-01-01T00:00:00Z" (incremental mode only)
lastSeenAt"2026-01-01T00:00:00Z" (incremental mode only)

changedFields, firstSeenAt and lastSeenAt are populated only when Incremental mode is on. Landing-page URLs with no numeric id segment (for example a sport, genre or language landing) get a slug: record id and carry null for showTitle, showId and contentId.

How to Use

  1. Pick a mode: sitemap (walk a catalog type) or url (paste content links).
  2. In sitemap mode, choose a catalog type; in URL mode, paste one or more catalog URLs.
  3. Set Max items (and, in sitemap mode, optionally Max maps per run) to control run size and cost.
  4. Click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.

Walk the episode catalog (the default):

{
"mode": "sitemap",
"mapType": "EPISODE",
"maxItems": 50
}

A different catalog type:

{
"mode": "sitemap",
"mapType": "SHOWS",
"maxItems": 100
}

Paste catalog URLs: URL mode with the prefilled list scrapes one example per URL shape (a show, an episode, a movie, a browse category, a sport landing page and a sport match highlights /watch page). Replace the list with your own links to scrape those instead. Supported shapes also include clip, movie, live TV and sport match /watch pages (rows are labelled clip, movie, live_tv, sport_match; these were previously labelled episode) and category pages (category). A sport match page looks like https://www.hotstar.com/in/sports/cricket/match-name/1540000000/video/highlights/watch; live (/video/live/watch), replay (/video/replay/watch) and highlights pages are all read the same way. Live match links disappear once the event ends, so use highlights or replay links for anything you want to keep.

New in this version, category rows: the CHANNELS, GENRES and LANGUAGES catalog types (sitemap mode) now return rows of kind category, with the numeric browse id as recordId (for example the id in a /browse/category/<name>/<id> page); the HOME_PAGE_TRAYS type returns category rows with a slug recordId of the form slug:persona-collection/<name>/<id>. These four catalog types previously returned no rows at all, so rows are labelled category, not channel, genre or language. Clip, movie, live TV and sport match /watch rows are labelled clip, movie, live_tv and sport_match; this changes only the kind value, every other field and a stored row's change status stay as before.

URL mode input:

{
"mode": "url",
"urls": [
"https://www.hotstar.com/in/shows/sample-show/500000",
"https://www.hotstar.com/in/movies/sample-movie/500001"
]
}

Daily change watch of a mapped catalog surface:

{
"mode": "sitemap",
"mapType": "EPISODE",
"maxItems": 0,
"incrementalMode": true,
"emitExpired": true
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/hotstar-com-scraper").call(run_input={"mode": "sitemap", "mapType": "SHOWS", "maxItems": 50})
for record in client.dataset(run["defaultDatasetId"]).iterate_items():
print(record["kind"], record["title"], record["url"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/hotstar-com-scraper').call({ mode: 'sitemap', mapType: 'SHOWS', 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 Max items and Max maps shape a sitemap walk

The episode surface alone holds hundreds of thousands of rows spread across about 10 catalog map files. A run walks map files in order and stops once Max items is reached; set it to 0 to walk every map file for that catalog type. Max maps per run is a separate, optional safety bound on how many map files to download in one run, useful for spreading a very large catalog type across several runs; leave it at 0 to let Max items be the only limit.

Resume and recurring updates

  • Resume (resumeFromRunId) continues one interrupted or capped run: paste its run or dataset id and this run skips everything already collected there, so you don't pay twice for the same catalog type.
  • Incremental mode (incrementalMode) is for walking the same catalog scope again and again, for example daily. Each record is classified NEW, REAPPEARED or EXPIRED against the previous walk (the catalog is static per URL, so a previously seen row never reports UPDATED unless its title text itself changed). UNCHANGED rows are suppressed and not billed unless emitUnchanged is on; EXPIRED rows are only produced after a run that scanned the whole scope with no cap, and only with emitExpired on. In sitemap mode, Max items counts every catalog row the run reads, including unchanged ones it does not return, so set it to 0 for a change watch; a smaller value only ever re-checks the first rows of the catalog type. stateKey names or shares the stored state; leave it empty and the actor derives one automatically from the mode, catalog type and URLs, so two different walks never mix state. ignoreFieldsForChanges lists fields that must never count as a change (they stay in the output, but never make a row UPDATED or appear in changedFields); scrapedAt and detailCarriedForward are always ignored. Stored baselines are compared against the current ignore list, so editing it never re-flags the whole catalog. Do not reuse one stateKey across different catalog types or URL lists with emitExpired on: each walk would report the other walk's rows as removed.

Send results into your apps (MCP connectors)

Optional: the run pipes a condensed summary per record (title, kind, URL) into a connector you authorize under Apify, Settings, API and Integrations. This is an extra delivery step after the scrape; the Apify dataset is never changed.

  1. Authorize a connector once under Apify -> Settings -> 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 records should be created.

Each connector receives a condensed summary per record, not the full record; the complete record always stays in the Apify dataset. Set maxNotifyListings to cap how many records flow per connector per run. Leave mcpConnectors empty to skip this entirely, which never changes what the dataset returns.

Input Parameters

ParameterTypeDefaultDescription
modestringsitemapsitemap walks the site's own published catalog lists. url processes pasted catalog URLs.
mapTypestringEPISODESitemap mode only: which catalog dataset to walk (EPISODE, SHOWS, MOVIE, MOVIE_WATCH_PAGES, SPORT, SPORT_LIVE, SPORT_REPLAY, SPORT_MATCH_HIGHLIGHTS, CLIPS, SHOW_LIVE, NEWS_LIVE, LIVE_TV, CHANNELS, GENRES, LANGUAGES, HOME_PAGE_TRAYS, FIRST_LEVEL_LANDING_PAGES, SECOND_LEVEL_LANDING_PAGES, LANGUAGE_GENRE_MOVIES_PAGES, LANGUAGE_GENRE_SHOWS_PAGES).
urlsarrayone example per URL shapeURL mode only: hotstar.com catalog URLs. Each pasted URL returns one record.
maxItemsinteger20Stop after collecting this many records across all catalog maps and URLs. 0 = unlimited.
maxPagesinteger0Safety bound on how many catalog map files (each up to 50,000 rows) to download per run. 0 = no map limit; the run then stops at Max items instead.
resumeFromRunIdstring(none)Continue one interrupted or capped run from its previous run id or dataset id.
incrementalModebooleanfalseRecurring monitoring of the same catalog walk: later runs return only what changed (NEW, plus EXPIRED and REAPPEARED when Emit expired is on) instead of the full snapshot.
stateKeystring(none)Optional name for the incremental state. Leave empty to get a separate state per mode, catalog type and URL list; set it only to name a campaign or deliberately share state.
emitUnchangedbooleanfalseIncremental mode only: also return (and bill) rows that have not changed, marked UNCHANGED.
emitExpiredbooleanfalseIncremental mode only: also return (and bill) rows the previous run tracked that are no longer in the mapped catalog. Only after a complete, uncapped scan.
ignoreFieldsForChangesarray[]Incremental mode only: field names that never count as a change and never appear in changedFields. A plain name matches that field at any depth; a dotted path such as a.b targets one nested field. Ignored fields are still returned. Changing the list never causes a one-time wave of UPDATED rows.
mcpConnectorsarray(none)Optional: send a summary of each record to apps you authorized under Integrations.
notionParentPageUrlstring(none)Notion connector only: page under which record pages are created.
maxNotifyListingsinteger50Cap on records written to each connector per run. Does not affect the dataset.
proxyobjectIndia residentialConnection settings. The catalog answers an India connection, so the default pins an India exit.

Output Example

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

Sample output record:

{
"recordId": "1000200000",
"url": "https://www.hotstar.com/in/shows/sample-show/500000/sample-episode-title/1000200000/watch",
"kind": "episode",
"title": "Sample Episode Title",
"showTitle": "Sample Show Name",
"showId": "500000",
"contentId": "1000200000",
"scrapedAt": "2026-01-01T00:00:00Z"
}

Plan Requirement

An India residential connection is required. The site answers any non-India or datacenter connection with a generic page instead of the catalog lists, so datacenter proxies do not work. The default pins an India residential exit; Apify free plans do not include residential proxies, so on a free plan either upgrade or supply your own India proxy URLs. Some exits fail at the connection level; the actor retries on a fresh session automatically.

If the selected connection is unavailable the run logs: "The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable." and later "Served over the backup connection (the default connection was unavailable)." If nothing can be read the run fails with one of: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required", "No results: residential proxies are unavailable on this run ... and the backup connection could not load the requested Hotstar pages", or "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search." Setting the environment variable HOTSTAR_COM_ALTERNATE_CONNECTION=0 disables the backup connection.

FAQ

How much does it cost?

You pay per record returned, plus the platform's standard per-run start event. The Pricing tab shows the current rates. Rows suppressed as unchanged are not returned and not billed. Use Max items to cap the cost of any run.

This actor reads only the catalog URL list the platform itself publishes in its sitemap, advertised in its own robots.txt. You are responsible for how you use the results: follow the platform's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution.

Can I get only new or removed titles on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode, with Emit expired records on if you also want to know what was removed. Unchanged rows are not billed.

Why does this actor not return descriptions, durations or ratings?

Those fields sit behind the platform's own session gate (a signup flow this actor does not fake), and the public page shell serves an empty template to automated readers. This actor reads the catalog index only: the row kind, title, show and ids, all taken from the URL itself.

Why did my pasted URL come back empty?

URL mode only understands catalog content pages (shows, movies, episodes, sport, clips, channels, genres, languages). Account pages and the site's search results are not catalog URLs and are reported as unread rather than guessed at.

Why did my run fail instead of returning an empty dataset?

If the site refuses every request, the run stops with a clear message so "nothing in this catalog type" is never confused with "nothing could be read". Run it again in a few minutes. If only some catalog map files could not be read, you still get what was found.

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.

🔗 Want more sports data?

Pair this actor with these related scrapers from the same team:

⚽ BookMyShow Scraper
Scrape BookMyShow movies and live events by city, category or URL. Extract genres...
⚽ Whatnot Scraper
Scrape Whatnot live and upcoming shows, queued items and lots, and seller profiles...
⚽ Globo Esporte Scraper
Scrape public sports content from ge.globo.com, including news, videos, matches and feed...
⚽ bet365 Odds Scraper
Scrape bet365 live in-play and pre-match odds across 20+ sports. Extract fixture...
⚽ FanDuel Odds Scraper
Scrape FanDuel sportsbook odds, including moneylines, spreads, totals, player props and...
⚽ Strava Data Scraper
Scrape public Strava data: clubs (members, location, sport, settings), athlete profiles...

👉 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.