# TikTok Video Scraper (`axiomworks/tiktok-video-scraper`) Actor

Collect structured data from TikTok video and profile URLs. Video records include captions, publication dates, engagement counts, duration, hashtags and sound details; profile records include names, bios, follower counts and other profile counts.

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

## Pricing

from $2.21 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## TikTok Video Scraper

**Returns:** one row per public TikTok video or profile with `id`, `recordType`, `sourceUrl`, `authorUsername`, `playCount`, `diggCount`, and `createTimeISO` (video fields are null for profiles).

**Input:** `{"startUrls":[{"url":"https://www.tiktok.com/@tiktok"}],"maxItems":1}`

**Best for:** video performance monitoring, creator profile spreadsheets, and TikTok API inputs for AI agents.

This TikTok scraper returned the following record in a local run on 2026-10-14; counts can change between runs.

```json
{
  "id": "7691036284428635423",
  "recordType": "video",
  "sourceUrl": "https://www.tiktok.com/@chris_sbrocco/video/7691036284428635423",
  "authorUsername": "chris_sbrocco",
  "playCount": 18700,
  "diggCount": 204,
  "createTimeISO": "2026-09-29T19:09:17.000Z",
  "musicOriginal": true
}
```

### What does TikTok Video Scraper do?

TikTok Video Scraper reads public TikTok pages and returns structured data as a dataset. Give it video URLs and it returns one record per video: caption, hashtags, publication date, play count, like count, comment count, share count, save count, duration, cover image, author details and the sound that was used. Give it a profile URL and it returns one profile record: display name, bio, follower count, following count, total likes, number of videos and the secure user ID.

It works from the public web page of each URL, the same page a visitor sees without signing in. There is no login, no cookie and no account needed. The Actor never solves CAPTCHAs; if TikTok shows a block page, the Actor retries on a fresh proxy session and gives up on that URL after a few attempts.

The Actor is a good fit when you already know which videos or creators you care about and want clean, comparable numbers for them. Typical uses:

1. tracking how a list of videos performs over time by running the Actor on a schedule;
2. building a spreadsheet of creator profiles with follower counts and bios;
3. checking a campaign: collecting views, likes, comments and shares for every video that was published;
4. feeding video captions and hashtags into your own analysis or an AI agent.

What it does not do: it does not list the videos of a profile, search TikTok, or crawl a hashtag page. Those listings need signed requests that plain page loads do not provide. Each input URL produces at most one record. Short links from vm.tiktok.com and vt.tiktok.com are followed to the video they point to.

### What data can you get?

Video records and profile records share one schema. Fields that do not apply to a record type are `null`.

| Field | Type | Applies to | Description |
|---|---|---|---|
| `authorBio` | string | both | Public creator biography from the same page; null if missing |
| `authorAvatarUrl` | string | both | Creator avatar URL; can expire and is not downloaded |
| `musicOriginal` | boolean | video | TikTok original-sound flag; null when absent or for profiles |
| `id` | string | both | Stable record ID. The video ID for videos, `profile-` plus the user ID for profiles |
| `recordType` | string | both | `video` or `profile` |
| `sourceUrl` | string | both | The page the record was read from |
| `url` | string | both | Canonical public URL of the video or profile |
| `text` | string | video | Video caption |
| `createTime` | number | video | Publication time as Unix epoch seconds |
| `playCount` | number | video | Number of plays |
| `diggCount` | number | video | Number of likes |
| `commentCount` | number | video | Number of comments |
| `shareCount` | number | video | Number of shares |
| `collectCount` | number | video | Number of saves |
| `duration` | number | video | Length in seconds |
| `coverUrl` | string | video | Cover image link, signed and time limited |
| `authorUsername` | string | both | Handle of the creator, without the at sign |
| `authorNickname` | string | both | Display name of the creator |
| `authorVerified` | boolean | both | Whether the account shows a verified badge |
| `authorFollowers` | number | both | Follower count of the creator |
| `musicTitle` | string | video | Title of the sound used |
| `musicAuthor` | string | video | Creator of the sound |
| `hashtags` | array of strings | video | Hashtags in the caption, without the hash sign |
| `followingCount` | number | profile | Accounts the profile follows |
| `likesCount` | number | profile | Total likes received across all videos |
| `videoCount` | number | profile | Number of videos on the profile |
| `bio` | string | profile | Profile bio text |
| `secUid` | string | profile | TikTok secure user ID |
| `avatarUrl` | string | profile | Avatar image link, signed and time limited |
| `createTimeISO` | string | video | Post time as an ISO 8601 UTC timestamp (videos only) |
| `videoUrl` | string | video | Signed video playback link; it expires (videos only) |
| `videoWidth` | integer | video | Video width in pixels |
| `videoHeight` | integer | video | Video height in pixels |
| `locationCreated` | string | video | Country code where the video was posted |
| `textLanguage` | string | video | Detected caption language code |
| `isAd` | boolean | video | Whether the video is marked as an ad |
| `isAigc` | boolean | video | Whether the video is labelled AI-generated |
| `duetEnabled` | boolean | video | Whether duets are allowed |
| `stitchEnabled` | boolean | video | Whether stitches are allowed |
| `musicId` | string | video | Sound ID |
| `authorId` | string | video, profile | Numeric TikTok author ID |
| `mentions` | array | video | Usernames mentioned in the caption |
| `repostCount` | number | video | Reposts shown on the video |
| `categories` | array | video | TikTok topic labels |
| `authorFollowingCount` | number | video, profile | Accounts the creator follows |
| `authorVideoCount` | number | video, profile | Videos the creator has posted |
| `musicPlayUrl` | string | video | Sound audio URL; may expire |

