100 free credits. No credit card required.Start building
Logo
TikTok logo
100 free credits. No credit card required

TikTok Trending API

Returns a page of popular TikTok videos with caption, view and like counts, author and thumbnail. Every row carries post.ext.region, the country the video is registered to.

GET /v1/tiktok/trending

Last updated November 2026Maintained by the SocialCrawl team

When to use the TikTok Trending API

Use it with feed=local for videos mostly from one country (57% measured). The default feed is largely worldwide whatever region you pass, so filter on post.ext.region.

From the API reference

Returns a page of popular TikTok videos for a country, with view, like, comment, share and save counts, caption, author and thumbnail. Two feeds, chosen with feed. The default (feed=global) is TikTok's web trending feed fetched through a connection in region: region sets where the request comes from, not where the videos come from, and for most countries the feed is one worldwide pool. Measured 13/09/2026 over 12 calls in six countries, 22% of its videos were registered in the requested country (US 65%, BR 43%, GB 9%, FR 8%, JP 6%, DE 0%). It returns about 13 videos in 3 to 12 seconds. feed=local is the For You feed TikTok's app serves to a phone set to region, so most, not all, of its videos are from that country: 57% of videos on 10 served pages the same day (DE 52%, US 66%, GB 41%, JP 81%), and 51% were captioned in the country's main language. It returns a median of 24 videos (13 to 33 on 9 pages in 10), and 9 calls in 10 answer within 22 seconds (364 served pages, 18-19/10/2026). On about 1 local call in 11 (26 of 281 measured 14-17/10/2026) the supplier is throttled or times out and no video comes back: that returns 503 with credits refunded, and a retry a minute later usually succeeds. A local request never falls back to the global feed. Both feeds cost the same, carry no cursor, and return each video once. Every row carries ext.region, the country the video is registered to, so filter on it when you need only that country; local rows also carry ext.content_language, TikTok's own caption-language tag. post.ext.matched_song_id is the catalogue song TikTok matched the row's sound to, present when it made a match: an official clip and the original sounds creators upload with it have different post.ext.music_id values and one matched_song_id, so group on it to count a song's uses (it is not a clipId for /v1/tiktok/song/videos).

Searching 69 platforms in parallel

