# TikTok Profile Scraper: a creator’s whole back catalogue

TikTok Profile Scraper takes a public TikTok handle and returns that creator’s posts, each one carrying its engagement, its video and audio metadata, and the creator’s own account stats.

[Run this scraper free](https://apify.com/apidojo/tiktok-profile-scraper)

[See the three jobs](#jobs)

apidojo/tiktok-profile-scraper

**Posts returned**

Estimated run cost

$0.00

Free Apify plan: 5 runs a month, 10 items a run. No credit card.

**$0.30** per 1,000 posts

**$0** query fee, results only

**425** posts per second

**99.97%** run success, last 30 days

Read on 27 September 2026.

## Two ways to name a creator, and two ways to bound them

A profile is named by handle or by link, and the two behave identically. The fields that change what comes back are the two date bounds and the run ceiling, and both are easier to get wrong than they look.

-   `usernames`

    $0.0003per post

    No per-profile fee

    The handle on its own. The listing is emphatic: strip the @ before you paste it.

    `gordonramsayofficial`

-   `startUrls`

    $0.0003per post

    Identical results

    The full profile link, as objects. Use it when the handles already live in a column of URLs.

    `{ "url": "https://www.tiktok.com/@f1" }`

-   The field pair that returns nothing when you guess

    `until / since`

    until → sinceold → new

    Reversed on purpose

    The date window, and the two words mean the reverse of what you expect. until is the older edge, since is the newer one.

    `until: "2025-01-01", since: "2025-03-31"`

-   `maxItems`

    × $0.0003caps the bill

    Run-wide, not per profile

    The ceiling on posts for the whole run, shared across every profile in it, not a limit per creator.

    `1000`

Both input fields are read in the same run, so a list can be half handles and half links without splitting it. Neither costs anything by itself: no profile is billed, only the posts that come back.

**Apify actor:** apidojo/tiktok-profile-scraper

**Inputs:** startUrls · usernames · since · until · maxItems · customMapFunction

**Returns:** One record per post, with the creator’s account nested on each

**Billing:** A single charge event at $0.0003 a post. No query fee, no minimum

**Date filter:** since and until, with the listing’s own meanings reversed

**Ceiling:** maxItems caps the whole run, not each profile

**Login or proxy:** Neither. Public profiles only

**Reliability:** 99.97% of 1,081,068 runs succeeded in the last 30 days

## One creator, a roster, or a slice of last quarter

Three shapes of run. What separates them is not the input field but how the ceiling and the date bounds are set, which is where both of this actor’s traps live.

**01 One creator $0.0003 / post · nothing else**

**02 A roster Ceiling shared across the list**

**03 A date window Only posts in range are billed**

### How do you scrape every post from a TikTok profile?

Put the handle in usernames with the @ removed and leave the date fields empty. There is no charge for the profile itself, 500 posts cost $0.15, and a thousand cost $0.30.

Input

```
{
  "usernames": ["gordonramsayofficial"],
  "maxItems": 1000
}
```

1,000 × $0.0003 \= **$0.30**

What comes back

The **post record**, Engagement, video specs and audio on every row, with the creator nested alongside.

```
{
  "id": "7524427347697896726",
  "title": "When afternoon tea interferes with a lap around the @Formula 1 track…",
  "views": 489994,
  "likes": 18968,
  "comments": 267,
  "shares": 952,
  "bookmarks": 1170,
  "uploadedAtFormatted": "2025-07-07T19:41:08.000Z",
  "postPage": "https://www.tiktok.com/@gordonramsayofficial/video/7524427347697896726"
}
```

The profile needs at least ten posts

The listing sets this as a condition of use, not a suggestion: a profile must exist, be public, and carry ten posts or more. Near-empty accounts create overhead and the listing warns they may be blocked. Private and deleted accounts cannot be read at all.

### How do you scrape several TikTok profiles in one run?

List the handles together. The trap is maxItems: it caps the whole run rather than each creator, so ten profiles under a ceiling of 200 share those 200 posts between them instead of taking 200 each.

Input

```
{
  "usernames": ["gordonramsayofficial", "f1", "nike", "adidas"],
  "maxItems": 2000
}
```

2,000 × $0.0003 \= **$0.60**

What comes back

The **post record**, channel.username tells you which creator each row came from across the batch.

```
{
  "channel": {
    "name": "Gordon Ramsay",
    "username": "gordonramsayofficial",
    "url": "https://www.tiktok.com/@gordonramsayofficial",
    "verified": true,
    "followers": 41108596,
    "following": 566,
    "videos": 653
  }
}
```

Multiply the ceiling by the list, or drop it

To give ten creators 200 posts each, set maxItems to 2,000, or leave it empty and let the run take everything. The listing recommends batches of 10 to 50 profiles, and says that when output stops mid-run the Log tab will show lines being skipped: the fix there is smaller batches, not a higher ceiling.

### How do you scrape only recent posts from a TikTok profile?

Use until and since, but read them backwards. In the listing’s own worked example, until is 2025-01-01 and since is 2025-03-31, and the run returns January through March. until sets the older edge of the window; since sets the newer one.

Input

```
{
  "usernames": ["gordonramsayofficial"],
  "until": "2025-01-01",
  "since": "2025-03-31",
  "maxItems": 500
}
```

500 × $0.0003 \= **$0.15**

What comes back

The **post record**, Both timestamp forms ship on every row, so you can sort without parsing a string.

```
{
  "uploadedAt": 1751917268,
  "uploadedAtFormatted": "2025-07-07T19:41:08.000Z",
  "hashtags": [],
  "song": {
    "title": "original sound - gordonramsayofficial",
    "artist": "Gordon Ramsay",
    "duration": 112
  }
}
```

An empty result usually means the pair is the wrong way round

Swapping them gives a window that ends before it starts, which returns nothing and looks exactly like a profile with no posts in range. Dates take YYYY-MM-DD or a full ISO timestamp. The listing also asks you not to set a very narrow range, which it treats as an inefficient query alongside artificially low limits.

## The record is a post, and the creator rides along

This is the thing to get straight before you write the parser: a run over one profile does not return one profile row. It returns a row per post, and the creator’s account stats are repeated on each of them, so the profile is whatever the first row tells you.

-   8

    The post

    One row each

    -   id, title
    -   views, likes, comments
    -   shares, bookmarks
    -   hashtags
    -   postPage, the live link
-   9

    The creator

    channel, repeated per row

    -   name, username, id, url
    -   avatar
    -   verified
    -   followers, following
    -   videos, lifetime count
-   7

    The video file

    video

    -   width, height, ratio
    -   duration, seconds, fractional
    -   url
    -   cover, thumbnail
-   6

    The sound

    song

    -   id, title
    -   artist, album
    -   duration
    -   cover

**id · title:** The post’s ID and its caption text

**views · likes · comments:** Engagement as TikTok showed it at scrape time

**shares · bookmarks:** The two counters most dashboards forget to collect

**hashtags:** Tags used on the post. An empty array where there were none

**postPage:** Canonical link to the post on tiktok.com

**uploadedAt:** Unix seconds, sort on this rather than the string

**uploadedAtFormatted:** The same moment as an ISO 8601 timestamp

**channel.username · name:** Handle and display name of the creator

**channel.followers · following:** Account reach at the moment of the run

**channel.videos:** Lifetime post count, compare it to your row count to spot a truncated run

**channel.verified:** Boolean on the account itself

**channel.bio:** Bio text. The listing names this field and says contact details appear in it, but its Example Output Object does not show it, treat it as present only once you have seen it in your own dataset

**collabInfo.shouldDisplayTag:** Whether TikTok is showing the post as a collaboration

**collabInfo.collaborators:** Each co-creator with id, username, name, avatar, verified, followers and url

**video.duration · ratio:** Length in seconds and the served resolution label

**song.title · artist:** The audio track, including "original sound" attributions

collabInfo is the field worth knowing about: on a joint post it carries the full list of co-creators with their own follower counts, which is how you map partnership networks without running a second scrape against each collaborator.

## Conditions the listing sets on a run

Five, taken from the listing’s usage note, its best-practice list and its troubleshooting section. Two of them will silently return nothing rather than fail loudly.

-   01

    Ten posts is the floor, and the profile must be public

    The listing asks that every profile exist, be public and carry at least ten posts. Private, deleted and near-empty accounts are named as cases that may be blocked rather than served.

-   02

    Strip the @ from every handle

    usernames takes gordonramsayofficial, never @gordonramsayofficial. It is the first thing the quick-start guide says and the last thing anyone checks.

-   03

    maxItems is a total, and it is shared

    The troubleshooting section is explicit that the ceiling applies across the entire run rather than per profile. A batch that comes back lopsided, the first creator complete, the rest empty, is this, not a failure.

-   04

    Never filter inside customMapFunction

    The listing says using the map function to filter results causes automatic blocking. It is for reshaping each object; narrowing the set is what the date fields are for.

-   05

    The Console preview hides most of the row

    It renders a subset of the fields. Collaboration data, the full channel block, song metadata and video specs arrive in the download, take it from the Storage tab before concluding a field is missing.

Free accounts run in demo mode: 5 runs a month, 10 items each, no charge.

## One line on the bill

There is nothing to model here. The actor charges a single event at $0.0003 a post, no fee for a profile, no included allowance to subtract, no tier that changes at volume. Multiply and you are done.

| Run | Method | Calculation | Cost |
| --- | --- | --- | --- |
| 100 posts | 1 profile, a quick test | 100 × $0.0003 | $0.03 |
| 500 posts | 1 profile, one quarter | 500 × $0.0003 | $0.15 |
| 1,000 posts | 1 profile, full history | 1,000 × $0.0003 | $0.30 |
| 2,000 posts | 4 profiles at 500 each | 2,000 × $0.0003 | $0.60 |
| 10,000 posts | 50 profiles at 200 each | 10,000 × $0.0003 | $3.00 |
| 100,000 posts | A roster of 500 creators | 100,000 × $0.0003 | $30.00 |

The listing quotes $30 for 100,000 posts, which is the same arithmetic from the other end. Because nothing is charged per profile, the cost of a run depends only on how many posts come back, so a ceiling is a budget, exactly and with no rounding.

## Who needs a creator’s whole output, not just their follower count?

The listing names influencer marketing, talent scouting, competitive intelligence, lead generation and academic research. What they share is that the answer is in the post history, cadence, consistency, what actually performed, rather than in the headline stat.

-   Influencer vetting

    One creator, full history

    Judge authenticity by posting cadence and the spread of engagement, not by a follower number that can be bought

    $0.30 per 1,000 posts

-   Talent scouting

    A roster, no ceiling

    Track a category’s creators over time and catch the ones whose recent posts outrun their follower count

    $3.00 per 10,000 posts

-   Competitive intelligence

    A date window, monthly

    Re-run the same quarter against rival brand accounts to compare themes, cadence and average engagement

    $0.15 per 500-post quarter

-   Partnership mapping

    A roster, then read collabInfo

    Build the graph of who posts with whom, with each collaborator’s follower count already attached

    $0.60 per 2,000 posts

-   Research datasets

    A roster, thousands deep

    Assemble labelled post corpora for growth modelling, with both timestamp forms on every row

    $30.00 per 100,000 posts

## Driving it from code

The actor is apidojo/tiktok-profile-scraper. Two things are worth wrapping once: the ceiling that has to be multiplied by the size of your list, and the date pair that reads backwards.

**Python**

**JavaScript**

**cURL**

```
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
ACTOR = "apidojo/tiktok-profile-scraper"

def profile_posts(handles, per_profile=200, oldest=None, newest=None):
    # maxItems caps the RUN, so scale it by the list or the tail goes empty.
    run_input = {
        "usernames": [h.lstrip("@") for h in handles],
        "maxItems": per_profile * len(handles),
    }
    # Reversed on purpose: 'until' is the older edge, 'since' the newer one.
    if oldest: run_input["until"] = oldest
    if newest: run_input["since"] = newest

    run = client.actor(ACTOR).call(run_input=run_input)
    return list(client.dataset(run.default_dataset_id).iterate_items())

rows = profile_posts(["gordonramsayofficial", "f1"], oldest="2025-01-01", newest="2025-03-31")

for r in rows:
    print(r["channel"]["username"], r["views"], r["uploadedAtFormatted"], r["title"][:40])
```

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const handles = ['gordonramsayofficial', 'f1', 'nike'];

const run = await client.actor('apidojo/tiktok-profile-scraper').call({
  usernames: handles,
  maxItems: handles.length * 200,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();

// channel.videos is the creator's lifetime count: compare it to what you got
// to see whether the ceiling truncated anyone.
for (const [handle, posts] of Object.entries(Object.groupBy(items, (r) => r.channel.username))) {
  console.log(handle, posts.length, 'of', posts[0].channel.videos, 'posts');
}
```

```
curl -X POST \
  "https://api.apify.com/v2/acts/apidojo~tiktok-profile-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"usernames":["gordonramsayofficial"],"maxItems":500}'
```

Exports are JSON, CSV or Excel from the Storage tab, or straight off the API. Apify’s scheduler will re-run a roster nightly, which is the usual way creator growth gets tracked.

## TikTok Profile Scraper FAQ

### How much does it cost to scrape a TikTok profile?

Posts are $0.0003 each and nothing else is charged, so a profile with 500 posts costs $0.15 and one with 1,000 costs $0.30. There is no per-profile fee and no minimum.

### Do since and until work the way I expect?

No, and this is the most common way a run comes back empty. The listing defines until as the older edge of the window and since as the newer one, its own example pairs until 2025-01-01 with since 2025-03-31 to get January through March.

### Why did only my first profile return posts?

maxItems caps the entire run rather than each profile, so a list of ten under a ceiling of 200 shares those 200 posts. Multiply the ceiling by the length of your list, or leave it empty.

### Does it return one row per profile or one per post?

One per post. The creator’s account stats, handle, followers, following, lifetime video count, verification, repeat on every row inside the channel object.

### Can I scrape a private TikTok account?

No. Only public profiles are accessible, and the listing also asks that each profile exist and carry at least ten posts.

### Should usernames include the @ symbol?

No. Paste gordonramsayofficial rather than @gordonramsayofficial. Profile URLs are accepted as an alternative and give identical results.

### Can I see who a creator posts with?

Yes. Joint posts carry a collabInfo object listing every collaborator with their username, display name, follower count, verification status and profile URL.

### How fast is it?

The listing states 425 posts per second, and puts a 500-post profile at under two minutes.

## Where TikTok Profile Scraper fits

[Parent scraper TikTok Scraper All six TikTok scrapers and what each one charges. Three of them can reach a creator’s posts as part of a wider job; this is the one that takes a handle and walks the whole profile, and the only one in the family billed on results alone.](/scrapers/tiktok-scraper/)

Sibling scrapers

-   [TikTok Comments Scraper](/scrapers/tiktok-comments-scraper/)
-   [TikTok User Scraper](/scrapers/tiktok-user-scraper/)
-   [TikTok Location Scraper](/scrapers/tiktok-location-scraper/)

Guides

-   Scoring TikTok creators on cadence instead of followers*Coming soon*
-   Mapping collaboration networks from collabInfo*Coming soon*
-   Date windows that return nothing, and why*Coming soon*

## Scrape one creator

A thousand posts for thirty cents. No query fee to reason about.

`usernames: ["gordonramsayofficial"] · maxItems: 1000`

[Run this scraper free](https://apify.com/apidojo/tiktok-profile-scraper)

Apidojo is not affiliated with TikTok or ByteDance.

## Guides for this scraper

-   [TikTok scraping guides Pulling posts, comments, sounds and places from TikTok: which door each scraper goes in by, what a run costs, and what the output does not contain.](/blog/tiktok/)
-   [TikTok date windows that return nothing, and why TikTok Profile Scraper's since and until mean the opposite of what almost everyone assumes. Swap them and the run returns an empty dataset.](/blog/tiktok/tiktok-since-until/)
-   [Why your TikTok user run cost three queries getFollowers and getFollowing are both on by default, and each is its own charge on top of the profile lookup. An unconfigured run bills three times.](/blog/tiktok/tiktok-user-defaults/)
