Cheapest TikTok API for Developers

Read TikTok profile and video data as structured JSON. Basic calls from $0.07/1K; enriched data, requested depth and optional media have separate charges.

Try for Free Read the Build Guide
5 endpoints 180 items per sync call Free to start No monthly plan

One enriched call returns a whole list for one charge, up to the 180-item synchronous cap. The limit you pass sets both the depth and the price — deeper costs more in total and less per item.

Run a live TikTok profile request

No signup and no key. The box sends a real profile request and prints exactly what the endpoint returns.

Five TikTok Endpoints, One API Key

Profile and video are the flat basic rate. Hashtag, search and music are list calls, and a list call is priced by the depth you ask for.

Video

Video record

from $0.07
/1K calls (Scale tier, basic)
  • GET /api/tiktok/video by id or URL
  • The true author, not a re-post handle
  • Caption, music, hashtags, mentions, labels, stats
  • Optional comments and related groups; include_media is priced separately and is not a group
Default$0.10/1K calls
Growth$0.09/1K calls
Scale$0.07/1K calls
Build guide →
Hashtag

Hashtag

from $2.10
/1K calls at limit=30 (Scale)
  • GET /api/tiktok/hashtag by tag or id
  • Accepts football, #football or a tag URL
  • Up to 180 items in one synchronous call
  • Priced by depth — see the ladder below
Default$3.00/1K calls
Growth$2.70/1K calls
Scale$2.10/1K calls
How depth is priced →
Search

Search

from $2.10
/1K calls at limit=30 (Scale)
  • GET /api/tiktok/search by keyword
  • The same items[] envelope as every other list
  • Up to 180 items in one synchronous call
  • Priced by depth — see the ladder below
Default$3.00/1K calls
Growth$2.70/1K calls
Scale$2.10/1K calls
How depth is priced →
Music

Music

from $2.10
/1K calls at limit=30 (Scale)
  • GET /api/tiktok/music by id or sound URL
  • Every item that used the sound, in one list
  • Up to 180 items in one synchronous call
  • Priced by depth — see the ladder below
Default$3.00/1K calls
Growth$2.70/1K calls
Scale$2.10/1K calls
How depth is priced →

The depth price, in full — $3.00 is the limit=30 price, not a flat rate

Per-item figures below assume every requested item is delivered. A short list costs more per usable returned item; the call charge still follows the requested limit.

An enriched call is any call carrying an include_* group, plus every hashtag, search and music call. It is charged as a fixed part plus a per-item part, and the limit you pass is what moves it. At Default the charge is $3.00/1K × (0.7 + 0.01 × limit).

limit=30 (default)
$3.00
$0.100 per 1,000 items at full yield
limit=60
$3.90
$0.065 per 1,000 items at full yield
limit=100
$5.10
$0.051 per 1,000 items at full yield
limit=180 (sync cap)
$7.50
$0.042 per 1,000 items at full yield

Read that both ways. A limit=180 call bills $7.50 per 1,000 calls — two and a half times the advertised $3.00. Per item it goes the other way: $0.100 falls to $0.042 per 1,000 delivered items at full yield, and to $0.029 on Scale. Short lists cost more per delivered item. Both statements are true and the second is the one we win on, so the first is printed first. Two groups are billed to less depth than you ask for: include_following is billed to a depth of 50 and include_related to the default depth of 30, so at limit=180 they bill $3.60 and $3.00 rather than $7.50. You are never billed for depth a list cannot return. Every other group follows the ladder above. Growth and Scale scale the whole ladder by the same 10% and 30%. The synchronous cap is 180 items; check GET /api/status for job availability, then use the general bulk job contract when available.

include_media is a surcharge, charged on top of the call. Media is $10.00 per 1,000 on Default, $9.00 on Growth and $7.00 on Scale, so a basic video call with media is $0.10 + $10.00 = $10.10 per 1,000 at Default — not $10.00. It is opt-in and never free-eligible, because it is the one part of this API whose cost is bytes rather than requests. When a hosted copy exists the media block carries a link that needs no headers plus an expires_at; when one cannot be produced the block says unavailable.

