# TikTok Video Downloader - MP4, All Qualities (`s-r/tiktok-video-downloader`) Actor

Download TikTok videos from a link. Returns a hosted MP4 link that works anywhere, the full quality ladder, and the post's caption, author, sound, hashtags and counters.

- **URL**: https://apify.com/s-r/tiktok-video-downloader.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** Social media, Videos
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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

## TikTok Video Downloader

Paste TikTok links, get MP4 files back. Every run returns a hosted download
link that works straight away, in any browser, on any machine, with nothing to
configure. Alongside the file you get the post itself: the caption, the author,
the sound, the hashtags and the view, like, comment and share counts as they
stood at the moment of the run.

It takes any shape of link you are likely to have. A full link copied from the
address bar, a link with all the tracking parameters TikTok's share button adds,
a short `vm.tiktok.com` link from a message, or a bare video id. One per line,
as many as two hundred in a run.

### Why the hosted link matters

Most tools that "download TikTok videos" hand you TikTok's own media address.
Those addresses look like ordinary links and behave nothing like them: pasted
into a browser, dropped into a spreadsheet, or passed to another job, they
usually return an error rather than a file. They are not built to be shared.

This actor pulls the bytes during the run and stores the file, so the
`file_url` on every row is a plain, permanent link to an MP4. Click it, curl it,
feed it to a video pipeline, hand it to a colleague. It just works.

If you would rather have TikTok's own address anyway, turn **Host the file**
off. You then get `selected_media_url` together with the `media_cookie_header`
that address requires, and no file is stored. That mode is faster and moves no
video data, which suits a run that only needs to know what qualities exist.

### Choosing a quality

Every TikTok video is published in several variants. The actor reads the full
ladder and puts it in the `qualities` field, best first, with the label, the
bitrate, the codec, the pixel size and the exact file size of each one. You pick
which to download with the **Quality** input:

| Setting | What you get |
|---|---|
| Highest available | The largest variant the video has |
| Up to 1080p / 720p / 540p | The best variant at or below that size |
| Smallest file | The smallest variant, for bulk archiving |

Two details save you time here. Asking for a size a video does not have returns
the closest one below it rather than failing, so a mixed list of links never
half-fails on quality alone. And the ladder is ordered by picture size rather
than by bitrate: TikTok sometimes encodes a smaller variant at a higher bitrate
than a larger one, so "highest" would otherwise hand you the smaller picture.

### What a row looks like

One row per link. The fields you will use most:

- `file_url`, `file_size_bytes` — the hosted MP4 and its size
- `selected_quality`, `qualities` — what was fetched, and everything on offer
- `description`, `created_at`, `hashtags` — the post
- `handle`, `nickname`, `author_id` — who posted it
- `duration_seconds`, `width`, `height`, `cover_url` — the video itself
- `play_count`, `like_count`, `comment_count`, `share_count`, `collect_count`
- `music_title`, `music_author`, `music_id`, `music_url` — the sound
- `play_url`, `download_url` — TikTok's two own addresses, kept apart because
  they are different files and the site uses them in different places
- `is_ad` — whether the post is a paid ad

The files land in the run's key-value store next to a `summary` record, which
tells you how many links were requested, how many videos came back, how many
files were stored and how many bytes that was.

### Videos that cannot be read

A link that fails becomes an entry in the `errors` record rather than a missing
row, so a list of two hundred never fails silently on the three that were
deleted. The reasons are named:

| Code | Meaning |
|---|---|
| `bad_input` | Not a TikTok video link or id |
| `unavailable` | Removed, private, or not available in the country you chose |
| `fetch_failed` | The page could not be read after several attempts |
| `media_failed` | The video's media could not be fetched |
| `no_media` | The post carries no video, which happens on photo posts |
| `store_failed` | The file could not be stored |

Availability really is regional. A video that returns `unavailable` for one
country can return perfectly well for another, which is what the **Country**
input is for. It takes a two-letter code and defaults to `us`.

### Sensible run sizes

Links are processed a few at a time. That is deliberate rather than cautious:
downloading many videos at once is bounded by bandwidth, not by concurrency,
and firing everything at once mostly makes the slowest link slower.

For a large archive job, split it into runs of a hundred or so and raise the
run's memory. A run holds each file in memory only while it is being stored, so
1 GB is comfortable for ordinary videos and is the default.

If you are collecting statistics rather than files, turn **Host the file** off.
Runs finish in a fraction of the time and cost far less, because no video data
moves at all.

### Legal and reasonable use

The videos are other people's work. Downloading a public post for research,
archiving, reporting or your own reference is one thing; republishing it as
your own, or building a service that redistributes other people's videos, is
another, and it is likely to breach both TikTok's terms and the copyright of
whoever made the video. That is your call to make and your responsibility to
get right. This actor reads only what TikTok serves publicly, and it reads
nothing that requires an account.

### Related actors

If you want an account's whole catalogue rather than single links, or reach
figures for a hashtag, use **TikTok Scraper - Profiles, Videos & Hashtags**.
For TikTok Shop listings and their prices, use **TikTok Shop Scraper**. For ads
running on the platform, use **TikTok Ads Library Scraper**.

# Actor input Schema

## `videos` (type: `array`):

Video links, one per line. A full link, a link with tracking parameters, a short vm.tiktok.com link or a bare video id all work.

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

Which variant to fetch. Asking for a height that a video does not have returns the closest one below it rather than nothing.

## `saveFile` (type: `boolean`):

Download the video and return a hosted link that works anywhere. Turn this off to get only TikTok's own address, which needs the cookie header returned alongside it.

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

Two-letter country code to read from. Some videos are only available in some countries.

## Actor input object example

```json
{
  "videos": [
    "https://www.tiktok.com/@tiktok/video/7106594312292453675"
  ],
  "quality": "highest",
  "saveFile": true,
  "country": "us"
}
```

# Actor output Schema

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

One row per link, with the hosted file URL and the metadata.

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

Links requested, videos returned, files stored and bytes downloaded.

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

Links that could not be read, with the reason.

# 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 = {
    "videos": [
        "https://www.tiktok.com/@tiktok/video/7106594312292453675"
    ],
    "country": "us"
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/tiktok-video-downloader").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 = {
    "videos": ["https://www.tiktok.com/@tiktok/video/7106594312292453675"],
    "country": "us",
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/tiktok-video-downloader").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 '{
  "videos": [
    "https://www.tiktok.com/@tiktok/video/7106594312292453675"
  ],
  "country": "us"
}' |
apify call s-r/tiktok-video-downloader --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/tiktok-video-downloader"
        }
    }
}
```

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/9b9EGX8LZYevtG1ur/builds/AqAbW6mV6eXj34koF/openapi.json