·TikTok logoTikTok·Instagram logoInstagram·YouTube logoYouTube·Facebook logoFacebook·X logoX·LinkedIn logoLinkedIn·Reddit logoReddit·Threads logoThreads·Pinterest logoPinterest·Twitch logoTwitch·Truth Social logoTruth Social·Snapchat logoSnapchat·Kick logoKick·Bluesky logoBluesky·Kwai logoKwai·Rumble logoRumble·Spotify logoSpotify·Apple Music logoApple Music·TikTok Shop logoTikTok Shop·Amazon Shop logoAmazon Shop·Google Shopping logoGoogle Shopping·Trustpilot logoTrustpilot·TripAdvisor logoTripAdvisor·Yelp logoYelp·Linktree logoLinktree·Komi logoKomi·Pillar logoPillar·lnk.bio logolnk.bio·Facebook Ads logoFacebook Ads·Google Ads logoGoogle Ads·LinkedIn Ads logoLinkedIn Ads·Google Search logoGoogle Search·Google News logoGoogle News·Finance logoFinance·Polymarket logoPolymarket·Tavily logoTavily·Hacker News logoHacker News·GitHub logoGitHub·Perplexity logoPerplexity·Naver logoNaver·Utility logoUtility·Universal Search logoUniversal Search
·TikTok logoTikTok·Instagram logoInstagram·YouTube logoYouTube·Facebook logoFacebook·X logoX·LinkedIn logoLinkedIn·Reddit logoReddit·Threads logoThreads·Pinterest logoPinterest·Twitch logoTwitch·Truth Social logoTruth Social·Snapchat logoSnapchat·Kick logoKick·Bluesky logoBluesky·Kwai logoKwai·Rumble logoRumble·Spotify logoSpotify·Apple Music logoApple Music·TikTok Shop logoTikTok Shop·Amazon Shop logoAmazon Shop·Google Shopping logoGoogle Shopping·Trustpilot logoTrustpilot·TripAdvisor logoTripAdvisor·Yelp logoYelp·Linktree logoLinktree·Komi logoKomi·Pillar logoPillar·lnk.bio logolnk.bio·Facebook Ads logoFacebook Ads·Google Ads logoGoogle Ads·LinkedIn Ads logoLinkedIn Ads·Google Search logoGoogle Search·Google News logoGoogle News·Finance logoFinance·Polymarket logoPolymarket·Tavily logoTavily·Hacker News logoHacker News·GitHub logoGitHub·Perplexity logoPerplexity·Naver logoNaver·Utility logoUtility·Universal Search logoUniversal Search
·TikTok logoTikTok·Instagram logoInstagram·YouTube logoYouTube·Facebook logoFacebook·X logoX·LinkedIn logoLinkedIn·Reddit logoReddit·Threads logoThreads·Pinterest logoPinterest·Twitch logoTwitch·Truth Social logoTruth Social·Snapchat logoSnapchat·Kick logoKick·Bluesky logoBluesky·Kwai logoKwai·Rumble logoRumble·Spotify logoSpotify·Apple Music logoApple Music·TikTok Shop logoTikTok Shop·Amazon Shop logoAmazon Shop·Google Shopping logoGoogle Shopping·Trustpilot logoTrustpilot·TripAdvisor logoTripAdvisor·Yelp logoYelp·Linktree logoLinktree·Komi logoKomi·Pillar logoPillar·lnk.bio logolnk.bio·Facebook Ads logoFacebook Ads·Google Ads logoGoogle Ads·LinkedIn Ads logoLinkedIn Ads·Google Search logoGoogle Search·Google News logoGoogle News·Finance logoFinance·Polymarket logoPolymarket·Tavily logoTavily·Hacker News logoHacker News·GitHub logoGitHub·Perplexity logoPerplexity·Naver logoNaver·Utility logoUtility·Universal Search logoUniversal Search
·TikTok logoTikTok·Instagram logoInstagram·YouTube logoYouTube·Facebook logoFacebook·X logoX·LinkedIn logoLinkedIn·Reddit logoReddit·Threads logoThreads·Pinterest logoPinterest·Twitch logoTwitch·Truth Social logoTruth Social·Snapchat logoSnapchat·Kick logoKick·Bluesky logoBluesky·Kwai logoKwai·Rumble logoRumble·Spotify logoSpotify·Apple Music logoApple Music·TikTok Shop logoTikTok Shop·Amazon Shop logoAmazon Shop·Google Shopping logoGoogle Shopping·Trustpilot logoTrustpilot·TripAdvisor logoTripAdvisor·Yelp logoYelp·Linktree logoLinktree·Komi logoKomi·Pillar logoPillar·lnk.bio logolnk.bio·Facebook Ads logoFacebook Ads·Google Ads logoGoogle Ads·LinkedIn Ads logoLinkedIn Ads·Google Search logoGoogle Search·Google News logoGoogle News·Finance logoFinance·Polymarket logoPolymarket·Tavily logoTavily·Hacker News logoHacker News·GitHub logoGitHub·Perplexity logoPerplexity·Naver logoNaver·Utility logoUtility·Universal Search logoUniversal Search
TikTok API

What can you do with the Trending API?

The Trending endpoint gives you structured TikTok data with computed fields in a single request. No scraping infrastructure to build or maintain.

Example Request

# GET /v1/tiktok/trending: 5 credits per call. Cache hits are free and failed calls are refunded.
# Check the price first for 0 credits: add dry_run=1 to the query. Nothing is fetched or charged.
# --max-time 58: this endpoint's measured p99 latency x 1.5.
# --retry 3: retries timeouts, 429 and 5xx, honoring Retry-After.
# -o response.json keeps only the final attempt's body.
# One Idempotency-Key per request, reused on every retry, so a retried call is never charged twice.
IDEMPOTENCY_KEY=$(od -An -N16 -tx1 /dev/urandom | tr -d ' \n')
curl -sS --max-time 58 --retry 3 -o response.json \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  "https://www.socialcrawl.dev/v1/tiktok/trending?region=US&trim=true" && cat response.json
# GET /v1/tiktok/trending: 5 credits per call. Cache hits are free and failed calls are refunded.
# Check the price first for 0 credits: add dry_run=1 to the query. Nothing is fetched or charged.
import os
import random
import time
import uuid