One call, one charge, whole list. An enriched call returns a list up to the 180-item synchronous cap for a single charge, where per-row vendors bill every item in it. Growth requires one qualifying $100 deposit, Scale $500, and Enterprise $1,000. Enterprise inherits Scale pricing outside Web. New credit uses the current schedule; existing credit keeps its original schedule. Refunded or charged-back amounts do not qualify toward a tier. A list that genuinely comes back empty, or a profile or video that does not exist, is an answer and is charged; a failure on our side is refunded.

TikTok Data in One Request

One header, one GET. Every list — a profile’s posts, a hashtag, a keyword search, a song — comes back in the same envelope, so your parser is written once.

cURL — profile, video, hashtag
# A basic profile — one record, the flat basic rate, no depth to set
curl "https://apiserpent.com/api/tiktok/profile?username=zachking&country=us" \
  -H "X-API-Key: YOUR_API_KEY"

# A video with its true author, music, hashtags and stats
curl "https://apiserpent.com/api/tiktok/video?url=https://www.tiktok.com/@zachking/video/7231" \
  -H "X-API-Key: YOUR_API_KEY"

# A hashtag list. limit sets BOTH the depth and the price — 180 is the sync cap
curl "https://apiserpent.com/api/tiktok/hashtag?tag=cottagecore&limit=180&country=us" \
  -H "X-API-Key: YOUR_API_KEY"
Python — one hashtag list into rows
import os, requests

h = {"X-API-Key": os.environ["SERPENT_API_KEY"]}
p = {"tag": "cottagecore", "limit": 180, "country": "us"}

data = requests.get("https://apiserpent.com/api/tiktok/hashtag",
                    params=p, headers=h, timeout=120).json()

# Check the envelope BEFORE the items. total_count is None when TikTok
# never stated one — it is not the same fact as result_count.
print(data["result_count"], data["total_count"], data["complete"])

for it in data["items"]:
    print(it["video_id"], it["author"]["username"], it["stats"]["play_count"])
Node — one profile record
const qs = new URLSearchParams({ username: "zachking", country: "us" });

const res = await fetch(`https://apiserpent.com/api/tiktok/profile?${qs}`, {
  headers: { "X-API-Key": process.env.SERPENT_API_KEY }
});

const profile = await res.json();
// A basic profile is a single record spread at the top level — no include_* set,
// so this is the flat basic rate and there is no depth to pay for.
console.log(profile.username, profile.verified, profile.stats.follower_count);
JSON Response — /api/tiktok/hashtag (partial)
{
  "success": true,
  "items": [
    {
      "video_id": "7301234567890123456",
      "video_url": "https://www.tiktok.com/@example/video/7301234567890123456",
      "description": "three weeks of sourdough in 40 seconds #cottagecore",
      "created_at": "2026-08-19T09:14:02.000Z",
      "author": {
        "username": "example",
        "nickname": "Example Creator",
        "verified": false
      },
      "music": {
        "music_id": "6987654321098765432",
        "title": "original sound",
        "original": true
      },
      "stats": {
        "play_count": 418200,
        "digg_count": 61400,
        "comment_count": 812,
        "share_count": 2140
      },
      "hashtags": [ { "name": "cottagecore" } ],
      "mentions": []
    }
  ],
  "result_count": 180,
  "total_count": null,
  "has_more": true,
  "next_cursor": "180",
  "truncated": false,
  "restricted": false,
  "complete": false,
  "meta": {
    "elapsed": "41830ms",
    "timestamp": "2026-09-08T11:04:31.522Z"
  }
}

Read the envelope before the items. total_count is null here because TikTok did not state a total for this tag — it is never back-filled from result_count, because “180 arrived” and “there are 180” are different facts. truncated (TikTok cut the list short), restricted (the list is not public) and complete (we reached the natural end) are three separate flags for three separate situations, and a collection that treats them as one will quietly record a private account as an empty one.

