fastsaverapi
v0.1.0
Published
Official FastSaverAPI SDK for Node.js and TypeScript: Instagram, TikTok (no watermark), YouTube (MP4 up to 4K, MP3), Pinterest, Facebook, X/Twitter, RuTube and Likee downloader API, YouTube audio as a Telegram file_id, and Shazam song recognition. Zero de
Maintainers
Keywords
Readme
fastsaverapi: Instagram, TikTok and YouTube downloader API for Node.js and TypeScript
One typed API to download Instagram reels and posts, TikTok videos without watermark, YouTube
as MP4 (up to 4K) or MP3, plus Pinterest, Facebook, X/Twitter, RuTube and Likee. Includes Shazam
song recognition and YouTube audio delivered as a Telegram file_id for music bots. Zero
dependencies; Node.js, Bun, Deno, Cloudflare Workers and Vercel Edge. Free tier: 1,000 credits,
no credit card.
import { FastSaver } from 'fastsaverapi'
const client = new FastSaver({ apiKey: 'fs_sk_...' }) // or set FASTSAVER_API_KEY
const video = await client.fetch('https://www.tiktok.com/@scout2015/video/6718335390845095173')
console.log(video.downloadUrl) // direct MP4 link, no watermarkStart free: 1,000 credits, no credit card. Create a key at api.fastsaver.io (email, Google or Telegram login),
npm install fastsaverapi, and you are downloading in under a minute. Or try it from the shell:FASTSAVER_API_KEY=fs_sk_... npx fastsaverapi fetch <url>
Sign up · API docs · Pricing · Telegram community · Python SDK
Table of contents
- Why FastSaverAPI · vs DIY scrapers
- Platforms and credits · Install · API key · Quickstart
- Instagram · TikTok · YouTube MP4/MP3 · Telegram bots · Pinterest, Facebook, X, RuTube, Likee · Shazam
- Errors · Retries, timeouts, proxies · Edge runtimes · CLI · Credits and rate limits · FAQ
Why FastSaverAPI
Scraping social networks yourself means proxies, cookies, IP bans, captchas and a parser that breaks every time Instagram or TikTok ships an update. FastSaverAPI is a hosted social media downloader API: you send a link and get back direct download URLs and metadata in one stable JSON shape.
- Free to start: 1,000 credits on sign-up, no credit card, 10 requests per minute.
- One endpoint for 7 platforms: Instagram, TikTok, Pinterest, Facebook, X/Twitter, RuTube and
Likee through
client.fetch(url), plus a full YouTube toolset. Every result has the same fields. - TikTok without watermark, Instagram reels, carousels and stories, YouTube up to 2160p (4K) and MP3, YouTube community posts.
- Built for Telegram bots: turn a YouTube video into a Telegram
file_idin one call. Your bot never downloads or uploads the file. - Shazam built in: recognise a song from a voice message and browse the charts.
- Predictable billing: a fixed credit price per call; a failed resolve costs 0.1 credit.
Why this SDK
- Zero dependencies, ESM and CommonJS, full TypeScript types, TSDoc on every method.
- Runs everywhere: Node.js 18.3+, Bun, Deno, Cloudflare Workers, Vercel Edge.
- Typed results: camelCase fields, convenience helpers (
downloadUrls,isAlbum,bestVideoFormat,bestMatch, ...) and the untouched JSON onraw. - Precise errors:
AuthenticationError,InsufficientCreditsError,RateLimitError,NotFoundError,FetchError, andInvalidArgumentErrorfor mistakes caught before a request (so they cost nothing). - Automatic retries with backoff for network errors, HTTP 429 and 5xx; timeouts and
AbortSignalon every call. save()streams any download link to disk without sending your API key to the CDN.- A CLI:
npx fastsaverapi fetch <url>.
FastSaverAPI vs DIY scrapers and ytdl-core-style libraries
Scraping libraries run on your server, and that is the whole difference:
| | Self-hosted scrapers / ytdl-core-style libraries | FastSaverAPI + fastsaverapi |
|---|---|---|
| Keeps working when platforms change | You upgrade, redeploy and hope | Handled server-side, same JSON |
| Proxies, cookies, IP bans, captchas | Your problem and your cost | Included |
| TikTok without watermark | Depends on the current extractor | Yes |
| YouTube 4K and MP3 | Needs ffmpeg and CPU on your server | Done upstream, you get a link |
| Telegram delivery | Download, then upload to Telegram | file_id in one call, no upload |
| Song recognition | A separate service | Built in |
| Runs on edge runtimes | Usually not (Node APIs, binaries) | Yes, it is just fetch |
| Works without a third party | Yes | No, it is a hosted API |
| Cost | Servers, proxies, your time | From $0; pricing |
When a self-hosted tool is still the right choice: one-off personal downloads, archiving your own content at zero marginal cost, or systems that must not call an external service.
Supported platforms and credit costs
| Platform | What you can download | Credits per call |
|---|---|---|
| Instagram | Posts, reels, carousels (albums) | 1.5 |
| Instagram | Stories and highlights | 5 |
| TikTok | Videos without watermark, photo posts, the original sound (tiktok.com, vm.tiktok.com, tt.site) | 1.5 |
| YouTube | Video info and formats; community posts (images, polls, videos) | 2 |
| YouTube | Search (YouTube Music) | 2 |
| YouTube | Download MP4 144p–1080p, or audio (MP3) | 15 |
| YouTube | Download 1440p (2K) or 2160p (4K) | 25 |
| YouTube → Telegram | Audio as a Telegram file_id | 7 cached · 15 first time |
| Pinterest | Pins, videos, idea pins (pinterest.com, country domains, pin.it) | 1.5 |
| Facebook | Videos and reels (facebook.com, fb.com, fb.watch) | 1.5 |
| X / Twitter | Videos, GIFs and images (x.com, twitter.com) | 1.5 |
| RuTube | Videos (rutube.ru, rutube.com) | 3 |
| Likee | Videos (likee.video, likee.com) | 3 |
| Shazam | Identify a song from audio | 5 |
| Shazam | Top charts by country | 1 |
| Account | Balance and plan | free |
A call that cannot be resolved costs 0.1 credit, and so does a fetch() link whose host is not
supported. Requests rejected before that (bad key, no credits, rate limit, invalid format) are
free. The same numbers are exported as CREDIT_COSTS.
Install
npm install fastsaverapipnpm add fastsaverapi # or: yarn add fastsaverapi · bun add fastsaverapiDeno: import { FastSaver } from 'npm:fastsaverapi'. The package has no dependencies.
Get your API key
- Sign up at api.fastsaver.io (email, Google or Telegram). No credit card.
- Copy your
fs_sk_...key from the dashboard. - Put it in the environment:
export FASTSAVER_API_KEY=fs_sk_..., or passapiKeyto the client.
Keep the key on your server. It is a secret: never ship it in browser code.
Quickstart
import { FastSaver, FastSaverError } from 'fastsaverapi'
const client = new FastSaver() // reads FASTSAVER_API_KEY
try {
const { plan, credits, rpmLimit } = await client.balance() // free
console.log(`${plan}: ${credits} credits, ${rpmLimit} requests/min`)
const media = await client.fetch('https://www.instagram.com/reel/DRsmm9UjKfH/')
console.log(media.platform, media.type) // 'instagram' 'video'
for (const url of media.downloadUrls) console.log(url) // one link, or every album item
} catch (error) {
if (error instanceof FastSaverError) console.error(error.name, error.message)
else throw error
}Create one client and reuse it; it is safe for concurrent calls.
Instagram downloader API (reels, posts, stories)
const post = await client.fetch('https://www.instagram.com/p/C9AlbumXyz1/')
if (post.isAlbum) {
for (const item of post.items) console.log(item.type, item.downloadUrl) // carousel
} else {
console.log(post.downloadUrl, post.width, post.height, post.duration)
}
// Stories and highlights use the same call (5 credits)
const story = await client.fetch('https://www.instagram.com/stories/natgeo/3456789012345678901/')
await client.save(story.downloadUrls[0], 'downloads/') // Node.js, Bun, DenoOnly public content is supported. A private or deleted post throws NotFoundError (0.1 credit).
TikTok downloader API (no watermark)
const tiktok = await client.fetch('https://vm.tiktok.com/ZMabc123/')
console.log(tiktok.downloadUrl) // MP4 without watermark
console.log(tiktok.music?.title, tiktok.musicUrl) // the original sound
if (tiktok.isAlbum) console.log(tiktok.downloadUrls) // photo posts come back as an albumYouTube to MP4 and MP3 download API (up to 4K)
// Metadata and every available format with its size (2 credits).
const info = await client.youtube.info('https://youtu.be/dQw4w9WgXcQ')
if (!info.isPost) console.log(info.title, info.availableFormats, info.bestVideoFormat)
// YouTube Music search: 10 results per page.
const { results } = await client.youtube.search('the weeknd', { page: 1 })
console.log(results[0]?.title, results[0]?.durationSeconds, results[0]?.url)
// MP4 '144p' ... '2160p', or 'audio' (MP3): 15 credits, 25 for 1440p/2160p.
const video = await client.youtube.download('https://youtu.be/dQw4w9WgXcQ', { format: '1080p' })
// The link is short-lived and needs no API key: save it right away.
const path = await client.save(video.downloadUrl, 'downloads/')
console.log(path)- An invalid format throws
InvalidArgumentErrorbefore any request, so it costs nothing. downloadUrlworks for about 5 minutes and up to 3 opens (10 minutes for 2K/4K links), so download it immediately or hand it straight to your user.save()follows redirects, never sends your key, writes through a temporary.partfile and has an idle timeout instead of a total one, so large files are fine.
YouTube community posts
youtube.info() also takes community post links at the same price. Check isPost first:
const result = await client.youtube.info('https://www.youtube.com/post/UgkxB7POmB4C7U0I3kIEWRZpYfE2t-ieP9CA')
if (result.isPost) {
const { post } = result
console.log(post.type, result.author, post.text, post.likes) // image, video, text, poll, quiz, ...
// Images are direct links; the CDN serves every one as "unnamed.jpg", so name them yourself.
for (const [i, url] of post.downloadUrls.entries()) {
await client.save(url, `downloads/${post.postId}_${i + 1}.jpg`)
}
for (const url of post.videoUrls) console.log('video:', url) // use youtube.download()
}Telegram music bot: YouTube audio as a file_id (grammY, Telegraf)
audioForBot() puts the audio into your bot and returns its Telegram file_id: your bot just
calls sendAudio with it, with no download, no upload and no 50 MB limit. 7 credits when the track
is cached, 15 the first time. A file_id only works for the bot it was requested for.
grammY
import { Bot } from 'grammy'
import { FastSaver, FastSaverError, extractYoutubeId } from 'fastsaverapi'
const bot = new Bot(process.env.BOT_TOKEN ?? '')
const client = new FastSaver()
bot.on('message:text', async (ctx) => {
const text = ctx.message.text.trim()
const videoId = extractYoutubeId(text)
if (!videoId || videoId === text) return ctx.reply('Send me a YouTube link.')
try {
const { fileId } = await client.youtube.audioForBot(videoId, ctx.me.username)
if (fileId) await ctx.replyWithAudio(fileId)
} catch (error) {
if (error instanceof FastSaverError) return ctx.reply(`Sorry: ${error.message}`)
throw error
}
})
await bot.start()Telegraf
import { Telegraf } from 'telegraf'
import { message } from 'telegraf/filters'
import { FastSaver, extractYoutubeId } from 'fastsaverapi'
const bot = new Telegraf(process.env.BOT_TOKEN ?? '')
const client = new FastSaver()
bot.on(message('text'), async (ctx) => {
const videoId = extractYoutubeId(ctx.message.text)
if (!videoId) return
const { fileId } = await client.youtube.audioForBot(videoId, ctx.botInfo.username)
if (fileId) await ctx.replyWithAudio(fileId)
})
await bot.launch()Prefer forwarding the original message? audioForBot(id, bot, { returnFileId: false }) returns
channelId and messageId for copyMessage instead. A full bot that also names songs from voice
messages: examples/telegram-bot-grammy.ts.
Pinterest, Facebook, X/Twitter, RuTube and Likee downloader
Same call, same result shape:
for (const url of [
'https://pin.it/1a2b3c4d',
'https://www.facebook.com/reel/1234567890',
'https://x.com/NASA/status/1234567890123456789',
'https://rutube.ru/video/0123456789abcdef0123456789abcdef/',
'https://l.likee.video/v/AbCdEf',
]) {
const media = await client.fetch(url)
console.log(media.platform, media.type, media.downloadUrls)
}detectPlatform(url) tells you which platform a link belongs to before you spend a credit; it
returns 'youtube' for YouTube links (use client.youtube.*) and null for unsupported hosts.
Shazam API for Node.js: identify songs, top charts
import { readFile } from 'node:fs/promises'
// mp3, m4a, ogg (Telegram voice notes) or mp4, up to 50 MiB; 5-15 seconds is enough (5 credits).
const match = await client.shazam.identify('clip.mp3') // a path, bytes, a Blob or a stream
console.log(match.artist, match.title, match.thumbnail, match.bestMatch?.url)
// In-memory audio: say what it is with the file name.
const voice = await client.shazam.identify(await readFile('voice.oga'), { filename: 'voice.ogg' })
console.log(voice.title)
// Charts for a country code or 'world': 10 tracks per page (1 credit).
const { results } = await client.shazam.top({ country: 'us', page: 1 })
for (const track of results) console.log(track.title, track.duration)No match throws NotFoundError (code Music not recognized). Formats the API does not accept
(wav, flac, WebM) are rejected before upload, free of charge.
Error handling
import {
FastSaverError, AuthenticationError, InsufficientCreditsError, RateLimitError,
InvalidArgumentError, NotFoundError, FetchError, RequestTimeoutError,
} from 'fastsaverapi'
try {
await client.fetch('https://www.instagram.com/p/private-or-deleted/')
} catch (error) {
if (error instanceof NotFoundError) console.log('private or deleted (0.1 credit)')
else if (error instanceof FetchError) console.log('could not resolve:', error.code)
else if (error instanceof InsufficientCreditsError) console.log('top up your balance')
else if (error instanceof RateLimitError) console.log('slow down, retry in', error.retryAfter)
else if (error instanceof AuthenticationError) console.log('check FASTSAVER_API_KEY')
else if (error instanceof InvalidArgumentError) console.log('bad input, nothing was sent')
else if (error instanceof RequestTimeoutError) console.log('timed out')
else if (error instanceof FastSaverError) console.log(error.name, error.message)
else throw error
}FastSaverError
├── ConfigurationError no API key, browser without opt-in, save() without a file system
├── InvalidArgumentError rejected before any request (free)
├── APIError status, detail, body, requestId, retryAfter
│ ├── AuthenticationError 401
│ ├── InsufficientCreditsError
│ ├── RateLimitError 429 (after automatic retries)
│ ├── InvalidRequestError "Invalid URL", invalid format, ...
│ │ └── ValidationError 422
│ ├── FetchError could not resolve the media (code: fetch.failed, ...)
│ │ └── NotFoundError private, deleted, or no Shazam match
│ └── ServerError 5xx (after automatic retries)
├── TransportError network failure
│ └── RequestTimeoutError
└── DownloadError save(): the link answered non-2xx (for example, it expired)instanceof works across the ESM and CommonJS builds. Every API error carries requestId;
include it when you contact support.
Retries, timeouts, abort and proxies
const client = new FastSaver({
timeout: 30_000, // ms per attempt (default 60 s; youtube.download 120 s, audioForBot 300 s)
maxRetries: 3, // network errors, 429 and 5xx; default 2
userAgent: 'my-bot/1.0',
})
// Per call: a different timeout, or your own AbortSignal.
const controller = new AbortController()
setTimeout(() => controller.abort(), 10_000)
await client.youtube.info('https://youtu.be/dQw4w9WgXcQ', { timeout: 15_000, signal: controller.signal })- 429 is retried after 2 s and then 4 s, network errors and 5xx after 0.5 s and then 1 s, and
Retry-Afteris honoured. Our own timeouts are never retried, because the server may already have done (and billed) the work. - API calls never follow redirects, so your key is never sent to another host.
Proxy or custom fetch: pass any fetch implementation, for example undici with a proxy:
import { fetch as undiciFetch, ProxyAgent } from 'undici'
const dispatcher = new ProxyAgent('http://proxy.local:8080')
const client = new FastSaver({ fetch: (url, init) => undiciFetch(url, { ...init, dispatcher }) })Edge runtimes: Next.js, Cloudflare Workers, Deno, Bun
The SDK uses only fetch, so the same code runs on Node.js, Bun, Deno, Cloudflare Workers and
Vercel Edge. save() and file-path uploads need a file system (Node.js, Bun, Deno); on edge
runtimes, hand the downloadUrl to the user or stream it with fetch.
// Cloudflare Worker: redirect the user to a fresh MP3 link.
interface Env {
FASTSAVER_API_KEY: string
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url).searchParams.get('url') ?? ''
const client = new FastSaver({ apiKey: env.FASTSAVER_API_KEY }) // secrets come from env
const audio = await client.youtube.download(url, { format: 'audio' })
return audio.downloadUrl ? Response.redirect(audio.downloadUrl, 302) : new Response('no link', { status: 502 })
},
}Never put your fs_sk_ key in browser code. The API does not accept cross-origin browser
requests anyway, and new FastSaver() refuses to start in a browser unless you pass
dangerouslyAllowBrowser: true (for browser extensions with host permissions). Call the API from
your server instead, as in the
Next.js route handler example.
Anyone who can reach such a route spends your credits, so protect it.
Command-line interface
export FASTSAVER_API_KEY=fs_sk_...
npx fastsaverapi fetch "https://www.tiktok.com/@scout2015/video/6718335390845095173"
npx fastsaverapi youtube info "https://youtu.be/dQw4w9WgXcQ"
npx fastsaverapi youtube search "the weeknd" --page 2
npx fastsaverapi youtube download "https://youtu.be/dQw4w9WgXcQ" --format audio --out downloads/
npx fastsaverapi youtube tg-audio dQw4w9WgXcQ --bot @my_music_bot
npx fastsaverapi shazam identify clip.mp3
npx fastsaverapi shazam top --country us
npx fastsaverapi balance
npx fastsaverapi save "<download url>" downloads/Output is JSON (--compact for one line), errors go to stderr with exit code 1, usage errors exit
with 2. Global options: --api-key, --base-url, --timeout (seconds), --help, --version.
npx fastsaverapi --compact fetch "$URL" | jq -r '.download_url // .items[].download_url'Credits and rate limits
- Free plan: 1,000 credits, 10 requests per minute, no credit card.
- Paid plans add credits and higher limits: api.fastsaver.io/pricing.
- The limit is per API key, in a fixed 60-second window shared by every paid endpoint.
balance()is free and has its own limit of 60 calls per minute. client.balance()returnsplan,credits,rpmLimitandplanExpiresAt. The bulk example paces requests to yourrpmLimit: examples/bulk.ts.
FAQ
How do I download an Instagram reel or post in Node.js?
await client.fetch(url) returns downloadUrl (or items for a carousel), and
await client.save(url, 'downloads/') writes it to disk. Stories and highlights use the same call.
How do I download TikTok videos without a watermark in JavaScript?
(await client.fetch(tiktokUrl)).downloadUrl is the clean MP4. Photo posts come back as an
album, and music.downloadUrl is the original sound.
How do I convert YouTube to MP3 or MP4 without ytdl-core or ffmpeg?
client.youtube.download(url, { format: 'audio' }) (or '1080p', up to '2160p') returns a
short-lived link; save it with client.save(). Conversion happens on FastSaverAPI's side.
How do I send YouTube music in a Telegram bot without downloading it?
client.youtube.audioForBot(videoId, '@your_bot') returns a Telegram file_id; pass it to
sendAudio (ctx.replyWithAudio in grammY and Telegraf).
How do I recognise a song from a Telegram voice message?
client.shazam.identify(bytes, { filename: 'voice.ogg' }) (5 credits) returns the title,
artist, cover art and matching YouTube tracks.
Is it really free? Every account gets 1,000 credits without a card, at 10 requests per minute. That is about 660 Instagram or TikTok links, or 66 YouTube downloads.
Do I need cookies, a login or proxies? No. You send a public URL and an API key; everything else happens on FastSaverAPI's side.
Can I use it in a commercial app or a public bot? The SDK is MIT-licensed. Use of the API is governed by the FastSaverAPI terms at api.fastsaver.io.
Does it work with TypeScript, ESM and CommonJS?
Yes: import { FastSaver } from 'fastsaverapi' or const { FastSaver } = require('fastsaverapi'),
with full types for every result.
Is there a Python SDK?
Yes: pip install fastsaver
(GitHub), with the same features.
Examples
quickstart · bulk downloads · YouTube download · YouTube posts · Shazam · grammY bot · Next.js route · Cloudflare Worker
Support, contributing, license
- Telegram community: t.me/fastsaverapi · Email: [email protected]
- API docs: api.fastsaver.io/docs
- Issues and pull requests: github.com/coder2077/fastsaver-js. See CONTRIBUTING.md and SECURITY.md.
- MIT License.