import requests

API_KEY = os.environ.get("SOCIALCRAWL_API_KEY", "YOUR_API_KEY")
TIMEOUT_S = 58  # this endpoint's measured p99 latency x 1.5.
MAX_RETRIES = 3
URL = "https://www.socialcrawl.dev/v1/tiktok/trending"


def backoff(attempt):
    # Exponential backoff with jitter: about 1 s, 2 s, then 4 s.
    return 2 ** attempt * (0.5 + random.random() / 2)


def socialcrawl(params):
    # One Idempotency-Key per request, reused on every retry, so a retried call is never charged twice.
    idempotency_key = str(uuid.uuid4())
    for attempt in range(MAX_RETRIES + 1):
        try:
            res = requests.get(
                URL,
                params=params,
                headers={"x-api-key": API_KEY, "Idempotency-Key": idempotency_key},
                timeout=TIMEOUT_S,
            )
            body = res.json()
        except (requests.RequestException, ValueError):
            # A timeout, a dropped connection or a non-JSON gateway page: retry with the same key.
            if attempt == MAX_RETRIES:
                raise
            time.sleep(backoff(attempt))
            continue
        if body["success"]:
            return body
        error = body["error"]
        # Branch on error["type"], never on the message text.
        if error["type"] == "RESOURCE_NOT_FOUND":
            return None  # refunded: nothing to read
        retry_after = res.headers.get("Retry-After")
        # SERVICE_UNAVAILABLE without Retry-After is a withdrawn endpoint: permanent.
        permanent = error["type"] == "SERVICE_UNAVAILABLE" and retry_after is None
        if not error.get("retryable") or permanent or attempt == MAX_RETRIES:
            raise RuntimeError(f"{error['type']}: {error['message']} (request_id {body['request_id']})")
        # Retry-After (seconds) wins; otherwise back off.
        time.sleep(float(retry_after) if retry_after else backoff(attempt))


params = {
    "region": "US",
    "trim": "true",
}
body = socialcrawl(params)
if body is not None:
    print(body["data"])
// GET /v1/tiktok/trending: 5 credits per call. Cache hits are free and failed calls are refunded.
// Check the price first for 0 credits: add dry_run=1 to the query. Nothing is fetched or charged.
const API_KEY = process.env.SOCIALCRAWL_API_KEY ?? "YOUR_API_KEY";
const TIMEOUT_MS = 58_000; // this endpoint's measured p99 latency x 1.5.
const MAX_RETRIES = 3;

type Page = { next_cursor: string | null; has_more: boolean };
type SocialCrawlResponse =
  | { success: true; data: any; pagination?: Page; credits_used: number; request_id: string }
  | { success: false; error: { type: string; message: string; retryable: boolean }; request_id: string };

const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
// Exponential backoff with jitter: about 1 s, 2 s, then 4 s.
const backoffMs = (attempt: number) => 2 ** attempt * 1000 * (0.5 + Math.random() / 2);

