# TikTok Scraper (`ecommerce_leads/tiktok-scraper`) Actor

Download TikTok videos without watermark, plus TikTok profiles, hashtags, comments-free video metadata, explore feed and keyword suggestions. 6 modes, no login or cookies needed.

- **URL**: https://apify.com/ecommerce\_leads/tiktok-scraper.md
- **Developed by:** [Monster Leads](https://apify.com/ecommerce_leads) (community)
- **Stats:** 2 total users, 1 monthly users, 60.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 tiktok video 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 Scraper — Download TikTok Videos Without Watermark

**Download TikTok videos** and scrape TikTok profiles, TikTok hashtags, TikTok trending videos and TikTok keyword suggestions — all from one TikTok scraper. No TikTok login, no TikTok cookies, no browser, no API key from TikTok.

Paste any TikTok link and get back a **direct MP4 download URL** in about a second, plus every quality TikTok offers and the full metadata around the video: creator, follower count, views, likes, comments, shares, the sound and the cover image.

The MP4 URLs this TikTok scraper returns are **plain CDN links**. Open one in a browser, hand it to `curl`, `wget`, `yt-dlp` or your own downloader — no special headers and no session required.

***

### ⬇️ Download TikTok videos (the main feature)

This is what most people come here for, so it is the default mode. Give the TikTok Scraper a list of TikTok links and it returns direct MP4 URLs for each TikTok video.

#### Input

```json
{
  "mode": "download",
  "videoUrls": [
    "https://www.tiktok.com/@nasa/video/7665075736742530317",
    "https://vm.tiktok.com/ZMabcdefg/",
    "7665075736742530317"
  ]
}
```

**Every TikTok link format works.** You do not have to clean anything up first:

| What you paste | Works? |
| --- | --- |
| `https://www.tiktok.com/@nasa/video/7665075736742530317` | ✅ Full TikTok link |
| `https://vm.tiktok.com/ZMabcdefg/` | ✅ TikTok short link (redirect followed for you) |
| `https://vt.tiktok.com/ZSabcdefg/` | ✅ TikTok short link, other domain |
| `https://www.tiktok.com/@user/photo/7665075736742530317` | ✅ TikTok photo post |
| `https://www.tiktok.com/v/7665075736742530317` | ✅ Legacy TikTok link |
| `7665075736742530317` | ✅ Bare TikTok video ID |

#### Output — one row per TikTok video

```json
{
  "type": "video",
  "video_id": "7665075736742530317",
  "desc": "A supermoon rises behind the Washington Monument 🌕 #nasa #moon",
  "hashtags": ["nasa", "moon"],
  "duration_seconds": 15,

  "download_url": "https://v16-webapp-prime.tiktok.com/video/tos/useast2a/…",
  "download_url_watermarked": "https://v16-webapp-prime.tiktok.com/video/tos/useast2a/…",
  "mirrors": [
    "https://v16-webapp-prime.tiktok.com/video/tos/useast2a/…",
    "https://v19-webapp-prime.tiktok.com/video/tos/useast2a/…"
  ],

  "qualities": [
    {
      "gear": "normal_1080_0",
      "bitrate": 2419521,
      "codec": "h264",
      "format": "mp4",
      "width": 1080,
      "height": 1920,
      "size": 4538291,
      "url": "https://v16-webapp-prime.tiktok.com/video/tos/useast2a/…",
      "mirrors": ["…", "…", "…"]
    },
    { "gear": "lower_540_0", "bitrate": 843122, "width": 540, "height": 960, "…": "…" }
  ],

  "cover": "https://p16-sign.tiktokcdn-us.com/obj/tos-useast5-p-0068-tx/…",
  "width": 1080,
  "height": 1920,
  "file_size_bytes": 4538291,

  "author": "nasa",
  "nickname": "NASA",
  "tiktok_url": "https://www.tiktok.com/@nasa/video/7665075736742530317"
}
```

#### The `qualities` ladder

Every quality TikTok encoded is returned, sorted highest bitrate first. Take `qualities[0]` for the best file, or the last entry for the smallest.

Each quality carries its own `mirrors` — the same file on several TikTok CDN hosts. If one host is slow or refuses a connection, retry the next mirror instead of scraping the video again.

`download_url` is the stream TikTok's own player uses. `download_url_watermarked` is TikTok's "save video" URL. Which one carries a visible watermark is TikTok's choice and it varies by video, so both are given rather than promising a clean file that TikTok might not serve.

***

### 👤 Scrape a TikTok profile

Get a TikTok creator's follower count, total likes, video count, bio, region and verification status — plus their recent TikTok videos.

```json
{
  "mode": "profile",
  "profileUrls": ["https://www.tiktok.com/@nasa", "@khaby.lame", "bbc"],
  "maxProfileVideos": 10
}
```

Full links, `@handles` and bare usernames all work. TikTok **numeric user IDs do not** — TikTok's profile pages key on the username only.

```json
{
  "type": "profile",
  "unique_id": "nasa",
  "nickname": "NASA",
  "user_id": "6727327145951183874",
  "sec_uid": "MS4wLjABAAAA…",
  "signature": "Exploring the universe and our home planet.",
  "avatar": "https://p16-sign.tiktokcdn-us.com/…",
  "verified": true,
  "private": false,
  "region": "US",
  "follower_count": 8300000,
  "following_count": 12,
  "heart_count": 91700000,
  "video_count": 512,
  "profile_url": "https://www.tiktok.com/@nasa"
}
```

> **On follower and like counts:** TikTok's own web payload overflows `heartCount` into a *negative* number for very large creators (a 32-bit integer bug on TikTok's side). This TikTok scraper reads the string-typed `statsV2` values instead, so the totals you get are the accurate ones.

