# TVmaze Scraper: TV Shows, Episodes & Cast (`arman-bd/tvmaze-shows-scraper`) Actor

Scrape TVmaze for TV series data. show details, genres, network, status, episode lists with air dates and full cast with character names. No key, no proxy, no browser.

- **URL**: https://apify.com/arman-bd/tvmaze-shows-scraper.md
- **Developed by:** [Arman Hossain](https://apify.com/arman-bd) (community)
- **Categories:** Automation, AI, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.37 / 1,000 show scrapeds

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## TVmaze Scraper: TV Shows, Episodes & Cast

![TVmaze: Every show as one row, genres, status, network, the full episode list and cast, one HTTP call each](https://api.apify.com/v2/key-value-stores/ZQOcNAOHrIgTacAmy/records/tvmaze-shows-scraper.jpg)

**TVmaze Scraper** pulls complete TV series metadata from **TVmaze**, show details, genres, network or streaming channel, status, rating, artwork, the full episode list with air dates and summaries, and the full cast with character names.

TVmaze is an open, community-maintained TV database with a public API that needs no key and no signup. This Actor calls it directly: **no browser, no proxies, no login, no rate-limit games.** Episodes and cast are embedded into the same request as the show, so a full series snapshot is one HTTP call.

**Agent skill: [SKILL.md](https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/tvmaze-shows-scraper.md)**

```
https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/tvmaze-shows-scraper.md
```

### What you get

| Output field | Meaning |
|---|---|
| `showId`, `name`, `url` | TVmaze ID, show title and the public TVmaze page |
| `type`, `language`, `genres` | Scripted / Reality / Animation, original language, genre list |
| `status` | Running, Ended, To Be Determined, In Development |
| `runtime` | Episode runtime in minutes (falls back to TVmaze's average when episodes vary) |
| `premiered`, `ended` | First and last air dates |
| `officialSite` | The show's own site, when the database has one |
| `network`, `webChannel` | Broadcast network **or** streaming channel, streaming-only shows have `network: null` |
| `rating` | TVmaze community rating out of 10 |
| `summary` | Show synopsis as clean plain text, HTML stripped, entities decoded |
| `imageUrl` | Full-resolution poster |
| `episodes` | Every episode: `season`, `number`, `name`, `type`, `airdate`, `airstamp`, `runtime`, `rating`, `url`, `summary` |
| `cast` | Every cast member: person, character, country, birthday, plus `self` and `voice` flags |
| `scrapedAt` | Run timestamp |

A `RUN_SUMMARY` record in the key-value store holds per-run counts, shows, episodes and cast members saved, plus any term or ID that failed.

### Common use cases

- **Build a TV tracking or watchlist app.** Air dates and episode numbering come ready to index.
- **Enrich a streaming catalogue.** Match your titles to TVmaze IDs and pull genres, artwork and cast.
- **Media research.** Analyse genre mix, network vs streaming split, or run length across a set of shows.
- **AI agents and RAG pipelines.** Clean plain-text summaries make good retrieval chunks with no HTML cleanup step.
- **Recommendation seeds.** Cast overlap between shows is a strong, cheap similarity signal.

### Quick start

Look up shows by name, best match for each:

```json
{
 "searchTerms": ["Severance", "Breaking Bad"]
}
```

Exact shows you already know, metadata only:

```json
{
 "showIds": ["44933", "https://www.tvmaze.com/shows/169/breaking-bad"],
 "includeEpisodes": false,
 "includeCast": false
}
```

Broad discovery, keep every ranked hit per term:

```json
{
 "searchTerms": ["detective", "space"],
 "maxShowsPerTerm": 10,
 "includeEpisodes": false,
 "includeCast": true
}
```

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `searchTerms` | array | `[]` | Show titles. Each is resolved through TVmaze's relevance-ranked search. |
| `showIds` | array | `[]` | Exact TVmaze IDs. Full `tvmaze.com/shows/<id>/.` URLs are accepted and normalised. |
| `includeEpisodes` | boolean | `true` | Embed the full episode list. |
| `includeCast` | boolean | `true` | Embed the full cast list. |
| `maxShowsPerTerm` | integer | `1` | How many ranked hits to keep per search term. TVmaze returns at most 10. `0` = keep every hit. |

At least one of `searchTerms` or `showIds` is required, supplying both is fine and the two are merged, so a show reached by both routes is still scraped once. Turning off `includeEpisodes` and `includeCast` produces a compact catalogue-style dataset; leaving both on makes each record self-contained.

### Output example

```json
{
 "showId": 44933,
 "name": "Severance",
 "type": "Scripted",
 "language": "English",
 "genres": ["Drama", "Science-Fiction", "Mystery"],
 "status": "Running",
 "runtime": 49,
 "premiered": "2022-02-18",
 "ended": null,
 "officialSite": "https://tv.apple.com/show/severance/…",
 "network": null,
 "webChannel": "Apple TV",
 "rating": 7.7,
 "summary": "Mark Scout leads a team at Lumon Industries, whose employees have undergone a severance procedure …",
 "imageUrl": "https://static.tvmaze.com/uploads/images/original_untouched/548/1371406.jpg",
 "url": "https://www.tvmaze.com/shows/44933/severance",
 "episodes": [
 {
 "episodeId": 2238231,
 "season": 1,
 "number": 1,
 "name": "Good News About Hell",
 "type": "regular",
 "airdate": "2022-02-18",
 "airstamp": "2022-02-18T12:00:00+00:00",
 "runtime": 57,
 "rating": 7.2,
 "url": "https://www.tvmaze.com/episodes/2238231/severance-1x01-good-news-about-hell",
 "summary": "Mark is promoted to lead a team who've had their memories surgically divided …"
 }
 ],
 "cast": [
 {
 "personId": 31964,
 "personName": "Adam Scott",
 "personUrl": "https://www.tvmaze.com/people/31964/adam-scott",
 "country": "United States",
 "birthday": "1973-04-03",
 "characterId": 673312,
 "characterName": "Mark Scout",
 "characterUrl": "https://www.tvmaze.com/characters/673312/severance-mark-scout",
 "self": false,
 "voice": false
 }
 ],
 "scrapedAt": "2026-08-06T12:00:00.000Z"
}
```

### API example

```bash
curl -X POST "https://api.apify.com/v2/acts/arman-bd~tvmaze-shows-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
 "searchTerms": ["Severance"],
 "includeEpisodes": true,
 "includeCast": true
 }'
```

### JavaScript example

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

const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('arman-bd/tvmaze-shows-scraper').call({
 searchTerms: ['Severance', 'The Bear'],
 includeEpisodes: true,
 includeCast: false,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const show of items) {
 console.log(`${show.name} (${show.premiered}), ${show.episodes.length} episodes on ${show.webChannel ?? show.network}`);
}
```

### Notes

- **A missing show doesn't kill the run.** A search with no hits, or an ID that does not exist, is recorded in `RUN_SUMMARY.failures` and the run continues. The Actor only errors out if nothing at all could be scraped.
- **Transient errors are retried.** 429 and 5xx get three attempts with exponential backoff; a 404 on a specific ID fails fast because retrying it never helps.
- **One request per show.** Episodes and cast come back as TVmaze embeds on the show call, so scraping a series with 200 episodes is still a single HTTP request.
- **Summaries are decoded twice.** TVmaze summaries are user-contributed HTML and some arrive already encoded, so entities are decoded before tags are stripped and again afterwards. You get real text, not `&lt;p&gt;`.
- **Network vs web channel.** Broadcast shows fill `network`; streaming originals fill `webChannel` and leave `network` null. Read both.
- **Public data only.** No authentication, no personal data, no access-control bypass.

### FAQ

**Do I need a TVmaze API key?** No. You supply no credentials.

**Do I need a proxy?** No. Proxy configuration is not required to run this Actor.

**Why did my search return the wrong show?** TVmaze ranks by relevance and the default keeps only the top hit. Raise `maxShowsPerTerm`, or pass the exact `showIds` when you already know them.

**Why is `runtime` different from an episode's runtime?** The show-level value is the typical length; TVmaze leaves it null for shows with variable episodes, in which case this Actor falls back to the average runtime. Per-episode `runtime` is always the exact one.

**Are specials and pilots included?** Yes, every episode TVmaze holds is returned, with `type` distinguishing `regular`, `special` and `insignificant`.

**Can I schedule it?** Yes. Air dates change often, so a nightly run over a watchlist keeps `episodes` current. Diff on `episodeId` plus `airdate` to spot schedule changes.

**Can I integrate it with something else?** Yes, Apify API, client libraries, webhooks, scheduled runs, dataset exports (JSON/CSV/Excel) or MCP. Output is structured JSON.

# Actor input Schema

## `searchTerms` (type: `array`):

Show titles to look up. Each term is resolved through TVmaze's relevance-ranked search; use 'Max shows per term' to keep more than the top match.

## `showIds` (type: `array`):

Exact TVmaze show IDs, e.g. 44933. Full tvmaze.com/shows/<id>/.. URLs are accepted and normalized automatically. Use this when you already know the show and want to skip the search step.

## `includeEpisodes` (type: `boolean`):

Embed the full episode list. season, number, air date, runtime, rating and summary for every episode.

## `includeCast` (type: `boolean`):

Embed the full cast. person, character, country and birthday, plus self/voice flags.

## `maxShowsPerTerm` (type: `integer`):

How many of each search term's ranked results to keep. 1 takes only the best match; TVmaze returns at most 10. Set 0 to keep every hit.

## Actor input object example

```json
{
  "searchTerms": [
    "Severance",
    "The Bear"
  ],
  "showIds": [
    "44933",
    "https://www.tvmaze.com/shows/169/breaking-bad"
  ],
  "includeEpisodes": true,
  "includeCast": true,
  "maxShowsPerTerm": 1
}
```

# Actor output Schema

## `items` (type: `string`):

Every record the run produced.

## `runsummary` (type: `string`):

The RUN\_SUMMARY record from the run's key-value store.

# 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 = {
    "searchTerms": [
        "Severance",
        "Breaking Bad"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("arman-bd/tvmaze-shows-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 = { "searchTerms": [
        "Severance",
        "Breaking Bad",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("arman-bd/tvmaze-shows-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 '{
  "searchTerms": [
    "Severance",
    "Breaking Bad"
  ]
}' |
apify call arman-bd/tvmaze-shows-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,arman-bd/tvmaze-shows-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/DIA7yuuijYgQhfFyg/builds/mRuCdbUqrr71fJDgH/openapi.json