async function socialcrawl(url: URL) {
  // One Idempotency-Key per request, reused on every retry, so a retried call is never charged twice.
  const idempotencyKey = crypto.randomUUID();
  for (let attempt = 0; ; attempt++) {
    let res: Response;
    let body: SocialCrawlResponse;
    try {
      res = await fetch(url, {
        headers: {
          "x-api-key": API_KEY,
          "Idempotency-Key": idempotencyKey,
        },
        signal: AbortSignal.timeout(TIMEOUT_MS),
      });
      body = (await res.json()) as SocialCrawlResponse;
    } catch (error) {
      // A timeout, a dropped connection or a non-JSON gateway page: retry with the same key.
      if (attempt >= MAX_RETRIES) throw error;
      await sleep(backoffMs(attempt));
      continue;
    }
    if (body.success) return body;
    // Branch on error.type, never on the message text.
    if (body.error.type === "RESOURCE_NOT_FOUND") return null; // refunded: nothing to read
    const retryAfter = res.headers.get("Retry-After");
    // SERVICE_UNAVAILABLE without Retry-After is a withdrawn endpoint: permanent.
    const permanent = body.error.type === "SERVICE_UNAVAILABLE" && retryAfter === null;
    if (!body.error.retryable || permanent || attempt >= MAX_RETRIES) {
      throw new Error(`${body.error.type}: ${body.error.message} (request_id ${body.request_id})`);
    }
    // Retry-After (seconds) wins; otherwise back off.
    await sleep(retryAfter ? Number(retryAfter) * 1000 : backoffMs(attempt));
  }
}

const url = new URL("https://www.socialcrawl.dev/v1/tiktok/trending");
url.searchParams.set("region", "US");
url.searchParams.set("trim", "true");

const body = await socialcrawl(url);
if (body) console.log(body.data);

Parameters worth sending

  • region=US Results for one market.
  • trim=true Same price, lighter payload: drops the bulky raw fields.

Parameters

ParameterRequiredDescription
regionYesISO 3166-1 alpha-2 country code (e.g., US, GB, DE). On the default feed it sets the country the request is routed through and does not filter videos; with `feed=local` it sets the country the For You feed is built for. Either way, check `ext.region` on each row for the country a video is actually from.
trimNoAccepted for compatibility; it has no effect with `feed=local`.
feedNo`global` (default): the web trending feed routed through `region`, mostly worldwide content, about 13 videos in 3 to 12 seconds. `local`: the For You feed for a phone in `region`, most videos from that country, a median of 24 videos with 9 calls in 10 answering within 22 seconds, and a refunded 503 when none come back. (global | local)
sinceNoOnly rows published on or after this date: YYYY-MM-DD (midnight UTC) or an ISO 8601 timestamp. Rows older than it are left off each page. This list is not in date order, so the walk does not stop at the date: keep following `next_cursor`, and each page costs what a page costs even when every row on it is filtered out. A row with no date is kept. `published_after`, `start_date`, `from_date`, `publish_time` (`yesterday`, `this-week`, `this-month`, `last-3-months`, `last-6-months`) and `max_age_days` are accepted and applied as `since`.
untilNoOnly rows published on or before this date: YYYY-MM-DD (that whole UTC day is included) or an ISO 8601 timestamp. Newer rows are left off each page and the walk does not stop, so older pages follow. A row with no date is kept. `published_before`, `end_date` and `to_date` are accepted and applied as `until`.
Example Response

What does the TikTok Trending API return?

Every response follows one unified schema. Here is a real, unmodified response body, so you can see the exact fields you get back before spending a credit.