***

### #️⃣ Scrape a TikTok hashtag

Get the numbers behind a TikTok topic — **total views across the hashtag** and how many TikTok videos use it — plus a sample of the videos themselves.

```json
{
  "mode": "hashtag",
  "hashtags": ["fyp", "cooking", "https://www.tiktok.com/tag/booktok"],
  "maxHashtagVideos": 10
}
```

```json
{
  "type": "hashtag",
  "tag": "cooking",
  "hashtag_id": "17951",
  "desc": "Show us what's on the menu.",
  "view_count": 546058192966,
  "video_count": 8241033,
  "is_commerce": false,
  "hashtag_url": "https://www.tiktok.com/tag/cooking"
}
```

Set `maxHashtagVideos` to `0` to get **only** the stats row. That is the cheapest way to compare the reach of many TikTok hashtags at once — one row and one charge per hashtag.

> TikTok reports `videoCount` as 0 on one of its endpoints and rounds `viewCount` to the nearest hundred million on another. This TikTok scraper reads the precise values, so `546058192966` is the real figure, not `546100000000`.

***

### 🧭 Scrape the TikTok explore feed

TikTok's public recommendation feed — trending TikTok videos with full engagement stats.

```json
{ "mode": "explore", "maxExploreVideos": 8 }
```

Explore rows carry the complete stat set: `play_count`, `digg_count`, `comment_count`, `collect_count`, `share_count`, the sound, and the video's own hashtag list.

***

### 🔎 TikTok keyword suggestions

The terms TikTok's own search box suggests — real TikTok search demand, for SEO and hashtag research.

```json
{ "mode": "keywords", "keyword": "cooking" }
```

```json
{
  "type": "keyword",
  "word": "cooking asmr",
  "seed_keyword": "cooking",
  "group_id": "6549558169829721606",
  "search_url": "https://www.tiktok.com/search?q=cooking%20asmr"
}
```

TikTok localises suggestions by region, so the same seed returns different terms in different markets.

***

### ℹ️ TikTok video info only

Title, creator, cover and embed code for a TikTok video, without resolving download URLs. Use it when you only need to identify a video rather than fetch it.

```json
{ "mode": "videoInfo", "videoUrls": ["https://www.tiktok.com/@nasa/video/7665075736742530317"] }
```

***

### How many TikTok results can I get?

Read this before planning a large TikTok scrape — it is the one thing that surprises people.

| Mode | Results per call | Pagination? |
| --- | --- | --- |
| ⬇️ Download TikTok videos | 1 per link, unlimited links | n/a — paste as many TikTok links as you want |
| ℹ️ TikTok video info | 1 per link, unlimited links | n/a |
| 👤 TikTok profile | 1 profile + ~10 videos | ❌ TikTok caps the video list |
| #️⃣ TikTok hashtag | 1 stats row + ~10 videos | ❌ TikTok caps the video list |
| 🧭 TikTok explore | 8 videos | ❌ TikTok returns one batch |
| 🔎 TikTok keywords | ~8 suggestions | ❌ fixed by TikTok |

**Download and Video info scale without limit** — give this TikTok scraper 10,000 TikTok links and you get 10,000 rows.

The listing modes do not, and that ceiling belongs to TikTok, not to this actor. TikTok's embed pages serve roughly 10 videos and **ignore every pagination parameter** — cursor, offset, page and count all return the identical batch. Asking for 500 videos from one TikTok hashtag returns about 10, and the run log tells you so rather than leaving you to guess.

Two ways to work with that:

