# JioHotstar Scraper - Movies, Shows, Sports & Episodes (`abotapi/hotstar-com-scraper`) Actor

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.

- **URL**: https://apify.com/abotapi/hotstar-com-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Features:** Limited permissions
- **Stats:** 3 total users, 0 monthly users, 90.3% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.70 / 1,000 catalog records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

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

| Field | Example |
| --- | --- |
| `recordId` | `"1000200000"` (the episode, show or movie's own numeric id) |
| `recordId` (no numeric segment) | `"slug:cricket"` (sport, genre, language and channel landing pages) |
| `url` | the 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):**

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

**A different catalog type:**

```json
{
  "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:**

```json
{
  "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:**

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

#### Run it from your code

Python:

```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:

```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

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `sitemap` | `sitemap` walks the site's own published catalog lists. `url` processes pasted catalog URLs. |
| `mapType` | string | `EPISODE` | Sitemap 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). |
| `urls` | array | one example per URL shape | URL mode only: hotstar.com catalog URLs. Each pasted URL returns one record. |
| `maxItems` | integer | `20` | Stop after collecting this many records across all catalog maps and URLs. `0` = unlimited. |
| `maxPages` | integer | `0` | Safety 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. |
| `resumeFromRunId` | string | (none) | Continue one interrupted or capped run from its previous run id or dataset id. |
| `incrementalMode` | boolean | `false` | Recurring 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. |
| `stateKey` | string | (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. |
| `emitUnchanged` | boolean | `false` | Incremental mode only: also return (and bill) rows that have not changed, marked `UNCHANGED`. |
| `emitExpired` | boolean | `false` | Incremental 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. |
| `ignoreFieldsForChanges` | array | `[]` | 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. |
| `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. Does not affect the dataset. |
| `proxy` | object | India residential | Connection 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:**

```json
{
  "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.

#### Is it legal to scrape JioHotstar?

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:

<table>
<tr><td>⚽ <a href="https://apify.com/abotapi/bookmyshow-scraper"><b>BookMyShow Scraper</b></a><br>Scrape BookMyShow movies and live events by city, category or URL. Extract genres...</td><td>⚽ <a href="https://apify.com/abotapi/whatnot-scraper"><b>Whatnot Scraper</b></a><br>Scrape Whatnot live and upcoming shows, queued items and lots, and seller profiles...</td></tr>
<tr><td>⚽ <a href="https://apify.com/abotapi/globo-ge"><b>Globo Esporte Scraper</b></a><br>Scrape public sports content from ge.globo.com, including news, videos, matches and feed...</td><td>⚽ <a href="https://apify.com/abotapi/bet365-odds-scraper"><b>bet365 Odds Scraper</b></a><br>Scrape bet365 live in-play and pre-match odds across 20+ sports. Extract fixture...</td></tr>
<tr><td>⚽ <a href="https://apify.com/abotapi/fanduel-odds-scraper"><b>FanDuel Odds Scraper</b></a><br>Scrape FanDuel sportsbook odds, including moneylines, spreads, totals, player props and...</td><td>⚽ <a href="https://apify.com/abotapi/strava-public-data-scraper"><b>Strava Data Scraper</b></a><br>Scrape public Strava data: clubs (members, location, sport, settings), athlete profiles...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/hotstar-com-scraper/issues/open). 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.

# Actor input Schema

## `mode` (type: `string`):

How the run finds catalog rows. 'sitemap' walks the site's own published catalog URL lists (the index at hotstar.com/in/new-sitemap.xml, as linked from the site's robots.txt): one content URL per row, filtered by the catalog type below. 'url' processes the content URLs you paste instead: each catalog URL returns one record, and rows are read out of the URL itself (show, show id, episode title, content id).

## `mapType` (type: `string`):

Which of the site's own catalog datasets to walk. EPISODE (the largest, tens of thousands of rows per map) is the default; SHOWS and MOVIE carry the show and movie landings; SPORT-related types carry the sport pages; the rest carry the smaller catalog surfaces (channels, genres, languages).

## `urls` (type: `array`):