Example response
{
  "success": true,
  "platform": "tiktok",
  "endpoint": "/v1/tiktok/trending",
  "data": {
    "items": [
      {
        "post": {
          "id": "7682049568975932702",
          "url": "https://www.tiktok.com/@user_ef4bc4/video/7682049568975932702",
          "content": {
            "text": "Sample comment text (redacted). Sample comment text (redacted). Sample comment text (redacted). Sample comment text (redacted). Sample comment text (redacted). Sample comment text (redacted). Sample comment text (redacted). Sample comment text (redacted). Sample comment text (redacted). Sample comment text (redacted). Sample comment text (redacted). Sample comment text (redacted). Sample comment text (redacted). Sample comment text (redacted).",
            "media_urls": [
              "https://p16-common-sign.tiktokcdn-us.com/tos-useast8-i-photomode-tx2/b5d243cd1e17487e8aa85aedec348a33~tplv-photomode-sr-vqe2-new:1440:0:1080:0:q75.jpeg?dr=10952&refresh_token=2a8eb8de&x-expires=1792242000&x-signature=tn8wMg1ATV4g%2ByST%2BpI4o4L%2BzQw%3D&t=5897f7ec&ps=28cf8ac7&shp=d05b14bd&shcp=1a816805&idc=useast5&s=FEED&biz_tag=tt_photomode&sc=image"
            ],
            "thumbnail_url": "https://p16-common-sign.tiktokcdn-us.com/tos-useast8-i-photomode-tx2/b5d243cd1e17487e8aa85aedec348a33~tplv-photomode-image-cover:640:0:q70.webp?dr=12229&refresh_token=a2b32c0d&x-expires=1792242000&x-signature=0bt9TVezhwQ2A3yzOq2dRxKPRMY%3D&t=5897f7ec&ps=d5b8ac02&shp=d05b14bd&shcp=1a816805&idc=useast5&s=FEED&biz_tag=tt_photomode&sc=cover",
            "duration_seconds": 0
          },
          "author": {
            "username": "user_ef4bc4",
            "display_name": "user_4cf053",
            "avatar_url": "https://example.com/avatars/user_783baf.png",
            "verified": false
          },
          "engagement": {
            "views": 3253405,
            "likes": 70388,
            "comments": 1892,
            "shares": 23013,
            "saves": 36428
          },
          "flags": {
            "nsfw": null,
            "spoiler": null,
            "pinned": null,
            "deleted": false
          },
          "published_at": "2026-09-05T13:56:12.000Z",
          "ext": {
            "music_id": "6814378834477975553",
            "author_id": "user_29dfab",
            "region": "US",
            "published_at_epoch": 1788616572
          }
        },
        "computed": {
          "engagement_rate": 0.02929,
          "language": "en",
          "content_category": "other",
          "estimated_reach": 3904086
        }
      },
      {
        "post": {
          "id": "7677659988789103902",
          "url": "https://www.tiktok.com/@user_8a8702/video/7677659988789103902",
          "content": {
            "text": "Sample comment text (redacted). Sample comment text (redacted). Sample comment text (redacted). Sample comment text (redacted).",
            "media_urls": "https://v16m.tiktokcdn-us.com/7200fde1f54a7b3ac3b3dcf15359dec3/6ac0015d/video/tos/useast8/tos-useast8-ve-0068c002-tx2/okqBUMjDiq5QE2iA1WXA7hkPuNyIAfCRMIijd8/?a=1233&bti=OHYpOTY0Zik3OjlmOm01MzE6ZDQ0MDo%3D&&bt=1216&ft=arR-Iqx4m3XPD12Pa4MI3wU3B4zKaeF~O5&mime_type=video_mp4&rc=aWU7NTs0M2U4NzczZjpoaUBpM3FpOmw5cnk7ZDMzaTczNEBfNTZgLy9gXzExNWJjMS4tYSNebGNrMmQ0YTNhLS1kMTJzcw%3D%3D&vvpl=1&l=20261002130753BA797C81DDCD61F02618&btag=e00090000",
            "thumbnail_url": "https://p19-common-sign.tiktokcdn-us.com/tos-useast8-p-0068-tx2/oMKB7A1AiCuAIviA1yaAEhkP4N0IBfCRMEiLpn~tplv-tiktokx-shrink_ep:640:640:q78.jpeg?dr=8592&refresh_token=aa8c83c9&x-expires=1791032400&x-signature=Brow6cNgUtLAHFGTBIaBI63oBb0%3D&t=bacd0480&ps=933b5bde&shp=d05b14bd&shcp=1a816805&idc=useast5&biz_tag=tt_video&s=FEED&sc=cover",
            "duration_seconds": 81
          },
          "author": {
            "username": "user_8a8702",
            "display_name": "user_4c407b",
            "avatar_url": "https://example.com/avatars/user_f9f9c2.png",
            "verified": false
          },
          "engagement": {
            "views": 20024442,
            "likes": 234869,
            "comments": 8723,
            "shares": 23981,
            "saves": 68392
          },
          "flags": {
            "nsfw": null,
            "spoiler": null,
            "pinned": null,
            "deleted": false
          },
          "published_at": "2026-08-24T18:02:23.000Z",
          "ext": {
            "music_id": "7677659961165499167",
            "author_id": "user_491ac5",
            "region": "US",
            "published_at_epoch": 1787594543
          }
        },
        "computed": {
          "engagement_rate": 0.013362,
          "language": "en",
          "content_category": "entertainment",
          "estimated_reach": 24029330
        }
      }
    ],
    "total": null,
    "dropped": 0
  },
  "credits_used": 5,
  "request_id": "req_example000000",
  "cached": false,
  "pagination": {
    "next_cursor": null,
    "has_more": false,
    "page_size": 11
  },
  "credits_remaining": 9999,
  "source": "captured",
  "captured_at": "2026-10-02T13:07:58.191Z",
  "redacted": true
}

