A complete RESTful API for anime streaming data powered by AniList GraphQL and Miruro providers
Search, browse, filter, watch β every endpoint returns fresh data with smart caching.
18 endpoints, 12 streaming providers, M3U8 URLs with subtitles and skip timestamps.
Table of Contents β’ Features β’ API Docs β’ Quick Start β’ Deployment β’ Contributing
Warning
- This
APIdoes not store any files β it only links to media hosted on 3rd party services. - This
APIis explicitly made for educational purposes only and not for commercial usage. This repo will not be responsible for any misuse of it. - All anime data, images, and content belong to their respective owners (AniList, Miruro). This project is not affiliated with miruro.tv.
- Overview
- Features
- Data Sources
- Tech Stack
- Architecture
- Project Structure
- Quick Start
- Configuration
- API Endpoints
- Streaming Flow
- API Response Schema
- Deployment
- Available Scripts
- Performance
- Changelog Highlights
- Troubleshooting
- FAQ
- Roadmap
- Contributing
- Acknowledgements
- License
- Author
- Star History
MiruroAPI is a serverless anime data API that fetches real-time information from AniList GraphQL and streaming data from Miruro providers β including anime details, episode lists, M3U8 streaming URLs with subtitles and skip timestamps, search, filtering, characters, and more β all through a clean REST API with zero database.
π‘ No database, no auth, no complex setup. Just deploy to Vercel and you have a production API.
- π¬ 18 Endpoints β Complete anime data coverage
- π Full-Text Search β Search anime by keyword with suggestions
- π Characters & Voice Actors β Full character data from AniList
- π― Advanced Filtering β Genre, year, season, format, sort
- π Trending & Popular β Discover what's hot right now
- π Airing Schedule β See what's airing on any date
- π‘ 12 Streaming Providers β M3U8 streaming sources
- βοΈ Skip Timestamps β OP/ED skip data
- β‘ Smart Caching β In-memory Map with configurable TTL
- π CORS Enabled β Works from any frontend, no proxy needed
- π Zero-Config Deploy β One click to Vercel, or run standalone with Express
flowchart TD
A["π Client Request<br/>(Browser / App / curl)"] --> B["π‘οΈ Express Server<br/>CORS Β· Security Headers Β· Rate Limiting"]
B --> C{"πΎ Cache Check<br/>(In-Memory Map)"}
C -- HIT --> D["β‘ Return Cached Response<br/>~50ms"]
C -- MISS --> E{"π Which Source?"}
E -- Metadata --> F["π‘ AniList GraphQL<br/>graphql.anilist.co"]
E -- Streaming --> G["πΊ Miruro Pipe<br/>miruro.tv/api/secure/pipe"]
F --> H["AniList Response<br/>JSON"]
G --> I["Pipe Response<br/>base64url + gzip"]
H --> J["Cache + Respond<br/>JSON"]
I --> J
style A fill:#1e1e2e,stroke:#a78bfa,color:#f1f5f9
style B fill:#1e1e2e,stroke:#6366f1,color:#f1f5f9
style C fill:#1e1e2e,stroke:#f43f8e,color:#f1f5f9
style D fill:#1e1e2e,stroke:#22c55e,color:#f1f5f9
style E fill:#1e1e2e,stroke:#a855f7,color:#f1f5f9
style F fill:#1e1e2e,stroke:#06b6d4,color:#f1f5f9
style G fill:#1e1e2e,stroke:#eab308,color:#f1f5f9
style H fill:#1e1e2e,stroke:#06b6d4,color:#f1f5f9
style I fill:#1e1e2e,stroke:#eab308,color:#f1f5f9
style J fill:#1e1e2e,stroke:#22c55e,color:#f1f5f9
|
|
|
|
| Feature | Description | Status |
|---|---|---|
| π¬ 18 API Endpoints | Complete anime data coverage | β |
| π Full-Text Search | Keyword search with pagination | β |
| π‘ Search Suggestions | Fast autocomplete | β |
| π― Advanced Filtering | Genre, year, season, format, sort | β |
| π Characters + Voice Actors | Full character data from AniList | β |
| π Relations & Recommendations | Related anime discovery | β |
| βοΈ Skip Timestamps | OP/ED skip data | β |
| π‘ 12 Streaming Providers | M3U8 streaming sources | β |
| π Smart Caching | In-memory Map with TTL | β |
| π One-Click Deploy | Vercel button deployment | β |
| ποΈ Express Mode | Standalone server with npm start |
β |
| π³ Docker Support | Containerized deployment | β |
| Source | API | Data |
|---|---|---|
| πΈ AniList | graphql.anilist.co |
Search, info, characters, relations, recommendations, filter, schedule |
| Source | Domain | Data |
|---|---|---|
| πΊ Miruro | miruro.tv |
Episodes, streaming sources (M3U8 URLs) |
| πΊ Miruro | miruro.to |
Mirror domain |
| πΊ Miruro | miruro.bz |
Mirror domain |
| πΊ Miruro | miruro.ru |
Mirror domain |
| Provider | Provider | Provider | Provider |
|---|---|---|---|
| π₯ kiwi | π pewe | π» bee | π― bonk |
| π bun | π€ ally | π¦ nun | π― twin |
| βοΈ cog | π moo | π° hop | πΊ telli |
| Technology | Purpose | Version | Documentation |
|---|---|---|---|
| π’ Node.js | JavaScript runtime | >= 20 | Docs |
| β‘ Express | HTTP server framework | 4.21 | Docs |
| β² Vercel Functions | Serverless deployment | β | Docs |
| πΈ AniList GraphQL | Anime metadata API | β | Docs |
| π Axios | HTTP client | 1.8 | Docs |
| π§ dotenv | Environment variables | 16.4 | Docs |
| π cors | CORS middleware | 2.8 | Docs |
{
"express": "^4.21.0", // HTTP server
"axios": "^1.8.0", // HTTP client
"cors": "^2.8.5", // CORS middleware
"dotenv": "^16.4.0" // Environment variables
}| Stage | Component | Description |
|---|---|---|
| 1 | Client | Browser, app, or curl sends request |
| 2 | Express Server | Routes request, applies CORS + security headers + rate limiting |
| 3 | Cache Check | In-memory Map with TTL β hit = instant response |
| 4 | Fetch Data | AniList GraphQL or Miruro pipe endpoint |
| 5 | Decode | Pipe responses decoded: base64url β gunzip β JSON |
| 6 | Cache + Respond | Store in cache, return JSON response |
flowchart TD
A["π₯ Request"] --> B{"π§ Memory Cache<br/>(Map + TTL)"}
B -- HIT --> C["β‘ Return Cached<br/>~50ms"]
B -- MISS --> D["π‘ Fetch from<br/>AniList / Miruro"]
D --> E["π Decode<br/>base64url + gzip"]
E --> F["πΎ Cache Result<br/>(1-5 min TTL)"]
F --> G["π€ Return Fresh"]
style A fill:#1e1e2e,stroke:#a78bfa,color:#f1f5f9
style B fill:#1e1e2e,stroke:#f43f8e,color:#f1f5f9
style C fill:#1e1e2e,stroke:#22c55e,color:#f1f5f9
style D fill:#1e1e2e,stroke:#6366f1,color:#f1f5f9
style E fill:#1e1e2e,stroke:#06b6d4,color:#f1f5f9
style F fill:#1e1e2e,stroke:#a855f7,color:#f1f5f9
style G fill:#1e1e2e,stroke:#22c55e,color:#f1f5f9
π‘ Serverless functions have read-only filesystems except
/tmp. The cache uses in-memoryMapwhich survives across warm invocations.
MiruroAPI/
βββ π public/ # π Static files
β βββ π index.html # π Premium landing page (real Miruro icons)
β βββ π docs.html # π Swagger UI interactive documentation
β βββ π openapi.json # π OpenAPI 3.0 spec
β βββ π icon-dark.svg # π Miruro dark mode favicon
β βββ π icon-light.svg # βοΈ Miruro light mode favicon
β βββ π icon-512x512.png # π± Miruro app icon
β βββ π favicon.ico # π Classic favicon
β βββ π apple-touch-icon-180x180.png # π iOS home screen icon
β βββ π og-image.png # πΌοΈ OG/Twitter share image
β
βββ π assets/ # π¨ Scraped Miruro assets
β βββ π favicons/ # π All favicon variants
β βββ π logos/ # π·οΈ Status page logo
β βββ π fonts/ # π€ Inter + FontAwesome
β βββ π media/ # πΌοΈ Testimonial avatars
β
βββ π src/ # βοΈ Core logic
β βββ π helpers/ # π οΈ Integration modules
β β βββ π anilist.js # πΈ AniList GraphQL integration
β β βββ π pipe.js # πΊ Miruro pipe integration
β β βββ π cache.js # πΎ In-memory cache with TTL
β β
β βββ π routes/ # π€οΈ Express routes
β βββ π apiRoutes.js # π Main API routes (18 endpoints)
β
βββ π server.js # π Express server entry point
βββ π package.json # π¦ Dependencies & scripts
βββ π vercel.json # β² Vercel routing config
βββ π Dockerfile # π³ Docker support
βββ π .dockerignore # π³ Docker ignore
βββ π CHANGELOG.md # π Version history
βββ π README.md # π This file
| Requirement | Minimum | Recommended |
|---|---|---|
| π¦ Node.js | 20.x | 20.x LTS |
| π¦ npm | 9.0+ | 10.x |
| π» OS | Windows, macOS, Linux | Any |
# 1οΈβ£ Clone the repository
git clone https://github.com/Shineii86/MiruroAPI.git
cd MiruroAPI
# 2οΈβ£ Install dependencies
npm install
# 3οΈβ£ Start development server
npm run devπ Open http://localhost:3000 in your browser.
# Start production server
npm start# Using yarn
yarn install
yarn dev
# Using pnpm
pnpm install
pnpm dev
# Using bun
bun install
bun dev| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
Server port (Express mode only) |
ALLOWED_ORIGINS |
* |
Comma-separated allowed origins |
The vercel.json file handles:
- Builds β Maps
server.jsto@vercel/node - Routes β All requests forwarded to Express
https://mirurotvapi.vercel.app/api
All endpoints return:
{
"success": true,
"results": { ... }
}To get a stream URL, follow these 3 steps:
# Step 1: Get episodes (returns provider slugs)
curl "https://mirurotvapi.vercel.app/api/episodes/20"
# Step 2: Get streaming sources (pass provider + anilistId + category + slug)
curl "https://mirurotvapi.vercel.app/api/watch/kiwi/20/sub/animepahe-1"
# Step 3: Play M3U8 in any HLS player
# Use hls.js, video.js, or native <video> with hls supportProviders return both sub and dub episode lists:
const eps = await fetch("/api/episodes/20").then(r => r.json());
const kiwi = eps.results.providers.kiwi.episodes;
// Pick sub or dub
const subEps = kiwi.sub; // [{ id: "watch/kiwi/20/sub/anikoto-1", ... }]
const dubEps = kiwi.dub; // [{ id: "watch/kiwi/20/dub/...", ... }]
// Get stream URL
const stream = await fetch(`/api/watch/kiwi/20/sub/animepahe-1`).then(r => r.json());
// stream.results.streams[0].url = "https://...m3u8"/healthNo parameters required.
curl "https://mirurotvapi.vercel.app/api/health"import axios from "axios";
const resp = await axios.get("https://mirurotvapi.vercel.app/api/health");
console.log(resp.data);{
"success": true,
"results": {
"status": "healthy",
"version": "1.2.0",
"uptime": "0h 0m 34s",
"uptimeSeconds": 34,
"timestamp": "2026-06-09T09:55:00.884Z",
"node": "v24.14.1",
"memory": { "used": "13MB", "total": "15MB" },
"endpoints": 16,
"providers": ["kiwi","pewe","bee","bonk","bun","ally","nun","twin","cog","moo","hop","telli"]
}
}/statsNo parameters required.
curl "https://mirurotvapi.vercel.app/api/stats"import axios from "axios";
const resp = await axios.get("https://mirurotvapi.vercel.app/api/stats");
console.log(resp.data);{
"success": true,
"results": {
"uptime": "0h 0m 34s",
"requests": { "total": 156, "errors": 3, "successRate": "98.1%" },
"cache": { "size": 12, "maxSize": 100, "ttl": "1 min" },
"endpoints": 16,
"timestamp": "2026-06-09T09:55:00.884Z"
}
}/search| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
query |
string |
Yes βοΈ | β | Search keyword |
page |
number |
No | 1 |
Page number |
per_page |
number |
No | 20 |
Results per page |
curl "https://mirurotvapi.vercel.app/api/search?query=naruto&per_page=2"import axios from "axios";
const resp = await axios.get("https://mirurotvapi.vercel.app/api/search", {
params: { query: "naruto", per_page: 2 }
});
console.log(resp.data);{
"success": true,
"results": {
"page": 1,
"perPage": 2,
"total": 5000,
"hasNextPage": true,
"results": [
{
"id": 20,
"title": { "romaji": "NARUTO", "english": "Naruto", "native": "NARUTO -γγ«γ-" },
"coverImage": { "large": "https://s4.anilist.co/file/anilistcdn/media/anime/cover/medium/bx20-dE6UHbFFg1A5.jpg" },
"format": "TV",
"season": "FALL",
"seasonYear": 2002,
"episodes": 220,
"status": "FINISHED",
"averageScore": 80,
"genres": ["Action","Adventure","Comedy","Drama","Fantasy","Supernatural"]
}
]
}
}/suggestions| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
query |
string |
Yes βοΈ | β | Search keyword |
curl "https://mirurotvapi.vercel.app/api/suggestions?query=naruto"import axios from "axios";
const resp = await axios.get("https://mirurotvapi.vercel.app/api/suggestions", {
params: { query: "naruto" }
});
console.log(resp.data);{
"success": true,
"results": [
{ "id": 20, "title": "Naruto", "title_romaji": "NARUTO", "poster": "https://s4.anilist.co/file/...", "format": "TV", "status": "FINISHED", "year": 2002, "episodes": 220 },
{ "id": 1735, "title": "Naruto: Shippuden", "title_romaji": "NARUTO: Shippuuden", "poster": "https://s4.anilist.co/file/...", "format": "TV", "status": "FINISHED", "year": 2007, "episodes": 500 }
]
}/filter| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
genre |
string |
No | β | Genre name (e.g. "Action") |
tag |
string |
No | β | Tag name |
year |
number |
No | β | Release year |
season |
string |
No | β | FALL, WINTER, SPRING, SUMMER |
format |
string |
No | β | TV, MOVIE, OVA, ONA, SPECIAL, MUSIC |
status |
string |
No | β | RELEASING, FINISHED, NOT_YET_RELEASED, CANCELLED |
sort |
string |
No | POPULARITY_DESC | Sort order |
page |
number |
No | 1 |
Page number |
per_page |
number |
No | 20 |
Results per page |
curl "https://mirurotvapi.vercel.app/api/filter?genre=Action&year=2024&season=WINTER&per_page=3"import axios from "axios";
const resp = await axios.get("https://mirurotvapi.vercel.app/api/filter", {
params: { genre: "Action", year: 2024, season: "WINTER", per_page: 3 }
});
console.log(resp.data);{
"success": true,
"results": {
"page": 1,
"perPage": 3,
"total": 5000,
"hasNextPage": true,
"results": [
{
"id": 21,
"title": { "romaji": "ONE PIECE", "english": "One Piece" },
"coverImage": { "large": "https://..." },
"format": "TV",
"status": "RELEASING",
"averageScore": 85
}
]
}
}/trending| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
per_page |
number |
No | 20 |
Results per page |
curl "https://mirurotvapi.vercel.app/api/trending?per_page=3"import axios from "axios";
const resp = await axios.get("https://mirurotvapi.vercel.app/api/trending", {
params: { per_page: 3 }
});
console.log(resp.data);{
"success": true,
"results": {
"page": 1,
"perPage": 3,
"total": 5000,
"hasNextPage": true,
"results": [
{
"id": 21,
"title": { "romaji": "ONE PIECE", "english": "One Piece" },
"coverImage": { "large": "https://..." },
"format": "TV",
"status": "RELEASING",
"averageScore": 85
}
]
}
}/popular| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
per_page |
number |
No | 20 |
Results per page |
curl "https://mirurotvapi.vercel.app/api/popular?per_page=3"import axios from "axios";
const resp = await axios.get("https://mirurotvapi.vercel.app/api/popular", {
params: { per_page: 3 }
});
console.log(resp.data);/upcoming| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
per_page |
number |
No | 20 |
Results per page |
curl "https://mirurotvapi.vercel.app/api/upcoming?per_page=3"import axios from "axios";
const resp = await axios.get("https://mirurotvapi.vercel.app/api/upcoming", {
params: { per_page: 3 }
});
console.log(resp.data);/recent| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
per_page |
number |
No | 20 |
Results per page |
curl "https://mirurotvapi.vercel.app/api/recent?per_page=3"import axios from "axios";
const resp = await axios.get("https://mirurotvapi.vercel.app/api/recent", {
params: { per_page: 3 }
});
console.log(resp.data);/spotlightNo parameters required.
curl "https://mirurotvapi.vercel.app/api/spotlight"import axios from "axios";
const resp = await axios.get("https://mirurotvapi.vercel.app/api/spotlight");
console.log(resp.data);{
"success": true,
"results": [
{
"id": 21,
"title": { "romaji": "ONE PIECE", "english": "One Piece" },
"coverImage": { "large": "https://..." },
"bannerImage": "https://...",
"format": "TV",
"episodes": null,
"status": "RELEASING",
"averageScore": 85,
"genres": ["Action","Adventure","Comedy","Fantasy"],
"description": "Gol D. Roger was known as the Pirate King..."
}
]
}/schedule| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
date |
string |
No | today | Date in YYYY-MM-DD format |
curl "https://mirurotvapi.vercel.app/api/schedule?date=2026-06-09"import axios from "axios";
const resp = await axios.get("https://mirurotvapi.vercel.app/api/schedule", {
params: { date: "2026-06-09" }
});
console.log(resp.data);/info/:id| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
id |
number |
Yes βοΈ | β | AniList anime ID |
curl "https://mirurotvapi.vercel.app/api/info/20"import axios from "axios";
const resp = await axios.get("https://mirurotvapi.vercel.app/api/info/20");
console.log(resp.data);{
"success": true,
"results": {
"id": 20,
"idMal": 20,
"title": { "romaji": "NARUTO", "english": "Naruto", "native": "NARUTO -γγ«γ-" },
"description": "Naruto Uzumaki, a hyperactive and knuckle-headed ninja...",
"coverImage": { "large": "https://s4.anilist.co/file/..." },
"bannerImage": "https://s4.anilist.co/file/...",
"format": "TV",
"season": "FALL",
"seasonYear": 2002,
"episodes": 220,
"duration": 23,
"status": "FINISHED",
"averageScore": 80,
"popularity": 694959,
"genres": ["Action","Adventure","Comedy","Drama","Fantasy","Supernatural"],
"studios": [{ "name": "Studio Pierrot", "isAnimationStudio": true }],
"startDate": { "year": 2002, "month": 10, "day": 3 },
"endDate": { "year": 2007, "month": 2, "day": 8 }
}
}/anime/:id/characters| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
id |
number |
Yes βοΈ | β | AniList anime ID |
curl "https://mirurotvapi.vercel.app/api/anime/20/characters"import axios from "axios";
const resp = await axios.get("https://mirurotvapi.vercel.app/api/anime/20/characters");
console.log(resp.data);{
"success": true,
"results": {
"edges": [
{
"role": "MAIN",
"node": {
"id": 17,
"name": { "full": "Naruto Uzumaki", "native": "γγγΎγγγ«γ" },
"image": { "large": "https://s4.anilist.co/file/..." }
},
"voiceActors": [
{
"id": 95015,
"name": { "full": "Junko Takeuchi", "native": "η«Ήε
ι ε" },
"languageV2": "Japanese"
}
]
}
]
}
}/anime/:id/relations| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
id |
number |
Yes βοΈ | β | AniList anime ID |
curl "https://mirurotvapi.vercel.app/api/anime/20/relations"import axios from "axios";
const resp = await axios.get("https://mirurotvapi.vercel.app/api/anime/20/relations");
console.log(resp.data);/anime/:id/recommendations| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
id |
number |
Yes βοΈ | β | AniList anime ID |
curl "https://mirurotvapi.vercel.app/api/anime/20/recommendations"import axios from "axios";
const resp = await axios.get("https://mirurotvapi.vercel.app/api/anime/20/recommendations");
console.log(resp.data);/episodes/:id| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
id |
number |
Yes βοΈ | β | AniList anime ID |
curl "https://mirurotvapi.vercel.app/api/episodes/20"import axios from "axios";
const resp = await axios.get("https://mirurotvapi.vercel.app/api/episodes/20");
console.log(resp.data);{
"success": true,
"results": {
"providers": {
"kiwi": {
"meta": { "id": "1571", "title": "Naruto", "type": "TV" },
"episodes": {
"sub": [
{
"id": "watch/kiwi/20/sub/anikoto-1",
"number": 1,
"title": "Enter: Naruto Uzumaki!",
"image": "https://image.tmdb.org/t/p/original/...",
"airDate": "2002-10-03",
"audio": "sub",
"filler": false,
"fillerType": "manga_canon"
}
]
}
}
}
}
}/watch/:provider/:anilistId/:category/:slug| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
provider |
string |
Yes βοΈ | β | Provider name (kiwi, pewe, etc.) |
anilistId |
number |
Yes βοΈ | β | AniList anime ID |
category |
string |
Yes βοΈ | β | sub or dub |
slug |
string |
Yes βοΈ | β | Episode slug from episodes response |
curl "https://mirurotvapi.vercel.app/api/watch/kiwi/20/sub/animepahe-1"import axios from "axios";
const resp = await axios.get("https://mirurotvapi.vercel.app/api/watch/kiwi/20/sub/animepahe-1");
console.log(resp.data);{
"success": true,
"results": {
"streams": [
{
"url": "https://vault-01.uwucdn.top/stream/.../uwu.m3u8",
"type": "hls",
"quality": "360p",
"resolution": { "width": 640, "height": 360 },
"codec": "h264",
"audio": "sub",
"fansub": "df68",
"isActive": false,
"referer": "https://kwik.cx/e/..."
},
{
"url": "https://kwik.cx/e/...",
"type": "embed",
"quality": "360p",
"codec": "h264",
"audio": "sub",
"fansub": "df68",
"isActive": false
}
],
"download": "https://pahe.win/LJmbA"
}
}To get a stream URL, follow these 3 steps:
# Step 1: Get episodes (returns provider slugs)
curl "https://mirurotvapi.vercel.app/api/episodes/20"
# => providers.kiwi.episodes.sub[0].id = "watch/kiwi/20/sub/anikoto-1"
# Step 2: Get streaming sources
curl "https://mirurotvapi.vercel.app/api/watch/kiwi/20/sub/animepahe-1"
# => streams[0].url = "https://...m3u8"
# Step 3: Play M3U8 in any HLS player
# Use hls.js, video.js, or native <video> with hls supportProviders return both sub and dub episode lists:
const eps = await fetch("/api/episodes/20").then(r => r.json());
const providers = eps.results.providers;
// Pick provider
const kiwi = providers.kiwi.episodes;
// Get sub episodes
const subEps = kiwi.sub; // [{ id: "watch/kiwi/20/sub/anikoto-1", ... }]
// Get dub episodes (if available)
const dubEps = kiwi.dub || []; // [{ id: "watch/kiwi/20/dub/...", ... }]<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<video id="player" controls></video>
<script>
const video = document.getElementById('player');
const streamUrl = 'https://...m3u8'; // From /api/watch response
if (Hls.isSupported()) {
const hls = new Hls();
hls.loadSource(streamUrl);
hls.attachMedia(video);
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = streamUrl; // Native HLS (Safari)
}
</script>{
"success": true,
"results": { ... }
}{
"success": false,
"message": "Error description"
}| Field | Type | Description | Example |
|---|---|---|---|
id |
number |
AniList ID | 20 |
title |
object |
{ romaji, english, native } |
{ "romaji": "NARUTO" } |
coverImage |
object |
{ large } |
{ "large": "https://..." } |
format |
string |
Anime format | "TV" |
status |
string |
Release status | "FINISHED" |
episodes |
number |
Total episodes | 220 |
averageScore |
number |
AniList score | 80 |
genres |
string[] |
Genre list | ["Action","Adventure"] |
| Field | Type | Description | Example |
|---|---|---|---|
id |
string |
Watch slug | "watch/kiwi/20/sub/anikoto-1" |
number |
number |
Episode number | 1 |
title |
string |
Episode title | "Enter: Naruto Uzumaki!" |
image |
string |
Thumbnail URL | "https://..." |
airDate |
string |
Air date | "2002-10-03" |
audio |
string |
sub or dub |
"sub" |
filler |
boolean |
Is filler episode | false |
| Field | Type | Description | Example |
|---|---|---|---|
url |
string |
M3U8 or embed URL | "https://...m3u8" |
type |
string |
hls or embed |
"hls" |
quality |
string |
Video quality | "720p" |
resolution |
object |
{ width, height } |
{ "width": 1280, "height": 720 } |
codec |
string |
Video codec | "h264" |
audio |
string |
sub or dub |
"sub" |
fansub |
string |
Fansub group | "df68" |
isActive |
boolean |
Is active stream | false |
referer |
string |
Referer URL | "https://kwik.cx/e/..." |
- Click the button above (or import manually on vercel.com)
- Vercel auto-detects the project β no config needed
- Your API is live! π
# Or use Vercel CLI
npx vercel --prod# Clone and install
git clone https://github.com/Shineii86/MiruroAPI.git
cd MiruroAPI && npm install
# Start production server
npm start
# β http://localhost:3000# Build
docker build -t miruroapi .
# Run
docker run -p 3000:3000 miruroapi| Command | Description | Details |
|---|---|---|
npm run dev |
π₯ Start development server | Runs on localhost:3000 |
npm start |
π Start production server | node server.js |
| Metric | Value |
|---|---|
| β‘ Cold start | ~500ms |
| π Warm response | ~50-200ms |
| πΎ Cache hit | ~10ms |
| πΎ Cache TTL | 1-5 minutes |
| β±οΈ Rate limit | 100 req/min/IP |
| π» Memory usage | ~15MB |
| π¦ Cache max size | 100 entries |
- πΎ In-memory cache β Map-based with TTL expiration
- β‘ Pipe decoding β Efficient base64url + gzip decompression
- π― Selective fetching β Only AniList GraphQL or Miruro pipe
- π Minimal deps β Only 4 production dependencies
- π Graceful fallback β Empty arrays on error, never crashes
| Version | Date | Key Changes |
|---|---|---|
| 1.2.0 | 2026-06-09 | Critical response format fix, full endpoint diagnostic, 18/18 passing |
| 1.1.0 | 2026-06-09 | Swagger UI docs, OpenAPI spec, mappings field, Docker, landing page |
| 1.0.0 | 2026-06-09 | Initial release β 16 endpoints, AniList GraphQL + Miruro pipe, caching |
π See CHANGELOG.md for the full version history.
| Problem | Cause | Solution |
|---|---|---|
β npm install fails |
Node.js version too old | Upgrade to Node.js 20+ (node -v) |
| β CORS errors | Frontend domain blocked | CORS is * β check browser extension |
| β 404 on API routes | Wrong URL format | Use /api/ prefix, not just / |
| β Empty episodes | Provider not available | Check which providers return data for the anime |
| β Deploy fails on Vercel | Build error | Check node server.js locally first |
| β Slow first request | Serverless cold start | Normal β first request after idle takes ~500ms |
| β Rate limited | Too many requests | Cache reduces this β wait for TTL expiry |
# Run with verbose logging
NODE_ENV=development npm run dev
# Test specific endpoint
curl http://localhost:3000/api/health
curl http://localhost:3000/api/search?query=naruto
curl http://localhost:3000/api/episodes/20π How do I search for anime?
Use
/api/search?query=your+search. Results include title, cover, format, status, episodes, and score. For autocomplete suggestions, use /api/suggestions?query=your+search which returns fast suggestions.
πΊ How do I get episode lists?
Use
/api/episodes/:id where :id is the AniList anime ID (e.g., 20 for Naruto). The response includes all providers with sub/dub episode lists.
π― How does filtering work?
Use
/api/filter with query params. Combine genre, year, season, format, status, and sort for advanced filtering. All params are optional.
π‘ Can I use this in my frontend app?
Yes! CORS is enabled for all origins (
*). Just make fetch requests to the API endpoints. No API key needed. Example: fetch('https://mirurotvapi.vercel.app/api/search?query=naruto')
π How often does the data refresh?
The cache TTL is 1-5 minutes depending on the endpoint. After that, the next request triggers a fresh fetch from AniList/Miruro.
π Can I self-host this?
Yes! Use
npm start to run the Express server on any VPS, Docker container, or PaaS. The Vercel serverless functions are optional β server.js handles everything.
π¬ Which streaming providers are available?
12 providers: kiwi, pewe, bee, bonk, bun, ally, nun, twin, cog, moo, hop, telli. Not all anime are available on every provider.
- π API key authentication β Per-user rate limits
- π Analytics endpoint β Usage statistics
- π Dark/light mode β Theme toggle for landing page
- π± PWA support β Install as app on mobile
- π Webhook notifications β Push new episodes to Discord
- ποΈ Redis cache β Persistent caching for serverless
- π Multi-language β Sub/dub language metadata
- π¦ NPM package β Client SDK for easy integration
- π¬ 18 API endpoints covering all data
- π Full-text search with pagination
- π‘ Search suggestions for autocomplete
- π― Advanced filtering (genre, year, season, format, sort)
- π Characters + voice actors from AniList
- π Relations and recommendations
- βοΈ Skip timestamps (OP/ED)
- π‘ 12 streaming providers with M3U8 URLs
- π Smart caching with configurable TTL
- π One-click Vercel deployment
- π³ Docker support
- π Swagger UI interactive docs
- π Comprehensive documentation with real API data
Contributions are welcome and appreciated! Here's how you can help:
|
Found something broken? |
Have an idea? |
Ready to contribute code? |
# 1οΈβ£ Fork the repository
# Click the "Fork" button on GitHub
# 2οΈβ£ Clone your fork
git clone https://github.com/YOUR_USERNAME/MiruroAPI.git
cd MiruroAPI
# 3οΈβ£ Create a feature branch
git checkout -b feature/amazing-feature
# 4οΈβ£ Make your changes
# Edit files, add features, fix bugs...
# 5οΈβ£ Commit your changes
git commit -m 'feat: add amazing feature'
# 6οΈβ£ Push to your fork
git push origin feature/amazing-feature
# 7οΈβ£ Open a Pull Request
# Go to GitHub and create a PR- β Follow the existing code style and documentation conventions
- β Write meaningful commit messages (use conventional commits)
- β Update CHANGELOG.md with your changes
- β Keep PRs focused β one feature or fix per PR
- β Add JSDoc comments for new functions
- β Don't commit
node_modulesor cache files - β Don't add unrelated changes to a single PR
| Source | About |
|---|---|
| AniList | Anime metadata API (GraphQL) |
| Miruro | Anime streaming site β source for episodes and streaming |
| Miruro TO | Mirror domain |
| Miruro BZ | Mirror domain |
| Miruro RU | Mirror domain |
- Express β Fast, unopinionated web framework
- AniList GraphQL β Rich anime metadata
- Axios β Promise-based HTTP client
- Vercel β Serverless deployment platform
- Shields.io β Badges for README
- Star History β GitHub star history charts
- Capsule Render β Header banner generator
This project is licensed under the MIT License.
Free to use, modify, and distribute β see the LICENSE file for details.
Shinei Nouzen
Full-Stack Developer & Anime Enthusiast
β If you found this project useful, please consider giving it a star!
Made With β€οΈ For The Anime Community
Β© Shinei Nouzen. All Rights Reserved.