Every Field a TikTok Call Returns

Named JSON fields, not HTML you have to select against. Every key is always present, so an absent value arrives as null and never as a missing key.

Profile record

  • username, user_id, sec_uid
  • nickname, biography, bio_link
  • profile_url, avatar.thumb/medium/large
  • verified, private_account, is_organization
  • commerce_user, tt_seller, is_ad_virtual
  • region, language, created_at
  • stats (followers, likes, videos)
  • settings.comment/duet/stitch/download
  • settings.liked_videos_public
  • tabs.music, tabs.question, tabs.playlist

Video record

  • video_id, video_url, description
  • created_at, created_region, language
  • author (the true author, not a re-post)
  • music.music_id, title, author_name
  • music.original, music.duration
  • stats.play_count, digg_count
  • stats.comment_count, share_count
  • hashtags[], mentions[], labels[]
  • image_post, is_ad
  • duet_enabled, stitch_enabled, share_enabled
  • media.play_url, media.download_url (every video call)
  • media.video_link_headers, media.link_expires_at
  • media.hosted (only with include_media)

The list envelope

  • items[]
  • result_count
  • total_count (null when unstated)
  • has_more
  • next_cursor
  • truncated
  • restricted
  • complete
  • partialResults.requested
  • partialResults.returned
  • partialResults.reason, .note

Request parameters

  • username — profile
  • video_id or url — video
  • tag, q, music_id — the list calls
  • limit (1–180 sync; sets the price)
  • country (two-letter code)
  • include_posts, include_followers
  • include_following, include_liked
  • include_comments, include_related
  • include_media (surcharge, never free)

The playback links ship on every video call — and one field has to travel with them. media.play_url and media.download_url come back on every /video call at no extra charge, with no flag to set. They are time-limited, and a request for one has to carry the exact header set returned beside it in media.video_link_headers — send it as returned, unchanged. Without it the request does not get the file. media.link_expires_at is that link’s own expiry, so read it off the response rather than assuming a window. When we cannot produce a link that will actually serve, all four come back null instead of a link that would fail on you later. media.hosted is the separate, paid part: our own copy of the file, on a link that needs no headers, and the only piece include_media adds.

What is TikTok data, and why teams use it

It is the record behind a profile, video, hashtag or song: author, bio, stats, caption, music and the list itself. Four things decide whether it is usable.

The author has to be the real one

A TikTok video can surface under a handle that did not make it. author on a video record is the creator of that video, carrying username, user_id, sec_uid, nickname and verified.

If you are building a creator database, an attribution report or an outreach list, this is the field the whole dataset rests on. Getting it wrong does not throw an error — it quietly credits the wrong person for a year.

A list has to say what kind of list it is

An empty list is three different situations. TikTok cut it short (truncated). It is not public (restricted). Or you reached the end and there is genuinely nothing more (complete).

All three are on the envelope, and total_count stays null when TikTok never stated a total rather than being back-filled from what arrived. A collector that cannot tell those apart records a private account as an empty one.

Depth is a price, and it should be visible

One enriched call returns a whole list — up to 180 items — for one charge, where per-row vendors bill every item. That is the structural saving, and it is also why the depth cannot be free.

So the formula is printed on this page rather than discovered on an invoice: $3.00/1K × (0.7 + 0.01 × limit). limit=180 bills $7.50, which is 2.5× the headline — and $0.042 per 1,000 delivered items at full yield. Fewer usable rows raise the effective per-item cost. Two groups are billed to less depth than you ask for: include_following is billed to a depth of 50 and include_related to the default depth of 30, so at limit=180 they bill $3.60 and $3.00. You are never billed for depth a list cannot return.

Media costs bytes, so it is priced apart

