Getting Started
A small Typescript SDK for searching anime and manga, listing episodes/chapters, and resolving direct stream/page URLs (with subtitle tracks). Nine providers, a handful of reusable embed extractors, a pluggable HTTP transport, and an optional HTTP server with a stream/subtitle proxy and a bring-your-own cache hook.
Requirements
Section titled “Requirements”- Node 20+ or Bun: native
fetchandcrypto.subtleare required - ffmpeg: only needed to run the live E2E test suite for anime streams
Install
Section titled “Install”npm install anime-sdk# -- or --pnpm add anime-sdk# -- or --bun add anime-sdkHow it works
Section titled “How it works”Every provider exposes the same three methods: search → fetchContentUnits → resolveStream.
import { HttpClient, GogoanimeProvider, MangadexProvider } from 'anime-sdk';
const client = new HttpClient({ timeoutMs: 10_000 });
// Anime exampleconst anime = new GogoanimeProvider(client);const shows = await anime.search('Frieren');const eps = await anime.fetchContentUnits(shows[0].id);const stream = await anime.resolveStream(eps[0].id, 'sub');
// Manga exampleconst manga = new MangadexProvider(client);const books = await manga.search('Frieren');const chapters = await manga.fetchContentUnits(books[0].id);const pages = await manga.resolveStream(chapters[0].id);The resolved stream shape
Section titled “The resolved stream shape”resolveStream returns ResolvedMediaStream: a discriminated union on type:
type ResolvedMediaStream = | { type: 'video'; streams: IVideoPayload[] } | { type: 'manga'; pages: IMangaPayload };Manga providers return type: 'manga', while anime providers return type: 'video'. Always check result.type before accessing the payload.
Each IMangaPayload carries:
interface IMangaPayload { imageUrls: string[]; // high-resolution image URLs for each page headers?: Record<string, string>; // Referer required by some sites}Each IVideoPayload in the streams array has:
interface IVideoPayload { sourceUrl: string; // direct URL or HLS manifest isHLS: boolean; // true → feed to an HLS player quality: '1080p' | '720p' | '480p' | '360p' | 'auto'; language?: ContentLanguage; headers?: Record<string, string>; // Referer/User-Agent required by some CDNs subtitles?: ISubtitleTrack[]; // external VTT tracks, when the provider has them}
interface ISubtitleTrack { url: string; language: string; // BCP-47 (e.g. 'en', 'pt-BR') label: string; // human-readable ("English", "Português") format?: 'vtt' | 'srt' | 'ass';}Sub / dub / raw
Section titled “Sub / dub / raw”fetchContentUnits returns one unified episode list: each IContentUnit advertises its translations via availableLanguages: ContentLanguage[]. The translation is picked at resolveStream time:
type ContentLanguage = 'sub' | 'dub' | 'raw';const eps = await provider.fetchContentUnits(shows[0].id);const ep = eps[0]; // ep.availableLanguages tells you what's playableconst result = await provider.resolveStream(ep.id, 'dub');Providers that don’t support the requested language fall back to 'sub'.
Inspecting tracks without resolving the stream
Section titled “Inspecting tracks without resolving the stream”Some providers expose a cheap metadata endpoint so a UI can show the subtitle/quality selector before playback. Implement (or call) fetchUnitTracks when available:
if (provider.fetchUnitTracks) { const { subtitles, qualities } = await provider.fetchUnitTracks(ep.id, 'sub'); // subtitles: ISubtitleTrack[], qualities: IVideoPayload['quality'][]}Providers without a cheap path leave the method undefined: read IVideoPayload.subtitles straight off the resolved stream instead.
Using the resolved URL
Section titled “Using the resolved URL”Pass sourceUrl directly to any HLS player or downloader. Many CDNs require the headers object to be forwarded:
const hls = new Hls();hls.loadSource(stream.sourceUrl);// hls.js doesn't support custom headers on fetch: serve through your HTTP server instead
// ffmpeg// ffmpeg -i "url" -headers "Referer: ..." output.mp4
// React Native / Video<Video source={{ uri: stream.sourceUrl, headers: stream.headers }} />Downloading to disk
Section titled “Downloading to disk”The SDK includes built-in download utilities. HLS anime streams are downloaded by fetching segments and muxing with ffmpeg; direct MP4s stream straight to disk. Manga chapters are packaged as .zip archives.
import { downloadVideo, downloadMangaChapter } from 'anime-sdk';
// Anime: resolveStream → downloadVideoconst animeResult = await animeProvider.resolveStream(eps[0].id, 'sub');if (animeResult.type === 'video') { const { outputPath, fileSize } = await downloadVideo(animeResult.streams, './episode-1.mp4', { onProgress: ({ phase, detail }) => console.log(`[${phase}] ${detail ?? ''}`), }); console.log(`Saved ${fileSize} bytes → ${outputPath}`);}
// Manga: resolveStream → downloadMangaChapterconst mangaResult = await mangaProvider.resolveStream(chapters[0].id);if (mangaResult.type === 'manga') { const { pageCount, outputPath } = await downloadMangaChapter(mangaResult.pages, './ch-1.zip', { onProgress: ({ downloaded, total }) => console.log(`${downloaded}/${total}`), }); console.log(`Packed ${pageCount} pages → ${outputPath}`);}Pass the full streams array to downloadVideo and it tries each candidate in order, falling back automatically on failure. See Downloads for the full API including batch downloads and low-level HLS helpers.
Swapping providers
Section titled “Swapping providers”The three calls are identical across providers. Swap the import and constructor, nothing else changes:
import { AllmangaProvider } from 'anime-sdk';const provider = new AllmangaProvider(new HttpClient());// same: search → fetchContentUnits → resolveStreamNext steps
Section titled “Next steps”- Browse providers: AllManga, Gogoanime, Anikoto, Goyabu
- Downloads: save episodes as MP4 and chapters as ZIP
- Run the HTTP server: call anime-sdk from any language
- Full API reference
- Add a provider