Paste hotstar.com catalog URLs: show pages (https://www.hotstar.com/in/shows/show-name/000), episode pages (https://www.hotstar.com/in/shows/show-name/000/episode-name/000/watch), or movie pages (https://www.hotstar.com/in/movies/movie-name/000). Each pasted URL returns one record read out of the URL itself; the Max items cap stops the walk if you paste many. Also accepted: browse category pages (https://www.hotstar.com/in/browse/category/name/000), sport landing pages (https://www.hotstar.com/in/sports/cricket), and clip, movie, live TV and sport match /watch pages (for example https://www.hotstar.com/in/sports/cricket/match-name/000/video/highlights/watch; live, replay and highlights match pages all work, and a live match link stops existing once the event ends). The prefilled list has one example of each shape.

## `maxItems` (type: `integer`):

Stop after collecting this many records across all catalog maps and URLs. Set 0 for unlimited.

## `maxPages` (type: `integer`):

Safety bound on how many catalog map files (each up to 50,000 rows) to download per run. Leave empty (0) for no map limit: the run then stops at Max items, not here. Does not impose a separate cap below Max items.

## `proxy` (type: `object`):

The catalog is served by the site's India-only region, so the default pins an India exit. If a run reports that it could not read any results, try again (the shared pool is a rotating one), or use a custom proxy endpoint of your own.

## `resumeFromRunId` (type: `string`):

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 catalog walk, use Incremental mode below instead.

## `incrementalMode` (type: `boolean`):

Turn this on for daily or weekly recurring monitoring of the same catalog walk, for example to watch what the platform adds or drops from the catalog. The first run returns everything as NEW. Later runs normally return only NEW and EXPIRED records: the catalog is static per URL, so a previously seen URL never reports UPDATED. Turn on Emit unchanged or Emit expired only when you also want those rows returned (and billed). State is kept separately per mode, catalog type and URL 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.

## `stateKey` (type: `string`):

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 mode, catalog type and URLs, so two different walks never mix state.

## `emitUnchanged` (type: `boolean`):

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.

## `emitExpired` (type: `boolean`):

Off by default. Turn on to also return records that were present in a previous run but are no longer found in the catalog, marked EXPIRED. Only produced once a run has fully scanned the mapped catalog: 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 removal tracking.

## `ignoreFieldsForChanges` (type: `array`):

Optional. Field names that must NOT count as a change when incremental mode compares a record with the previous run, for example showTitle or description. A plain name matches that field at any depth (also inside nested lists and objects); use dotted paths such as a.b for one specific nested field. Ignored fields are still returned in the output, they just never make a row UPDATED or appear in changedFields. Changing this list does not mark everything as UPDATED. Always ignored already: scrapedAt, detailCarriedForward.

## `mcpConnectors` (type: `array`):

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

## `notionParentPageUrl` (type: `string`):

URL or id of the Notion page under which record pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on records written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "sitemap",
  "mapType": "EPISODE",
  "urls": [
    "https://www.hotstar.com/in/shows/world-s-weirdest/6207",
    "https://www.hotstar.com/in/shows/triveni-sangama/13023/sudha-instigates-nanda-kishore/1000175440/watch",
    "https://www.hotstar.com/in/movies/chintamani/1971007215",
    "https://www.hotstar.com/in/browse/category/romance/928",
    "https://www.hotstar.com/in/sports/cricket",
    "https://www.hotstar.com/in/sports/football/troyes-vs-paris-fc-highlights/1271686360/video/highlights/watch"
  ],
  "maxItems": 20,
  "maxPages": 0,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "IN"
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "ignoreFieldsForChanges": [],
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `changes` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "sitemap",
    "mapType": "EPISODE",
    "urls": [
        "https://www.hotstar.com/in/shows/world-s-weirdest/6207",
        "https://www.hotstar.com/in/shows/triveni-sangama/13023/sudha-instigates-nanda-kishore/1000175440/watch",
        "https://www.hotstar.com/in/movies/chintamani/1971007215",
        "https://www.hotstar.com/in/browse/category/romance/928",
        "https://www.hotstar.com/in/sports/cricket",
        "https://www.hotstar.com/in/sports/football/troyes-vs-paris-fc-highlights/1271686360/video/highlights/watch"
    ],
    "maxItems": 20,
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "IN"
    },
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false,
    "ignoreFieldsForChanges": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/hotstar-com-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "sitemap",
    "mapType": "EPISODE",
    "urls": [
        "https://www.hotstar.com/in/shows/world-s-weirdest/6207",
        "https://www.hotstar.com/in/shows/triveni-sangama/13023/sudha-instigates-nanda-kishore/1000175440/watch",
        "https://www.hotstar.com/in/movies/chintamani/1971007215",
        "https://www.hotstar.com/in/browse/category/romance/928",
        "https://www.hotstar.com/in/sports/cricket",
        "https://www.hotstar.com/in/sports/football/troyes-vs-paris-fc-highlights/1271686360/video/highlights/watch",
    ],
    "maxItems": 20,
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "IN",
    },
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
    "ignoreFieldsForChanges": [],
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/hotstar-com-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "sitemap",
  "mapType": "EPISODE",
  "urls": [
    "https://www.hotstar.com/in/shows/world-s-weirdest/6207",
    "https://www.hotstar.com/in/shows/triveni-sangama/13023/sudha-instigates-nanda-kishore/1000175440/watch",
    "https://www.hotstar.com/in/movies/chintamani/1971007215",
    "https://www.hotstar.com/in/browse/category/romance/928",
    "https://www.hotstar.com/in/sports/cricket",
    "https://www.hotstar.com/in/sports/football/troyes-vs-paris-fc-highlights/1271686360/video/highlights/watch"
  ],
  "maxItems": 20,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "IN"
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "ignoreFieldsForChanges": []
}' |
apify call abotapi/hotstar-com-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/hotstar-com-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/LIQ5h3Q7ggzSMMIEW/builds/CYAiDZUNDPZunHhiu/openapi.json