include_media is the one option here whose cost is the file rather than the request, and it is billed as a surcharge on top of the call rather than folded into a band that hides it. The playback links are not what it buys — those come back on every video call at no extra charge.

It is opt-in and never free-eligible. When a hosted copy exists, the media block carries a link that needs no headers plus an expires_at; when one cannot be produced it says unavailable rather than returning a link that will fail later.

TikTok API Pricing, Side by Side

Every figure is the vendor’s own published rate. Units differ wildly here, so the table names each one and normalises to a comparable figure below.

Provider What one unit is Cost per 1,000 — entry Cost per 1,000 — lowest published What the lowest rate requires Free tier
Serpent API Per call. A profile or a video flat; a list call returns up to 180 items for one charge. $0.10 basic
$3.00 list call at limit=30
$0.07 basic
$2.10 list call at limit=30
A single $500 deposit, spendable as balance. No monthly plan and no daily bucket; the tier never expires or downgrades — refunded or charged-back amounts don't count. Free to start
Apify — clockworks/tiktok-scraper Per result (one post) $3.70 $1.70 Gold discount tier, on Apify’s Business plan. Bronze $19/month is $3.00; Silver $199 is $2.30; Gold $999 is $1.70. Two cheaper tiers, Platinum and Diamond, sit on no published Apify plan — contact sales only (checked 2026-09-16). $5 platform credit
Apify — xmolodtsov/tiktok-search-scraper Per post $0.30 $0.20 Gold discount tier, on Apify’s $999/month Business plan. Two cheaper tiers, Platinum and Diamond, sit on no published Apify plan — contact sales only (checked 2026-09-16). $5 platform credit
Apify — pro100chok/tiktok-profile-pro Per profile $4.00 $3.00 Gold or above; Business is $999 per month $5 platform credit
Apify — get-leads/all-in-one-tiktok-scraper Per profile $2.40 $1.50 Gold or above; Business is $999 per month $5 platform credit
ScrapingDog Per request (5 credits) $1.00 (LITE, $40/month) $0.136 $30,000 per month 200 credits
Bright Data Per record $1.50 (pay as you go) $1.30 Scale plan, $499 per month 5,000 records/month
EnsembleData Per unit, drawn from a daily bucket that does not roll over about $2.22 per 1,000 units (Wood, $100/month, 1,500 units/day) about $0.93 per 1,000 units Platinum, $1,400 per month — and only if you spend the full daily allowance every day. The bucket resets at 00:00 UTC. 50 units/day

Normalised per item, which is the only fair way to read the rows above. Rates checked against each vendor’s own live pricing page on 2026-09-08. An enriched list call can return up to 30 items at the default depth and up to 180 at the cap. At full yield only, per delivered item it is $0.100 per 1,000 items at limit=30 and $0.042 at limit=180 on Default, or $0.029 at limit=180 on Scale. At full yield, that is 3× below the compared Apify actor's $0.30 free-tier rate and 2× below its $0.20 lowest published rate at the default depth, widening to 4.8× at limit=180. Fewer usable rows narrow or erase those differences. That $0.20 needs Apify’s $999-a-month Business plan; its two cheaper discount tiers, Platinum and Diamond, sit on no published plan at all (checked 2026-09-16). One row genuinely beats us, on the per-item unit, and it is in the table above. ScrapingDog’s floor of $0.136 per 1,000 requests is above our $0.10 basic call, and it needs $30,000 a month. EnsembleData’s Platinum plan normalises to roughly $0.047 per 1,000 posts on Search Hashtag, where one unit returns 20 posts: about twice as cheap as our full-yield default-depth $0.100, and slightly dearer than our full-yield $0.042 at limit=180. It costs $1,400 a month and holds that rate only if you spend the full daily allowance every single day.

What Teams Actually Pull TikTok Data For

Four jobs that account for most TikTok data traffic, and the endpoint, depth and parameters each one needs.

Creator research and outreach lists