Live sample illustrating the unified response shape. Field values reflect the record you query.

API Details

How does the TikTok Trending API work?

Send a GET request with your API key and get back clean, structured JSON in our unified schema. Supported computed fields are populated when the source provides the required inputs.

Method

GET

Response

JSON

Why SocialCrawl

Why use SocialCrawl for TikTok Trending data?

We handle the complexity of TikTok data extraction so you can focus on building. Unified schema, AI enrichment, and zero platform logic in your code.

Developer First

How do you scrape social media data in seconds?

The fastest social media scraping API for developers. Scrape profiles, posts, comments, and analytics from 69 platforms covering 10B+ monthly active users.

One schema, every platform

Query 69 platforms with identical response structures. Write your integration once.

Computed fields, not just scraped

When an endpoint supports these metrics and the source provides the required inputs, the normalized record includes engagement_rate, estimated_reach, content_category, and language. Ready to use.

See your data before you code

Visual Data Explorer. Paste any URL, get rich result cards, sortable tables, CSV export.

import requests

response = requests.get(
    'https://www.socialcrawl.dev/v1/tiktok/profile',
    params={'handle': 'charlidamelio'},
    headers={'x-api-key': 'sc_YOUR_API_KEY'}
)
data = response.json()
[ .JSON ]
{
  "success": true,
  "platform": "tiktok",
  "data": {
    "author": {
      "username": "charlidamelio",
      "followers": 152400000
    },
    "engagement": {
      "likes": 12400000000,
      "engagement_rate": 0.087
    },
    "metadata": {
      "language": "en",
      "content_category": "lifestyle"
    }
  }
}
+ 69 platforms
FAQ

Have a question? We got answers

Find answers to frequently asked questions about SocialCrawl's API, pricing, and capabilities.

Contact us
How do I get the TikTok trending feed with an API?
Send a GET request to /v1/tiktok/trending with region set to a two-letter country code such as US, GB or DE. By default you get TikTok's web trending feed routed through that country, which for most countries is one worldwide pool. Add feed=local for the For You feed TikTok serves a phone in that country: in a 13/09/2026 test, 57% of its videos were from the requested country.
What data does the TikTok Trending endpoint return?
Each trending video includes video id, url, caption, view count, like count, comment count, share count, thumbnail URL, creation timestamp, full creator details, and the country the video is registered to (post.ext.region). Local feed rows also carry TikTok's caption-language tag (post.ext.content_language).
Does region return only videos from that country?
No, region never filters. On the default feed it sets the country the request is routed through, and in a six-country test on 13/09/2026 only 22% of videos matched it (US 65%, DE 0%). With feed=local most videos come from that country (DE 52%, US 66%, JP 81%), but not all. To keep one country's videos only, filter the rows on post.ext.region.
How fresh is the TikTok trending feed?
Each call reflects the feed at the moment of the request, and a repeat call returns a different set. Responses are cached for two minutes, so back-to-back identical requests return quickly without extra credits. The default feed answers in 3 to 12 seconds; a local feed call takes 12 to 35 seconds.
How much does the TikTok Trending API cost?
Each request costs 5 credits on the advanced tier because trending feeds require heavier upstream work. New accounts get 100 free credits with no credit card required.

Ask AI about SocialCrawl

Ready to scrape TikTok Trending data?

Get your API key and start pulling TikTok data in under 60 seconds.

Start for free

🤖 AI agent or LLM? Read this page as markdown