# MyAnimeList Anime Scraper (`axiomworks/myanimelist-anime-scraper`) Actor

Collect MyAnimeList anime data as structured records, including titles, scores, rankings, popularity, episode counts, airing status, genres and studios. Choose top, search, season or ID mode. Data comes from Tenrai, a public mirror with a Jikan v4-compatible JSON schema.

- **URL**: https://apify.com/axiomworks/myanimelist-anime-scraper.md
- **Developed by:** [Axiom Works](https://apify.com/axiomworks) (community)
- **Categories:** Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.19 / 1,000 results

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

**Returns:** one row per anime with `malId`, `title`, `type`, `episodes`, `score`, `rank`, `genres` and `url`.
**Input:** `{"mode": "search", "searchQuery": "naruto", "maxItems": 20}`
**Best for:** building anime databases and recommendation datasets, tracking scores and rankings over time, and listing every title of a season.

```json
{"malId": 52991, "title": "Sousou no Frieren", "type": "TV", "episodes": 28, "score": 9.24, "rank": 1, "genres": ["Adventure", "Award Winning", "Drama", "Fantasy"], "url": "https://myanimelist.net/anime/52991/Sousou_no_Frieren"}
```

### What does MyAnimeList Anime Scraper do?

MyAnimeList Anime Scraper is a MyAnimeList scraper and MyAnimeList API alternative that returns structured anime records as a dataset. Pick a mode, run the Actor, and download the rows as JSON, CSV or Excel, or read them through the Apify API. Each row holds the titles in three languages, format, source material, episode count, airing status, aired dates, score, rank, popularity, member and favorite counts, synopsis, season, image, trailer, genres and studios.

The data comes from Tenrai, a public mirror of MyAnimeList content that serves the same JSON shape as the Jikan v4 API. No login is needed and no account is used. The Actor reads JSON endpoints directly, so runs are fast and light: one request returns up to 25 anime, with smaller limits for runs requesting fewer records, and requests are spaced to stay well inside the public rate limit.

Four modes cover the common jobs. The `top` mode walks the ranking from the highest rank down. The `search` mode finds anime by title keywords, in English, romaji or Japanese. The `season` mode lists everything that premiered in a given year and season. The `ids` mode fetches the full record of specific anime when you already know their MyAnimeList IDs or page URLs.

### What data can you get from MyAnimeList?

Every record has the fields below. Fields the source does not have for a title, for example `airedTo` for a show that is still airing or `trailerUrl` for a title without a trailer, are returned as `null`, so the columns stay the same across rows.

| Field | Description | Example |
|---|---|---|
| `id` | Stable MyAnimeList anime ID as a string. Unique within a run. | `52991` |
| `malId` | MyAnimeList anime ID. | `52991` |
| `title` | Default (romanised) title. | `Sousou no Frieren` |
| `titleEnglish` | English title, when one exists. | `Frieren: Beyond Journey's End` |
| `titleJapanese` | Title in Japanese. | `葬送のフリーレン` |
| `type` | Format: TV, Movie, OVA, ONA, Special, Music. | `TV` |
| `source` | What the anime is adapted from. | `Manga` |
| `episodes` | Episode count; empty while unknown. | `28` |
| `status` | Airing status. | `Finished Airing` |
| `airedFrom` | ISO start date. | `2023-09-29T00:00:00+00:00` |
| `airedTo` | ISO end date; empty while still airing. | `2024-03-22T00:00:00+00:00` |
| `duration` | Episode duration text. | `24 min per ep` |
| `rating` | Age rating text. | `PG-13 - Teens 13 or older` |
| `score` | Mean user score (1-10). | `9.25` |
| `scoredBy` | Number of users who scored it. | `942093` |
| `rank` | Rank by score. | `1` |
| `popularity` | Popularity rank. | `97` |
| `members` | Users with it on their list. | `1526833` |
| `favorites` | Users who favourited it. | `93949` |
| `synopsis` | Plot summary. | `During their decade-long quest to defeat the Demon King...` |
| `season` | Premiere season. | `fall` |
| `year` | Premiere year. | `2023` |
| `imageUrl` | Poster image URL. | `https://cdn.myanimelist.net/images/anime/1015/138006l.jpg` |
| `trailerUrl` | YouTube trailer URL. | `https://www.youtube.com/watch?v=ZEkwCGJ3o7M` |
| `genres` | Genre names. | `["Adventure", "Drama", "Fantasy"]` |
| `studios` | Studio names. | `["Madhouse"]` |
| `themes` | Theme names. | `["Isekai"]` |
| `demographics` | Demographic names. | `["Shounen"]` |
| `producers` | Producer company names. | `["Aniplex"]` |
| `licensors` | Licensor company names. | `["Crunchyroll"]` |
| `titleSynonyms` | Alternative titles. | `["Frieren at the Funeral"]` |
| `background` | Background notes, when the source has them. | `Aired on Nippon TV's Friday Anime Night block.` |
| `airing` | True while the anime is airing. | `false` |
| `broadcast` | Broadcast slot as text. | `Fridays at 23:00 (JST)` |
| `url` | MyAnimeList page of the anime. | `https://myanimelist.net/anime/52991/Sousou_no_Frieren` |
| `sourceUrl` | API endpoint the record came from. | `https://api.tenrai.org/v1/top/anime?limit=25&page=1` |

### How to use MyAnimeList Anime Scraper

1. Open the Actor in Apify Console and choose a `mode`: top, search, season or ids.
2. Fill in the matching field: `searchQuery` for search, `seasonYear` and `season` for season, or `animeIds` for ids. Top needs nothing else.
3. Set `maxItems` to the number of anime you want. The run stops as soon as that many records are saved.
4. Click Start. When the run finishes, open the Output tab and export the dataset as JSON, CSV, Excel, XML or RSS.
5. For recurring jobs such as monthly ranking snapshots, create a Schedule and compare the datasets.

Search mode also works without a `searchQuery` when you set at least one filter, for example every movie scored 8 or higher: `{"mode": "search", "type": "movie", "minScore": 8, "orderBy": "score"}`.

Tips: if you leave `mode` out but give `animeIds` or `searchQuery`, the Actor picks `ids` or `search` for you. Anime IDs can be plain numbers like `5114` or page URLs like `https://myanimelist.net/anime/5114/Fullmetal_Alchemist_Brotherhood`. Duplicate anime inside one run are returned once. If `season` and `seasonYear` are empty in season mode, the current season is used.

For a catalog restricted to one age rating, use `{"mode":"search","ageRating":"pg13","minScore":8,"orderBy":"score","sortDirection":"desc","maxItems":20}`. This selects the exact source rating category; PG-13 does not include G or PG titles. The returned `rating` column lets you check the selection. To browse the most popular matching titles first, use `orderBy: "popularity"` with `sortDirection: "asc"`, because popularity is a rank where smaller numbers come first. For alphabetical search results choose `orderBy: "title"` and `sortDirection: "asc"`. The default `auto` direction retains the existing behavior: descending for every field except title. These settings apply only to search mode and do not change top rankings, seasonal lists, or ID lookup order. They require no extra detail requests.

### Input

| Field | Type | Required | Description |
|---|---|---|---|
| `mode` | string | No | `top`, `search`, `season` or `ids`. Default `top`. |
| `searchQuery` | string | Query or filter for search | Title keywords, up to 200 characters, for example `naruto`. |
| `seasonYear` | integer | No | Year, 1917-2100. Defaults to the current year. |
| `season` | string | No | `winter`, `spring`, `summer` or `fall`. Defaults to the current season. |
| `animeIds` | array of strings | For ids | MyAnimeList anime IDs or anime page URLs. |
| `type` | string | No | Search mode only: `tv`, `movie`, `ova`, `special`, `ona` or `music`. |
| `status` | string | No | Search mode only: `airing`, `complete` or `upcoming`. |
| `minScore` | number | No | Search mode only: minimum score, 0-10. |
| `genres` | string | No | Search mode only: comma-separated MyAnimeList genre IDs, e.g. `1,2`. |
| `ageRating` | string | No | Search age rating: `all` (default), `g`, `pg`, `pg13` or `r17`. Can be used without title keywords. |
| `sortDirection` | string | No | Search order: `auto` (default, preserves existing order), `asc` or `desc`. Use ascending popularity or rank for rank 1 first. |
| `orderBy` | string | No | Search mode only: `popularity` (default), `score`, `rank`, `members`, `favorites`, `title` or `start_date`. |
| `maxItems` | integer | No | Maximum unique anime rows across the whole run, including all IDs; 1-10000, default 50. |
| `includeDetails` | boolean | No | Default false. When true, top, search and season rows also get opening and ending themes, relations, streaming links, external links and more info (one extra request per row, slower). Always filled in ids mode. |
| `proxyConfiguration` | object | No | Proxy settings. Default: no proxy. Turn on Apify Proxy for retry fallback if direct requests are blocked. |

```json
{
    "mode": "season",
    "seasonYear": 2023,
    "season": "fall",
    "maxItems": 100,
    "proxyConfiguration": { "useApifyProxy": false }
}
```

Input that cannot work, such as `search` mode without a `searchQuery` or any filter or an `animeIds` entry that is not an ID or anime URL, fails immediately with a message that says what to change. A well-formed request that matches nothing, such as a nonsense search term or an ID that does not exist, finishes successfully with zero results and mode-specific guidance: broaden search keywords or remove filters, check IDs, or change the season and year. A persistent block advises enabling proxyConfiguration or retrying later. When some IDs fail, other IDs continue and any real rows remain in the dataset.

### Output

Each run writes one dataset row per anime. Real records from a `top` run (the synopsis is shortened here):

```json
[
    {
        "id": "52991",
        "malId": 52991,
        "title": "Sousou no Frieren",
        "titleEnglish": "Frieren: Beyond Journey's End",
        "titleJapanese": "葬送のフリーレン",
        "type": "TV",
        "source": "Manga",
        "episodes": 28,
        "status": "Finished Airing",
        "airedFrom": "2023-09-29T00:00:00+00:00",
        "airedTo": "2024-03-22T00:00:00+00:00",
        "duration": "24 min per ep",
        "rating": "PG-13 - Teens 13 or older",
        "score": 9.25,
        "scoredBy": 942298,
        "rank": 1,
        "popularity": 97,
        "members": 1527146,
        "favorites": 93957,
        "synopsis": "During their decade-long quest to defeat the Demon King, the members of the hero's party—Himmel himself, the priest Heit...",
        "season": "fall",
        "year": 2023,
        "imageUrl": "https://cdn.myanimelist.net/images/anime/1015/138006l.jpg",
        "trailerUrl": "https://www.youtube.com/watch?v=ZEkwCGJ3o7M",
        "genres": [
            "Adventure",
            "Award Winning",
            "Drama",
            "Fantasy"
        ],
        "studios": [
            "Madhouse"
        ],
        "url": "https://myanimelist.net/anime/52991/Sousou_no_Frieren",
        "sourceUrl": "https://api.tenrai.org/v1/top/anime?limit=25&page=1"
    }
]
```

The dataset has an Overview view with the most useful columns: title, type, score, rank, popularity, members, episodes, status, season, year, genres and url. Export formats are JSON, CSV, Excel, XML and RSS.

### How much does it cost to scrape MyAnimeList?

MyAnimeList Anime Scraper is charged per result. You pay only for the anime records returned, and `maxItems` caps how many that can be, so a run never costs more than you planned. See the Pricing tab on the Actor page for the current price per result. Platform usage such as compute is covered by the Actor's publisher under pay-per-event pricing.

### Use with AI agents (MCP)

Connect MyAnimeList Anime Scraper to Claude, Cursor or any MCP client through the Apify MCP server:

```json
{
    "mcpServers": {
        "apify": {
            "url": "https://mcp.apify.com/?tools=axiomworks/myanimelist-anime-scraper"
        }
    }
}
```

Example prompts:

1. "Use the MyAnimeList scraper to get the top 30 anime and list their scores and genres."
2. "Search MyAnimeList for 'naruto' and return the 20 most popular matches with episode counts."
3. "List every anime from fall 2023 with a score above 8, sorted by members."

### Integrations and API

Run MyAnimeList Anime Scraper from your own code with the Apify API. Set `APIFY_TOKEN` to your Apify API token (send it in the `Authorization` header, never in the URL).

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("axiomworks/myanimelist-anime-scraper").call(run_input={"mode": "search", "searchQuery": "naruto", "maxItems": 20})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], item["score"])
```

**JavaScript**

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

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('axiomworks/myanimelist-anime-scraper').call({ mode: 'search', searchQuery: 'naruto', maxItems: 20 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

**cURL**

```bash
curl -X POST "https://api.apify.com/v2/acts/axiomworks~myanimelist-anime-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode": "search", "searchQuery": "naruto", "maxItems": 20}'
```

You can also connect the Actor to Make, Zapier, n8n, Google Sheets or your own webhooks from the Integrations tab, and trigger it on a schedule.

### FAQ

**Where does the data come from?**
The Actor reads Tenrai, a public mirror of MyAnimeList data that uses the Jikan v4 JSON format. The `url` field links to the anime's MyAnimeList page and `sourceUrl` shows the exact endpoint each row came from.

**How fresh is the data?**
It is as current as the source mirror. Scores, ranks and member counts change daily, so schedule runs if you track trends.

**Why did my run return 0 results?**
The search term matched nothing, the anime ID does not exist, or the source was unreachable. The status message of the run says which. Check the spelling, try a broader query, or retry later. If requests are blocked, enable Apify Proxy in the proxy settings.

**Can I get more than the top 100?**
Yes. `maxItems` goes up to 10000 and the Actor keeps paging until it has that many or the list ends.

**Does it return episodes, characters or reviews?**
No. It returns one record per anime. Characters and manga would be separate Actors.

**Why is a field empty?**
The source has no value for that title. Airing shows have no end date, and some titles have no trailer, English title or score yet.

**How fast is it?**
Requests are limited to about two per second, and list pages return up to 25 anime. A smaller maxItems uses a smaller fixed page size, avoiding unused records. When a proxy is enabled, the initial request still goes directly to Tenrai; retry attempts use fresh proxy sessions. Runtime also depends on source response times and retries.

**What happens if the source is down?**
Requests are retried with backoff. If the source still does not answer, the run finishes with zero results and a message instead of hanging.

### Is it legal to scrape MyAnimeList?

The Actor collects publicly available anime information that loads without a login. It does not touch user accounts, lists or private data. You are responsible for how you use the data: respect copyright on synopses and images, and follow the data protection rules that apply to you. This is not legal advice. This Actor is an independent tool and is not affiliated with or endorsed by MyAnimeList or Tenrai.

### Feedback

Found a bug or need a field that isn't here? Open an issue on the Issues tab and we'll look at it.

# Actor input Schema

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

Choose 'top' for ranked anime, 'search' for searchQuery or search filters, 'season' for seasonYear + season, or 'ids' for animeIds. Example: 'top'. If omitted, nonempty animeIds selects ids, otherwise searchQuery selects search, otherwise top. Explicit mode overrides inference.

## `searchQuery` (type: `string`):

Anime title keywords, e.g. 'naruto' or '進撃', up to 200 characters. Used in search mode; omitted mode infers search. Search needs this or at least one of type, status, minScore, genres or ageRating. Empty searches succeed with zero rows; try broader keywords or fewer filters.

## `seasonYear` (type: `integer`):

Premiere year for mode 'season', e.g. 2023; whole number 1917-2100. Omit to use the current UTC year. Combine with season; ignored in other modes.

## `season` (type: `string`):

Premiere season for mode 'season': winter, spring, summer or fall, e.g. 'fall'. Omit to use the current UTC calendar quarter. Combine with seasonYear; ignored in other modes.

## `animeIds` (type: `array`):

MyAnimeList anime IDs or anime page URLs for mode 'ids', e.g. \['5114', 'https://myanimelist.net/anime/1535/Death_Note']. Numeric IDs are also accepted by the API. Required in ids mode; omitted mode infers ids from a nonempty list. Duplicates are saved once. Missing IDs are skipped; maxItems is shared across all IDs.

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

Format for search mode: tv, movie, ova, special, ona or music, e.g. 'movie'. Omit for all formats.

## `status` (type: `string`):

Airing status for search mode: airing, complete or upcoming, e.g. 'complete'. Omit for all statuses.

## `minScore` (type: `number`):

Minimum anime score for search mode, 0-10, e.g. 8. Omit for no score threshold.

## `genres` (type: `string`):

Comma-separated MyAnimeList genre IDs for search mode, e.g. '1,2' (Action and Adventure; 22 is Romance). Omit for no genre filter.

## `orderBy` (type: `string`):

Sort search results by popularity, score, rank, members, favorites, title or start_date, e.g. 'score'. Default popularity. Uses descending order except title, which is ascending. Does not change top, season or ids ordering. Override direction with sortDirection.

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

Maximum unique anime rows across the entire run and all animeIds, e.g. 20. Whole number 1-10000, default 50. Returns fewer if the source runs out or targets fail. Duplicate IDs do not consume this limit. Charged only for rows saved.

## `includeDetails` (type: `boolean`):

If true, top/search/season rows are enriched from the single-anime endpoint with openingThemes, endingThemes, relations, streamingLinks, externalLinks and moreInfo (one extra request per row, about 0.5 s each). Default false: those six fields are null in list modes. Always filled in ids mode.

## `proxyConfiguration` (type: `object`):

Proxy settings, e.g. {"useApifyProxy": true}. Default {"useApifyProxy": false}. Initial requests are direct; configured proxy is used only on retries with fresh sessions. Persistent blocks succeed with zero rows when no target works; enable a proxy or retry later.

## `ageRating` (type: `string`):

Age rating for search mode: all for unrestricted (default), g for all ages, pg for children, pg13 for teens 13+, or r17 for ages 17+. Can be the only search filter. Ignored in top, season and ids modes.

## `sortDirection` (type: `string`):

Direction for orderBy in search mode: auto (default) preserves descending order except title ascending; asc sorts low to high and desc high to low. Use asc with popularity or rank to put rank 1 first. Ignored in top, season and ids modes.

## Actor input object example

```json
{
  "mode": "top",
  "searchQuery": "naruto",
  "animeIds": [
    "52991"
  ],
  "orderBy": "popularity",
  "maxItems": 20,
  "includeDetails": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "ageRating": "all",
  "sortDirection": "auto"
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset with one item per result, in the order found.

# 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": "top",
    "searchQuery": "naruto",
    "animeIds": [
        "52991"
    ],
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/myanimelist-anime-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": "top",
    "searchQuery": "naruto",
    "animeIds": ["52991"],
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/myanimelist-anime-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": "top",
  "searchQuery": "naruto",
  "animeIds": [
    "52991"
  ],
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call axiomworks/myanimelist-anime-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,axiomworks/myanimelist-anime-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/M7GlrJLclMsUMCFgL/builds/wtcLZAf3aKVAPH8GZ/openapi.json