A basic /api/tiktok/profile call is the flat rate and carries bio, bio_link, region, verified, private_account, commerce_user and the follower and like counts — enough to qualify a creator without paying for depth.

Add include_posts only for the handles that survive the first filter. That keeps the expensive band on the shortlist rather than on the whole scan.

Trend and hashtag tracking

Poll /api/tiktok/hashtag on a tag list and diff the item set day over day. One call returns the whole page for one charge, and has_more plus next_cursor tell you whether there was more behind it.

Set limit deliberately: it is the parameter that moves the invoice. A daily limit=30 sweep and a weekly limit=180 deep pull is usually cheaper than either alone.

Sound and campaign monitoring

/api/tiktok/music takes a music id or a sound URL and returns the items that used it, in the same envelope. That is how you measure whether a brand sound is actually being picked up rather than just posted.

Each item carries the true author, so a spike resolves to the creators who caused it instead of to whoever reposted it hardest.

Audit-safe list collection

truncated, restricted and complete, plus a partialResults block naming requested and returned, keep a list run honest: a short list is labelled short rather than filed as a finding.

That matters most when the output is a report someone else will act on. A silently truncated feed and a genuinely quiet week look identical in a chart, and only one of them is real.

Bash — daily hashtag sweep with an honest short-list check
# One line per tag: date, tag, items returned, and whether the list was complete.
# limit=30 is the default depth and the cheapest per call — deepen only when it pays.
while IFS= read -r tag; do
  curl -s -G "https://apiserpent.com/api/tiktok/hashtag" \
      --data-urlencode "tag=$tag" -d "limit=30" -d "country=us" \
      -H "X-API-Key: $SERPENT_API_KEY" \
    | jq -r --arg t "$tag" \
        '[$t, (.result_count|tostring), (.complete|tostring), (.restricted|tostring)] | @csv' \
    | sed "s|^|$(date -u +%F),|" >> tiktok-tags.csv
done < tags.txt

TikTok API Questions