1. **Collect over time.** The explore feed and hashtag pages rotate. A scheduled run every few hours accumulates a much larger TikTok dataset than any single run can.
2. **Fan out.** Scrape 50 TikTok hashtags at ~10 videos each rather than expecting 500 from one.

You are only ever charged for rows actually delivered, so a capped result never costs you what you asked for.

***

### Pricing

This TikTok scraper is **pay per result** — $1 per 1,000 list results. Nothing is charged when TikTok refuses an item.

| Event | Price | What it is |
| --- | --- | --- |
| TikTok video downloaded | **$0.01** | One TikTok video resolved to MP4 URLs with the full quality ladder |
| TikTok profile scraped | **$0.01** | One TikTok creator's stats, bio and verification |
| TikTok hashtag scraped | **$0.01** | One TikTok hashtag's total views and video count |
| TikTok video info scraped | **$0.01** | One TikTok video's title, creator and cover |
| TikTok video listed | **$0.001** | One TikTok video from a hashtag, profile or the explore feed |
| TikTok keyword scraped | **$0.001** | One TikTok search suggestion |

**Worked examples**

| What you run | Cost |
| --- | --- |
| Download 100 TikTok videos | $1.00 |
| 1,000 TikTok keyword suggestions | $1.00 |
| One TikTok hashtag: stats + 10 videos | $0.02 |
| 50 TikTok hashtags, stats only | $0.50 |
| One TikTok profile + 10 videos | $0.02 |
| Explore feed, 8 TikTok videos | $0.008 |

Single fetches cost 10× a list row because each one is a full page load through its own residential proxy — one such call does the work of about ten list rows.

**Failed TikTok items are free.** A deleted, private or region-locked TikTok video still appears in your dataset with an `error` field explaining what happened, and it is never charged. You always see which inputs failed.

***

### Output formats

Every run writes to a standard Apify dataset. Export as **JSON, CSV, Excel, XML, JSONL, HTML or RSS**, or pull it through the Apify API from Python, Node.js or `curl`.

The dataset has ready-made views: **Overview** (all TikTok result types side by side), **TikTok videos**, **TikTok profiles**, **TikTok hashtags** and **TikTok keywords**.

Missing engagement stats are `null`, never `0`. A TikTok video scraped from a hashtag page has `digg_count: null` because TikTok's embed page does not send like counts — that is different from a video with zero likes, and this TikTok scraper does not blur the two.

***

### Frequently asked questions

**Do I need a TikTok account or cookies?**
No. This TikTok scraper needs no TikTok login, no cookies and no TikTok API key.

**Can I download TikTok videos without a watermark?**
Both URLs TikTok exposes are returned: the stream its player uses and its "save video" URL. Which is watermark-free depends on the video, so pick whichever suits and check the file.

**Can anyone open the download URLs?**
Yes — they are ordinary CDN links. No headers, no cookies and no proxy needed. Download them from anywhere.

**Do the download URLs expire?**
TikTok's CDN links are signed and do not stay valid forever. Fetch the file reasonably soon rather than storing URLs for weeks, and re-run the actor if a link has gone stale.

**Can I scrape TikTok comments?**
Not in this version. TikTok's comment endpoint requires a logged-in session, which this scraper deliberately avoids. Only public TikTok data is collected.

