> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go-fetch.io/llms.txt
> Use this file to discover all available pages before exploring further.

# TikTok

> Videos from public TikTok profiles, with their stats. scraper_type tiktok.

`tiktok` collects the videos and photo posts of public TikTok accounts. One result is one post. For keyword search,
use [TikTok search](https://docs.go-fetch.io/scrapers/tiktok-search.md); for profile details in bulk, [TikTok profile](https://docs.go-fetch.io/scrapers/tiktok-profile.md).

## Run it

```python Python theme={null}
import os

from gofetch import GoFetchClient

client = GoFetchClient(api_key=os.environ["GOFETCH_API_KEY"])

run = client.actor("tiktok").call(run_input={"profiles": ["nasa", "natgeo"], "limit": 20})

for video in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(video["createTimeISO"], video["webVideoUrl"], video["playCount"], video["diggCount"])
```

```bash cURL theme={null}
curl https://go-fetch.io/api/v1/jobs/create/ \
  -H "X-API-Key: $GOFETCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"scraper_type": "tiktok", "config": {"profiles": ["nasa", "natgeo"], "limit": 20}}'
```

## Inputs

| Field | Type | Default | What it does |
| - | - | - | - |
| `profiles` | list of text | | Accounts: `nasa`, `@nasa` or `https://www.tiktok.com/@nasa`. `usernames` and `directUrls` are accepted as other names for the same list. |
| `limit` | integer | no limit | Posts per profile, from 0 to 1,000,000; the newest come first. Leave it out, or send `0`, to collect each profile's full history. |
| `onlyPostsNewerThan` | date (`YYYY-MM-DD`) | | Only posts published on or after this date. Posts from up to two hours before midnight UTC can be included. Not in the future. |
| `maxTotalChargeUsd` | number | | A spending cap, split across the profiles as a per-profile limit that never exceeds your `limit`. See [Billing](https://docs.go-fetch.io/billing.md#cap-a-job-with-maxtotalchargeusd). |

> [!NOTE]
>
> Send each profile once: a handle listed twice is collected, and billed, twice. A link to a video collects its
> author's whole profile. Keyword and hashtag input (`searchQueries`, `hashtags`, search or tag links) is refused with
> `400`: use [TikTok search](https://docs.go-fetch.io/scrapers/tiktok-search.md).

These Apify inputs are accepted but have no effect. A value other than the one shown adds a warning to the job's
log:

* `shouldDownloadVideos` (`true`): videos are always stored.
* `shouldDownloadCovers` and `shouldDownloadSlideshowImages` (`false`).
* `profileSorting` (`"latest"`): posts come newest first.
* `disableCheerioBoost` and `disableEnrichAuthorStats` (`false`).

> [!WARNING]
>
> Without `limit` or a date filter, a job collects every post of every profile. The cost then depends on how many
> posts they have. Set `limit`, `onlyPostsNewerThan` or `maxTotalChargeUsd`.

A date filter within the last 29 days makes the job a recent crawl, which is billed at its own rate; see
[Billing](https://docs.go-fetch.io/billing.md#rates).

## Output

One row per post. A real row from a job for @lego (the link to the stored video is masked here):

```json theme={null}
[
  {
    "id": "7696136651688512799",
    "text": "Take me back 🌧️ #LEGO #Autumn #ASMR ",
    "createTime": 1791896492,
    "createTimeISO": "2026-10-13T13:01:32.000Z",
    "author": "lego",
    "authorMeta": {
      "id": "7110143773192225797",
      "name": "lego",
      "nickName": "LEGO",
      "verified": true,
      "signature": "a minifigure runs this account",
      "bioLink": "",
      "avatar": "https://p19-common-sign.tiktokcdn-us.com/tos-useast2a-avt-0068-euttp/d0a44a47c41de16977fc7e8c104698d3~tplv-tiktokx-cropcenter:1080:1080.jpeg?dr=9640&refresh_token=b84a357a&x-expires=1792209600&x-signature=lGYnEX7i8UvIXj%2Fro59hWEPSnbU%3D&t=4d5b0474&ps=13740610&shp=a5d48078&shcp=81f88b70&idc=useast8",
      "commerceUserInfo": {
        "commerceUser": false
      },
      "privateAccount": false,
      "region": "",
      "roomId": "",
      "ttSeller": false,
      "following": 0,
      "friends": 0,
      "fans": 0,
      "heart": 0,
      "video": 0,
      "digg": 0
    },
    "musicMeta": {
      "musicName": "original sound",
      "musicAuthor": "LEGO",
      "musicOriginal": true,
      "playUrl": "https://v16-webapp-prime.us.tiktok.com/video/tos/useast8/tos-useast8-v-27dcd7-tx2/o4m2ESfDVI81JyqUsV4IGzNicB1CeEuAFAAsIA/?a=1988&bti=ODszNWYuMDE6&&bt=125&ft=GcAInInz7ThvowKGXq8Zmo&mime_type=audio_mpeg&rc=Mzk4OXg5cmU1ZTMzaTU8NEBpMzk4OXg5cmU1ZTMzaTU8NEBmZm1fMmQ0azRhLS1kMTJzYSNmZm1fMmQ0azRhLS1kMTJzcw%3D%3D&expire=1792060657&l=2026101504372932172A6527882606EAE0&ply_type=3&policy=3&signature=0c6684625d771cc105efb42fc30285fb&tk=0&btag=e00070000",
      "coverMediumUrl": "https://p19-common-sign.tiktokcdn-us.com/tos-useast2a-avt-0068-euttp/d0a44a47c41de16977fc7e8c104698d3~tplv-tiktokx-cropcenter:720:720.jpeg?dr=9640&refresh_token=ebad9c2d&x-expires=1792209600&x-signature=4SeQLSxkkbiKfccFAmksucZLSVA%3D&t=4d5b0474&ps=13740610&shp=a5d48078&shcp=81f88b70&idc=useast8",
      "musicId": "7696136804512107294"
    },
    "webVideoUrl": "https://www.tiktok.com/@lego/video/7696136651688512799",
    "mediaUrls": [
      "<masked: https://go-fetch.io/api/v1/jobs/{id}/media/{name}?token=…>"
    ],
    "slideshowImageLinks": [],
    "videoMeta": {
      "height": 1024,
      "width": 576,
      "duration": 8,
      "coverUrl": "https://p16-common-sign.tiktokcdn-us.com/tos-useast8-p-0068-tx2/oEEe4rEAVBAFEEiKDsRGqzfuAuDJECAI6A6qgO~tplv-tiktokx-dmt-logom:tos-useast8-i-0068-tx2/o0qAVNcLqCpIiAFR7EFQV1VAAzEkAffGVuVDEi.image?dr=9634&x-expires=1792209600&x-signature=fg%2FDhGDBfcWylfY3nAmQsqnT5U4%3D&t=4d5b0474&ps=13740610&shp=81f88b70&shcp=43f4a2f9&idc=useast8",
      "originalCoverUrl": "https://p16-common-sign.tiktokcdn-us.com/tos-useast8-p-0068-tx2/ocsI463AO6RIBi7r4snAEgviVKqzB0aAwOEIA~tplv-tiktokx-origin.image?dr=9636&x-expires=1792209600&x-signature=sV7QaWK1CYyxqDM2TLLVOk1JZrg%3D&t=4d5b0474&ps=13740610&shp=81f88b70&shcp=43f4a2f9&idc=useast8",
      "definition": "540p",
      "format": "mp4",
      "originalDownloadAddr": "",
      "downloadAddr": "<masked: https://go-fetch.io/api/v1/jobs/{id}/media/{name}?token=…>",
      "subtitleLinks": []
    },
    "diggCount": 671,
    "shareCount": 6,
    "playCount": 19200,
    "collectCount": 41,
    "commentCount": 104,
    "mentions": [],
    "hashtags": [
      {
        "name": "lego"
      },
      {
        "name": "autumn"
      },
      {
        "name": "asmr"
      }
    ],
    "effectStickers": [
      "",
      ""
    ],
    "isMuted": false,
    "isSlideshow": false,
    "isPinned": false,
    "isSponsored": false,
    "input": "lego"
  }
]
```

| Field | Type | What it holds |
| - | - | - |
| `id` | text | The post's id. |
| `text` | text | The caption. |
| `createTime`, `createTimeISO` | integer, date-time | When it was posted, as Unix seconds and as ISO 8601 UTC. |
| `webVideoUrl` | URL | Link to the post. |
| `playCount`, `diggCount`, `commentCount`, `shareCount`, `collectCount` | integer | Plays, likes, comments, shares and saves. |
| `author` | text | The author's handle. |
| `authorMeta` | object | Author fields: `id`, `name` (handle), `nickName`, `verified`, `signature` (bio), `bioLink`, `avatar`, `privateAccount`, `commerceUserInfo`, `ttSeller`, `region`, `roomId`, and counts `fans`, `following`, `friends`, `heart`, `video`, `digg`. |
| `musicMeta` | object | The sound: `musicName`, `musicAuthor`, `musicOriginal`, `musicId`, `playUrl`, `coverMediumUrl`. |
| `videoMeta` | object | `height`, `width`, `duration` (seconds), `coverUrl`, `originalCoverUrl`, `definition`, `format`, `downloadAddr` (the same stored-video path as `mediaUrls`), `subtitleLinks`. |
| `mediaUrls` | list of text | For a video, the absolute link to a copy we stored, `https://go-fetch.io/api/v1/jobs/{id}/media/{name}?token=…`. No API key needed: `GET` or `HEAD` on the link returns a `302` to a download link for that method, valid for 10 minutes. The link itself is valid for 5 days, and each read of the results returns fresh ones. Without the token, the path still works with your `X-API-Key` header (counts toward the key's hourly rate limit); a bad or expired token is a `404`. The copy goes when the job's results are deleted. If storing failed, TikTok's own link or nothing. For photo posts, the image links. |
| `isSlideshow`, `slideshowImageLinks` | true / false, list | Photo posts and their images. |
| `hashtags` | list | Hashtags, each as `{"name": ...}`. |
| `mentions` | list of text | Accounts mentioned, as `@handle`. |
| `isPinned`, `isSponsored`, `isMuted` | true / false | Pinned on the profile; an ad; muted. |
| `effectStickers` | list | Effects used. |
| `input` | text | The profile you asked for. |
| `isPartialProfileCrawl` | `true` | Present only when this profile's collection provably stopped short of what you asked for. |

> [!NOTE]
>
> The `authorMeta` counts can be `0` when they were not collected for that row, which is common on date-filtered
> jobs. Use [TikTok profile](https://docs.go-fetch.io/scrapers/tiktok-profile.md) for reliable author counts. Avatar, cover and sound links
> point at TikTok's servers and expire.

Some rows also carry `textLanguage`, `isAd`, `detailedMentions` and `fromProfileSection`, depending on how the post
was read.

## What logged-out means here

**You get:** posts from public accounts with their captions, counts, sound and author fields, as a signed-out visitor
sees them.

**Not available:**

* Private accounts.
* Accounts whose owner limits who can see them, and accounts TikTok does not show to signed-out visitors. These
  return a `profile_info` row with `"error": "Restricted profile"`, `restriction` and `restrictionReason`. It is not
  billed.
* Deleted or banned accounts.

A profile that returned nothing is listed in `scraper_metadata.targets_failed`, and the job still completes.

## Completeness

| Key | What it says |
| - | - |
| `profiles_scraped` | Profiles that returned at least one row. |
| `profiles_failed` | Profiles listed in `targets_failed`. |
| `completeness` | `profiles_processed`, `profiles_complete`, `profiles_partial`, `profiles_unproven` (the crawl gave no sign it reached the end), `profiles_restricted`, `videos_collected`, and `partial_profiles`: up to 50 profiles that stopped short, each with `username`, `reason`, `videos_collected`, `profile_total_videos`, `oldest_collected` and `requested_since`. |
| `restrictions` | Profiles TikTok withheld: `username`, `restriction` (`login_wall` or `unavailable`), `restrictionReason`. |
| `targets_failed` | Profiles that returned nothing: `target`, `reason` (`unavailable` for private, `not_found` for deleted or banned, `blocked`, `extraction_failed`), `detail` (for reading, not parsing) and `retriable`. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.