Yes. /api/tiktok/profile, /video, /hashtag, /search and /music all answer today, and the rates on this page are the billable rates. Basic /profile and /video calls usually return in a few seconds. Optional field groups and list requests can take 20 to 40 seconds; check GET /api/status for job availability. When available, submit TikTok items through POST /api/bulk/jobs using tiktok_profile, tiktok_video, tiktok_hashtag, tiktok_search or tiktok_music. A retryable 503 or 504 includes an async_endpoint when a job form is available, and a failed call is not charged.
Five: profile, video, hashtag, search and music. Profile and video return a single record and accept optional include_* groups; hashtag, search and music are list calls. Every list on every endpoint — a profile’s posts, a hashtag feed, a keyword search, the videos using one song — comes back in the same items[] envelope, so a parser written for one reads all of them.
Two bands. Basic is a profile or video call with no enrichment groups: $0.10 per 1,000 calls on Default, $0.09 on Growth, $0.07 on Scale. Enriched is any call with an enrichment group, plus every hashtag, search and music call: $3.00 per 1,000 calls on Default, $2.70 on Growth and $2.10 on Scale at the default limit=30. Enriched is priced by depth, so those figures are the limit=30 price and not a flat rate — see the depth question below. For videos, include_media alone adds its media surcharge while keeping the Basic base price. A qualifying single $100 deposit unlocks Growth and $500 unlocks Scale. Spending credits does not lower your tier; refunded or charged-back amounts do not count toward qualification.
Because an enriched call is charged as a fixed part plus a per-item part. The exact charge is $3.00/1K × (0.7 + 0.01 × limit) at Default. So limit=30, the default, is exactly the published $3.00; limit=100 is $5.10; and limit=180, the synchronous cap, is $7.50 — two and a half times the advertised rate. Per item it falls the other way: $0.100 per 1,000 items at limit=30, $0.051 at limit=100 and $0.042 at limit=180 ($0.029 on Scale). Two groups are billed to less depth than you ask for: include_following is billed to a depth of 50 and include_related to the default depth of 30, so at limit=180 they bill $3.60 and $3.00 rather than $7.50 — you are never billed for depth a list cannot return. Set limit deliberately. It is the one parameter on this API that changes your invoice.
It is a surcharge charged on top of the call, not a band that replaces it. Media is $10.00 per 1,000 on Default, $9.00 on Growth and $7.00 on Scale, so a basic video call with include_media is $0.10 + $10.00 = $10.10 per 1,000 at Default — not $10.00. It is opt-in and never free-eligible, because it is the only part of this API whose cost is the bytes rather than the request. When a hosted copy exists the media block carries a link that needs no headers plus an expires_at; when one cannot be produced the block says unavailable.
items[] and result_count are what arrived. total_count is TikTok’s own stated total and is null when TikTok did not state one — it is never back-filled from result_count, because that would turn “we do not know” into a number. has_more and next_cursor are what TikTok said about the page after this one. truncated means TikTok cut the list short, restricted means the list is not public, and complete means we reached the natural end and there is genuinely nothing more. Those three are different facts and the envelope keeps them apart.
You get what we hold, and the response says so. A short list carries a top-level partialResults block with requested and returned, plus a reason only when it is short by more than 40%, and a note. A list that genuinely comes back empty, or a profile or video that does not exist, is an answer and is charged; a failure on our side is refunded. Nothing is silently truncated to make a response look complete.
On some units, yes, and the comparison table on this page shows every one of them. ScrapingDog’s floor is $0.136 per 1,000 requests, above our $0.10 basic call — it needs $30,000 a month. Apify’s xmolodtsov/tiktok-search-scraper is $0.30 per 1,000 posts on the free tier and $0.20 on its $999-a-month Business plan, the lowest rate it publishes. EnsembleData’s Platinum plan normalises to roughly $0.047 per 1,000 posts at $1,400 a month, and only if you spend the full daily allowance every day. Where we win is the enriched list per item: $0.100 per 1,000 items at the default depth and $0.042 at limit=180, against that $0.20 published floor. And there is no monthly plan and no daily bucket here at all.
Neither. There is no monthly plan anywhere in Serpent’s pricing and no per-day allowance. Growth requires one qualifying $100 deposit, Scale $500, and Enterprise $1,000. Enterprise inherits Scale pricing outside Web. New credit uses the current schedule; existing credit keeps its original schedule. Refunded or charged-back amounts do not qualify toward a tier. A vendor whose allowance resets at 00:00 UTC and does not roll over cannot let a busy week borrow from a quiet one; a balance can.
Yes. The box at the top of this page sends a real profile request with no signup and no key, and prints exactly what the endpoint returns. Free to start on eligible endpoints, with the allowance shared across them and no card required. Media is the one thing the free calls never cover.

Start using the TikTok API

Free to start on eligible endpoints, with the allowance shared across them. No card, no subscription, no monthly plan and no daily bucket. TikTok profile and video data from $0.07/1K calls.

Get your free API key

Related guides

More on working with social and creator data in code.

Track a TikTok Hashtag with an API Without Inventing a TrendBuild a dated TikTok hashtag review from returned video IDs and list flags, without mistaking a sampled list for platform-wide trend volume. I Reviewed TikTok Video API Fields. Here’s What to Save for Repeat Checks.Read a known TikTok video ID, validate identity and metadata, and handle missing counts and expiring media links without overclaiming. Best TikTok Scraping APIsEvery vendor compared on price, unit and list honesty. Build a TikTok Scraper in PythonA runnable route to profile, video and hashtag records. Instagram APIProfiles and recent posts in the same call, at the same price. YouTube APIChannel, video and search data without a quota unit. Social Media APIEvery social surface in the catalog, on one key. The Cheapest SERP API in 2026A full cost comparison across every major provider. Amazon Scraper APIProduct, search and bestseller data across 22 marketplaces. PricingEvery published rate, and the two one-time deposit tiers.