**Can I get more than 10 videos from a TikTok hashtag?**
Not in one call — see [How many TikTok results can I get?](#how-many-tiktok-results-can-i-get). Schedule repeat runs or fan out across more hashtags.

**Is scraping TikTok legal?**
This TikTok scraper collects only public TikTok data — no login, no private accounts, no personal data behind a barrier. You are responsible for how you use what you collect, including copyright in TikTok videos and any applicable data-protection rules. Downloaded TikTok videos belong to their creators.

**Can I run this TikTok scraper on a schedule?**
Yes. Use Apify Schedules to run it hourly or daily — the recommended way to build a large TikTok dataset given TikTok's per-call caps.

***

### Integrations

Connect this TikTok scraper to **Zapier, Make, n8n, Slack, Google Sheets, Airtable, GitHub** or any webhook through the Apify platform, or drive it from the Apify API.

```python
from apify_client import ApifyClient

client = ApifyClient('<YOUR_API_TOKEN>')
run = client.actor('tiktok-scraper').call(run_input={
    'mode': 'download',
    'videoUrls': ['https://www.tiktok.com/@nasa/video/7665075736742530317'],
})

for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(item['download_url'])
```

# Actor input Schema

## `mode` (type: `string`):

Pick the TikTok task to run. **Download videos** is the default and the most used: paste TikTok links and get direct MP4 URLs back. Every other mode reveals its own fields below.

## `videoUrls` (type: `array`):

TikTok links to download. Paste anything TikTok gives you — full links (`https://www.tiktok.com/@nasa/video/7665075736742530317`), short links (`https://vm.tiktok.com/ZMabcdefg/`), photo posts, or a bare video ID. Each TikTok link becomes one row in the output.

## `includeRawData` (type: `boolean`):

Adds a `raw` field with the full untouched TikTok payload. Leave off unless you need a TikTok field this actor does not already map — it makes each row substantially larger.

## `profileUrls` (type: `array`):

TikTok creators to scrape. Paste the profile link (`https://www.tiktok.com/@nasa`) or the bare handle (`@nasa` or `nasa`). TikTok numeric user IDs do **not** work here — TikTok's profile pages only accept the @username.

## `maxProfileVideos` (type: `integer`):

How many of the creator's recent TikTok videos to include, on top of their profile stats. ⚠️ TikTok serves roughly 10 videos per profile through its embed page and supports **no pagination**, so asking for more than ~10 returns what TikTok has, not more. Pinned videos can push the count slightly higher. Set to 0 for profile stats only.

## `hashtags` (type: `array`):

TikTok hashtags to scrape, without the `#` (for example `fyp`, `cooking`). A `https://www.tiktok.com/tag/fyp` link works too. Each hashtag returns one stats row (total views and video count) plus its videos.

## `maxHashtagVideos` (type: `integer`):

How many TikTok videos to return per hashtag, on top of the hashtag's own stats. ⚠️ TikTok serves roughly 10 videos per hashtag through its embed page and supports **no pagination**. Set to 0 for hashtag stats only (view counts and video counts), which is the cheapest way to research TikTok topics.

## `maxExploreVideos` (type: `integer`):

How many videos to pull from TikTok's explore feed. ⚠️ TikTok returns **8 videos per call and supports no pagination** — passing a cursor returns the same batch. The feed does rotate over time, so scheduling repeat runs is how you build a larger set.

## `keyword` (type: `string`):

Seed keyword for TikTok search suggestions. Returns the terms TikTok's own search box suggests — useful for TikTok SEO and hashtag research. Suggestions follow TikTok's region, so results are localised. Example: `cooking`.

## `crawlerUrl` (type: `string`):

Base URL of the TikTok crawler backend, e.g. `https://ping.example.com`. Falls back to the `CRAWLER_URL` environment variable.

## `crawlerApiKey` (type: `string`):

API key for the TikTok crawler backend. Falls back to the `CRAWLER_API_KEY` environment variable.

## Actor input object example

```json
{
  "mode": "download",
  "videoUrls": [
    "https://www.tiktok.com/@nasa/video/7665075736742530317"
  ],
  "includeRawData": false,
  "maxProfileVideos": 10,
  "maxHashtagVideos": 20,
  "maxExploreVideos": 8
}
```

# Actor output Schema

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

Every row from this run, whatever mode produced it: TikTok videos, profiles, hashtags or keywords. Rows carrying an `error` field are TikTok items that could not be fetched — they are recorded so you can see which input failed, and they are never charged. Start here if you are not sure which mode the run used.

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

Downloadable TikTok videos with direct MP4 URLs, cover images, duration, resolution, creator and engagement stats. Produced by the Download, Video info, Profile, Hashtag and Explore modes. Use `download_url` for the file; the Download mode additionally returns a `qualities` bitrate ladder with per-quality CDN mirrors.

## `profiles` (type: `string`):

TikTok creator profiles with follower counts, total likes, video counts, bio, region and verification status. Produced by the Profile mode.

## `hashtags` (type: `string`):

TikTok hashtag stats with total view counts and video counts — the numbers behind a topic's reach. Produced by the Hashtag mode.

## `keywords` (type: `string`):

Keyword suggestions taken from TikTok's own search box — what TikTok users actually type. Produced by the Keywords mode and used for TikTok SEO and hashtag research.

# 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 = {
    "mode": "download",
    "videoUrls": [
        "https://www.tiktok.com/@nasa/video/7665075736742530317"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("ecommerce_leads/tiktok-scraper").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 = {
    "mode": "download",
    "videoUrls": ["https://www.tiktok.com/@nasa/video/7665075736742530317"],
}

# Run the Actor and wait for it to finish
run = client.actor("ecommerce_leads/tiktok-scraper").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 '{
  "mode": "download",
  "videoUrls": [
    "https://www.tiktok.com/@nasa/video/7665075736742530317"
  ]
}' |
apify call ecommerce_leads/tiktok-scraper --silent --output-dataset

```

## MCP server setup

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

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/srJmxQTEdBzdDWv1d/builds/L4sTG8gUzHCv7ez2f/openapi.json
