# TikTok Video Downloader - MP4 or MP3 (`dami_studio/tiktok-video-downloader`) Actor

Paste public TikTok video links and get each video as an MP4, or just its sound as an MP3. Each file is stored in the run with a direct download link. No login, no cookies. You pay per megabyte of file delivered, and links that fail cost nothing per megabyte.

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

## Pricing

from $1.00 / 1,000 megabyte downloadeds

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 the link of a public TikTok video and you get it as an MP4, or only its sound as an MP3. Each
file is saved in the run's key-value store, and its row in the dataset carries a direct download link.

You pay for the megabytes you receive. A link that fails, or a video over your size limit, is skipped
and not billed per megabyte.

### Input

```json
{ "urls": ["https://www.tiktok.com/@hankgreen1/video/7047596209028074758"] }
```

| Field | Default | What it does |
|---|---|---|
| `urls` | none | One link per line, each to a single TikTok video (tiktok.com/@name/video/...). |
| `quality` | `1080` | `best`, `1080`, `720`, `480` or `360`. The number is the short side of the picture, so `1080` means 1080x1920 for a vertical video. If a video doesn't come in that quality, you get the closest one it has. |
| `audioOnly` | `false` | Only the video's sound, as a 128 kbit/s MP3. |
| `maxMegabytes` | `500` | Your limit per video. A bigger video is skipped before anything is downloaded. |

This actor takes TikTok links only. A Facebook or X link is refused before anything is fetched, with a
pointer to our [Facebook Video Downloader](https://apify.com/dami_studio/facebook-video-downloader) or
[X Video Downloader](https://apify.com/dami_studio/x-video-downloader). YouTube links go in our
[YouTube Downloader](https://apify.com/dami_studio/youtube-video-downloader).

### What you get

One dataset row per delivered file:

```json
{
  "url": "https://www.tiktok.com/@hankgreen1/video/7047596209028074758",
  "host": "tiktok",
  "title": "TikTok video #7047596209028074758",
  "author": "hankgreen1",
  "durationSeconds": 21.27,
  "resolution": "576x1024",
  "format": "mp4",
  "fileSizeBytes": 5076682,
  "billedMegabytes": 6,
  "mediaKey": "tiktok-7047596209028074758.mp4",
  "mediaUrl": "https://api.apify.com/v2/key-value-stores/.../records/tiktok-7047596209028074758.mp4"
}
```

When a video has no caption, TikTok gives it no title, so the row says `TikTok video #<id>` as above.
`resolution` and `durationSeconds` are measured on the file you receive, not copied from the page.
`billedMegabytes` is the file size rounded up to whole megabytes, where a megabyte is 1,000,000 bytes.

You get the stream TikTok plays in the app, not the copy its own download button makes with the
moving TikTok logo. If a video already has the logo in the picture, as the one above does, it stays:
that video carries it in every version TikTok serves.

The video is H.264 where TikTok offers it, because every player opens it. The catch: TikTok's H.264
copy can be about three times the size of its H.265 one (5.1 MB against 1.8 MB for the video above),
and you pay per megabyte.

Links that don't work out are listed in the `ERRORS` record of the same key-value store, each with a
plain reason. They never show up in the dataset. If not one link could be downloaded, the run ends as
Failed instead of Succeeded, so a scheduled job or an integration notices.

### Billing

Each delivered file is charged once, for its size in megabytes rounded up: the 5.08 MB video above
counts as 6 MB. The price per megabyte for your Apify plan is on the Pricing tab.

A link that fails, a video over your `maxMegabytes`, or one that doesn't fit the run costs nothing per
megabyte. If you set a maximum charge for the run, the actor checks it before each download and skips
a video it can't pay for rather than going over.

### Big files

One run holds files up to about 70% of its memory, so 716 MB at the default 1024 MB. A bigger video
is refused with a message that names the memory to use. TikTok videos rarely come close.

### What it doesn't do

- **Other sites.** TikTok only; see the links above for Facebook, X and YouTube. Instagram and Vimeo
  are not supported by any of them.
- **Private posts, or posts only friends can see.** There's no account and no cookies behind this.
- **Some posts that are only available in certain countries.** Those fail with a message that says so.
- **Photo posts and slideshows.** There is no video in them.
- **Whole profiles, sounds or hashtags.** One link, one video.
- **Lives** while they are still live.

### Copyright

The videos belong to the people who posted them. Download only what you own or have permission to
use, and stay within TikTok's terms.

### FAQ

**Do I need an account, cookies or an API key?** No. The link is the whole input.

**Can I send lots of links in one run?** Yes. They are downloaded one after another, and a short clip
takes 5 to 10 seconds. The default run timeout is 30 minutes, so give a very big batch more.

**Will a smaller memory setting save money?** No. It doesn't change the price, and at 512 MB the same
batch took about 75% longer in testing.

**Why is my video 540p when I asked for 1080?** Many TikToks are only available at 540p or 576p,
and you get the best the video has up to your setting.

**Where are the files?** In the run's key-value store. `mediaUrl` in each row is a direct link, and
`mediaKey` is the key if you'd rather fetch it through the API. How long the store is kept depends on
your Apify plan, so download what you need.

# Actor input Schema

## `urls` (type: `array`):

One link per line, each to a single TikTok video (tiktok.com/@name/video/...). Each link gives one file. Links from other sites are refused, with a pointer to the downloader that takes them.

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

Measured on the short side of the picture, so 1080 means 1920x1080 for a landscape video and 1080x1920 for a vertical one. If a video doesn't come in that quality you get the closest one it has. You pay per megabyte, so a higher quality costs more.

## `audioOnly` (type: `boolean`):

Save just the video's sound, as a 128 kbit/s MP3, instead of the video.

## `maxMegabytes` (type: `integer`):

A video bigger than this is skipped before it is downloaded, and you are not charged for it. One run can hold files up to about 70% of its memory (716 MB at the default 1024 MB), so for anything bigger raise the run's memory as well.

## Actor input object example

```json
{
  "urls": [
    "https://www.tiktok.com/@hankgreen1/video/7047596209028074758"
  ],
  "quality": "1080",
  "audioOnly": false,
  "maxMegabytes": 500
}
```

# Actor output Schema

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

One row per delivered file: the link, title, author, duration, measured resolution, size, megabytes billed and a direct link to the file.

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

The MP4 and MP3 files themselves, in the run's key-value store.

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

Each failed or refused link with the reason. These are not billed per megabyte.

# 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 = {
    "urls": [
        "https://www.tiktok.com/@hankgreen1/video/7047596209028074758"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/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 = { "urls": ["https://www.tiktok.com/@hankgreen1/video/7047596209028074758"] }

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/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 '{
  "urls": [
    "https://www.tiktok.com/@hankgreen1/video/7047596209028074758"
  ]
}' |
apify call dami_studio/tiktok-video-downloader --silent --output-dataset

```

## MCP server setup

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