A note on image links: TikTok signs cover and avatar links and they stop working after a while. The Actor only returns the links; it never downloads the images. If you need the images, download them soon after the run.

A note on counts: the numbers are the ones TikTok shows on the page at the moment of the run.

Video records now include `authorBio` and `authorAvatarUrl` copied from the embedded creator object, without a second profile request. Profile records include these alongside the existing `bio` and `avatarUrl`, which keep their original behavior. Missing biographies are null.

`musicOriginal` copies TikTok's original-sound flag for grouping alongside `musicId`, `musicTitle`, and `musicAuthor`. The flag is null for profiles or when omitted.

### How to use TikTok Video Scraper

1. Open the Actor in Apify Console and go to the Input tab.
2. Paste one or more TikTok URLs into the URL list. You can mix video URLs and profile URLs in the same run.
3. Set the maximum number of items. The run stops as soon as that many records are saved.
4. Leave the proxy setting on the default residential proxy unless you have a reason to change it.
5. Click Start. Results appear in the Output tab and can be exported as JSON, CSV, Excel, XML or HTML.

The Actor fetches about one page per second and keeps a small number of requests in flight, to stay polite to the target site. A run with a few dozen URLs finishes in about a minute.

If a URL points to a deleted, private or region blocked video, the Actor logs a warning and skips it. No placeholder record is saved for it. If none of the URLs yields a record, the run still finishes, with an empty dataset and a warning in the log that explains how many URLs failed. If the input has no valid TikTok URL at all, the run fails right away with a clear message.

### Input

| Field | Type | Required | Description |
|---|---|---|---|
| `startUrls` | array | yes | URL objects such as `[{"url":"https://www.tiktok.com/@tiktok"}]`; video/profile URLs and vm/vt short links are accepted |
| `maxItems` | integer | no | Maximum records to return across all URLs. 1 to 10000, default 50 |
| `proxyConfiguration` | object | no | Apify Proxy settings. Default is the residential group with the US country |

Example input:

```json
{
  "startUrls": [
    { "url": "https://www.tiktok.com/@chris_sbrocco/video/7691036284428635423" },
    { "url": "https://www.tiktok.com/@tiktok" }
  ],
  "maxItems": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "US"
  }
}
```

Duplicate URLs are collapsed, and a video that appears twice (for example once as a short link and once as a full link) is saved once. The `maxItems` limit is exact: with `maxItems` set to 7 and ten valid URLs, exactly seven records are saved and the rest are never fetched.

### Output

These shortened records came from local runs on 2026-10-13. Counts and signed URLs can change.

Video record:

```json
{
  "id": "7691036284428635423",
  "recordType": "video",
  "sourceUrl": "https://www.tiktok.com/@chris_sbrocco/video/7691036284428635423?lang=en",
  "text": "This @TikTok TikTok ad campaign is live right now — and it’s airing on major national TV channels like @Fox News @CNN. What a great opportunity to be part of the movement getting the younger generation into the skilled trades. There’s not a better lens for them to look at a career path than social platforms like TikTok. Big thanks to @Akcelo  for choosing me for this campaign, and to Joy for directing it. Everything came out amazing. Much more content around this campaign coming too. Super fortunate to be chosen and to keep partnering with TikTok on skilled trades advocacy. #SkilledTrades #TikTok #Fox #CNN #Trades  ",
  "createTime": 1790708957,
  "playCount": 18000,
  "diggCount": 198,
  "duration": 15,
  "authorUsername": "chris_sbrocco",
  "authorBio": "CLEVELAND | Master Plumber | Builder | Entrepreneur\n\nS5VP1R",
  "authorAvatarUrl": "https://p16-common-sign.tiktokcdn-eu.com/tos-maliva-avt-0068/7330740761455820805~tplv-tiktokx-cropcenter:1080:1080.jpeg?dr=10399&refresh_token=17487986&x-expires=1792069200&x-signature=n%2Fs6fkUnqe4BfJy4xUntbvx4ftk%3D&t=4d5b0474&ps=13740610&shp=a5d48078&shcp=81f88b70&idc=no1a",
  "musicTitle": "original sound",
  "musicOriginal": true,
  "bio": null,
  "avatarUrl": null
}
```

Profile record:

```json
{
  "id": "profile-6516903274669429760",
  "recordType": "profile",
  "sourceUrl": "https://www.tiktok.com/@thedodo?lang=ja",
  "authorUsername": "thedodo",
  "authorFollowers": 6326300,
  "bio": "For animal people.",
  "authorBio": "For animal people.",
  "musicOriginal": null,
  "text": null,
  "playCount": null
}
```

The dataset has an Overview view with the most useful columns: record type, author username and nickname, caption, date, plays, likes, comments, shares, hashtags, followers and URL.

### How much does it cost?

The Actor is charged per result: you pay for each record saved to the dataset, and nothing for URLs that fail or are skipped. Current rates are on the Pricing tab of the Actor page. Because you can cap a run with `maxItems`, the cost of a run is bounded by the limit you set. Apify platform usage, such as proxy traffic, is shown in the run details.

### Use with AI agents (MCP)

You can call this Actor from any MCP compatible AI client through the Apify MCP server. Add the Actor to your client configuration like this:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=axiomworks/tiktok-video-scraper"
    }
  }
}
```

Example prompts you can give your agent:

1. "Get the play count, likes and comments for this TikTok video: https://www.tiktok.com/@chris_sbrocco/video/7691036284428635423"
2. "Look up the TikTok profiles @tiktok and @khaby.lame and compare their follower counts."
3. "Fetch these five TikTok video links and list the hashtags used in each caption."

The input is small and flat, so agents can fill it without help: a list of URLs and an optional limit.

### Integrations and API

You can run the Actor from code, from the Apify API, or connect it to tools such as Make, Zapier, n8n and Google Sheets through the Apify integrations.

**JavaScript**

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('axiomworks/tiktok-video-scraper').call({
  startUrls: [{ url: 'https://www.tiktok.com/@tiktok' }],
  maxItems: 5,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => process.stdout.write(JSON.stringify(item) + "\n"));
```

**Python**

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("axiomworks/tiktok-video-scraper").call(run_input={
    "startUrls": [{"url": "https://www.tiktok.com/@tiktok"}],
    "maxItems": 5,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

**cURL**

```bash
curl -X POST "https://api.apify.com/v2/acts/axiomworks~tiktok-video-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"startUrls":[{"url":"https://www.tiktok.com/@tiktok"}],"maxItems":5}'
```

You can also schedule the Actor to re-run daily or hourly and compare the counts between runs, or set up a webhook that fires when a run finishes.

### FAQ

**Can I scrape all videos of a creator?**
Not with this Actor. It returns one record per URL you provide. A profile URL gives you the profile record with the video count, not the list of videos. Collect the video URLs elsewhere and pass them in.

**Can I search by hashtag or keyword?**
No. Search and hashtag listings are not supported.

**Why is a field null?**
Fields that belong to the other record type are always null. A few video fields, such as the save count or hashtags, can also be empty when the video has none or TikTok does not show them.

**A URL was skipped. Why?**
The video may be deleted, private or not available in the proxy country, or the link may not be a TikTok video or profile URL. The log says which case applies. Try a different proxy country if the video is region restricted.

**Are the cover and avatar links permanent?**
No. TikTok signs them and they expire. Download them soon after the run if you need them.

**Why do I need a residential proxy?**
TikTok often answers datacenter IP addresses with a block page. Residential proxies are the default so runs recover and succeed.

**How many URLs can I process per run?**
Up to the `maxItems` limit, which you can set up to 10000. Because the Actor keeps a gentle request rate, large runs take proportionally longer.

**Does it work with short links?**
Yes. Links from vm.tiktok.com and vt.tiktok.com are followed to the final video page.

### Is it legal to scrape TikTok?

The Actor only reads information that TikTok shows publicly to any visitor without logging in. It does not bypass logins or CAPTCHAs. Whether your use of the data is lawful depends on what you collect and what you do with it. Public pages can still contain personal data, such as usernames, display names and bios, and data protection laws like GDPR can apply to it. Collect only what you need, keep it only as long as you need it, and respect the rights of the people in the data. TikTok's terms of service may restrict automated access, so check them against your use case, and take legal advice if you are unsure. This Actor is an independent tool and is not affiliated with or endorsed by TikTok.

### Feedback

Found a bug, a missing field or a page layout that no longer parses? Open an issue from the Actor page in Apify Console, and include the URL and the run ID so the problem can be reproduced. Suggestions for new fields are welcome too.

# Actor input Schema

## `startUrls` (type: `array`):

Public TikTok video or profile URLs as objects, e.g. \[{"url":"https://www.tiktok.com/@tiktok"}]. Accepts tiktok.com and www.tiktok.com URLs, plus vm.tiktok.com and vt.tiktok.com short links. Each unique available target returns at most one record; profiles return metadata, not video feeds. maxItems is shared across all targets. Unavailable or blocked targets return no row; try another public URL or change proxy settings.

## `maxItems` (type: `integer`):

Shared limit across all startUrls, from 1 to 10000, default 50; e.g. 1 returns at most one video or profile record total. Duplicate IDs and unavailable targets do not count. This limits records, not videos per profile; fewer records are returned when fewer targets are available.

## `proxyConfiguration` (type: `object`):

Proxy settings used for every TikTok page request, e.g. {"useApifyProxy":true,"apifyProxyGroups":\["RESIDENTIAL"],"apifyProxyCountry":"US"}. Defaults to Apify residential proxy in the US. Blocked requests retry on fresh sessions. If targets return no data, check that they are public or change proxy settings.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.tiktok.com/@chris_sbrocco/video/7691036284428635423"
    },
    {
      "url": "https://www.tiktok.com/@tiffstreats/video/7685532257993362701"
    },
    {
      "url": "https://www.tiktok.com/@thedodo/video/7677743868229455135"
    }
  ],
  "maxItems": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

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

One record per URL, videos and profiles.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.tiktok.com/@chris_sbrocco/video/7691036284428635423"
        },
        {
            "url": "https://www.tiktok.com/@tiffstreats/video/7685532257993362701"
        },
        {
            "url": "https://www.tiktok.com/@thedodo/video/7677743868229455135"
        }
    ],
    "maxItems": 3,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/tiktok-video-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 = {
    "startUrls": [
        { "url": "https://www.tiktok.com/@chris_sbrocco/video/7691036284428635423" },
        { "url": "https://www.tiktok.com/@tiffstreats/video/7685532257993362701" },
        { "url": "https://www.tiktok.com/@thedodo/video/7677743868229455135" },
    ],
    "maxItems": 3,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/tiktok-video-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 '{
  "startUrls": [
    {
      "url": "https://www.tiktok.com/@chris_sbrocco/video/7691036284428635423"
    },
    {
      "url": "https://www.tiktok.com/@tiffstreats/video/7685532257993362701"
    },
    {
      "url": "https://www.tiktok.com/@thedodo/video/7677743868229455135"
    }
  ],
  "maxItems": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call axiomworks/tiktok-video-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,axiomworks/tiktok-video-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/BZppIHXzoYjLoWD9b/builds/8f3nIbNyr6EjmyXY0/openapi.json
