TikTokTikTok Search APITikTok Top Search APITikTok Photo Carousel APIKeyword Search

TikTok Search API: Find Videos and Photo Carousels

Research TikTok videos and photo carousels with SocQ. Collect captions, creators, media and engagement counts, with filters and JSON and CSV export code.

SocQUpdated October 16, 20266 min read

Research TikTok videos and photo carousels together with SocQ. Collect captions, creators, media links and engagement counts around one keyword, then organize video demonstrations, recipe cards and image guides in the same topic dataset.

The SocQ TikTok Top Search API searches public videos and photo carousels by keyword. This guide covers the request, result-format handling, and exports of posts and ordered image links.

Quick answer: Send a required query to POST /v1/tiktok/top-search. After the task succeeds, read data.results.items. Use type=video for videos and type=photo_carousel for image posts; the carousel's image entries are in media.

Choose the Search Endpoint for Your Content Format

Starting pointSocQ endpointResult scope
Keyword, videos onlyTikTok SearchA video-search workflow
Keyword, videos and image postsTikTok Top SearchMixed results distinguished by type
Known post URLTikTok VideosRetrieve the specified content
Known sound IDTikTok Song VideosFind videos associated with that sound

Top Search returns existing posts for a keyword. To work with photo posts, select type=photo_carousel from the results and read the images in media.

Search TikTok by Keyword

Set SOCQ_API_KEY and submit a search capped at 20 records:

curl -X POST "https://api.socq.ai/v1/tiktok/top-search" \
  -H "Authorization: Bearer $SOCQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query":"coffee","sort_by":"relevance","results_limit":20}'

Save data.task_id as TASK_ID and query that task:

curl "https://api.socq.ai/v1/tasks/$TASK_ID?limit=100" \
  -H "Authorization: Bearer $SOCQ_API_KEY"

Wait between checks while the status is queued, running or retrying. On succeeded, read data.results.items; on failed, inspect data.error_message. If the result has has_more=true, follow next_cursor to read the remaining saved pages.

A task-result cursor reads saved records. The submitted results_limit sets the collection cap. After a client timeout, resume querying the existing task ID.

Set Sorting, Publication Filters and Region

ParameterAccepted values or rangeMeaning
queryRequired nonempty keyword or phraseSubject to search for
sort_byrelevance, date, likesRequested result ordering; relevance is the default
published_withinday, week, month, three_months, six_monthsOptional publication-time filter
regionTwo-letter code, such as USContent availability for the search
results_limitIntegers from 1 to 2000; default 100Cap across the returned content formats

day selects yesterday, week this week, and month this month. These three options use calendar periods. three_months and six_months select the last three and six months respectively.

region changes which content is accessible for the search. Save region=US as a request condition; verify creator location using separate geographic evidence.

For example, if 20 results include eight photo carousels, format filtering produces eight photo posts. results_limit counts both formats together, and the photo count depends on their distribution in that capture.

The following video and five-image carousel examples show how to read each result format:

Observed fieldVideo recordPhoto carousel record
id76785360685509706387685189869970246926
typevideophoto_carousel
author.usernamepatrickmcgee62coffeewithcandace
duration_seconds5.247null
Media entriesOne videoFive images

Standard records store captions in text, media in media, sound information in audio and engagement counts in metrics. Process subsequent queries using the records returned by their own tasks.

Read carousel images in their returned media order. A null duration_seconds means no duration was provided; a null metric means no measurement was provided. Preserve returned zeros and keep play counts and view counts in their respective fields.

Save this standard-library helper as socq_collect.py:

import json
import os
import time
from urllib.parse import urlencode
from urllib.request import Request, urlopen

BASE = "https://api.socq.ai/v1"
PENDING = {"queued", "running", "retrying"}

def api(method, path, payload=None):
    body = json.dumps(payload).encode("utf-8") if payload is not None else None
    request = Request(
        BASE + path, data=body, method=method,
        headers={
            "Authorization": "Bearer " + os.environ["SOCQ_API_KEY"],
            "Content-Type": "application/json",
        },
    )
    with urlopen(request, timeout=60) as response:
        result = json.load(response)
    if result.get("code") != 200:
        raise RuntimeError(result)
    return result["data"]

def collect(endpoint, payload):
    task_id = api("POST", "/" + endpoint, payload)["task_id"]
    print("Task:", task_id, flush=True)
    path = "/tasks/" + task_id
    deadline = time.monotonic() + 600
    data = api("GET", path + "?limit=100")
    while data["status"] in PENDING:
        if time.monotonic() >= deadline:
            raise TimeoutError("Resume GET " + path + "; do not resubmit automatically")
        time.sleep(2)
        data = api("GET", path + "?limit=100")
    if data["status"] != "succeeded":
        raise RuntimeError(data.get("error_message") or data["status"])

    items, seen_cursors = [], set()
    while True:
        if time.monotonic() >= deadline:
            raise TimeoutError("Resume pagination for " + task_id)
        page = data["results"]
        items.extend(page["items"])
        if not page["has_more"]:
            return task_id, items
        cursor = page.get("next_cursor")
        if not cursor or cursor in seen_cursors:
            raise RuntimeError("Missing or repeated result cursor")
        seen_cursors.add(cursor)
        data = api("GET", path + "?" + urlencode({"limit": 100, "cursor": cursor}))
        if data["status"] != "succeeded":
            raise RuntimeError("Task is not ready for result pagination")

Save the following as export_search.py in the same directory:

import csv
import json
from socq_collect import collect

payload = {"query": "coffee", "sort_by": "relevance", "results_limit": 20}
task_id, records = collect("tiktok/top-search", payload)
with open("tiktok-search.json", "w", encoding="utf-8") as f:
    json.dump({"task_id": task_id, "input": payload, "items": records},
              f, ensure_ascii=False, indent=2)

def csv_cell(value):
    if value is None:
        return ""
    if isinstance(value, str) and value.lstrip().startswith(("=", "+", "-", "@")):
        return "'" + value
    return value

def write_csv(path, fields, rows):
    with open(path, "w", encoding="utf-8-sig", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=fields)
        writer.writeheader()
        writer.writerows({k: csv_cell(v) for k, v in row.items()} for row in rows)

posts, images, seen_ids = [], [], set()
for item in records:
    post_id = item.get("id")
    if post_id is not None:
        if str(post_id) in seen_ids:
            continue
        seen_ids.add(str(post_id))
    metrics = item.get("metrics") or {}
    posts.append({"post_id": post_id, "type": item.get("type"),
                  "text": item.get("text"), "url": item.get("url"),
                  "username": (item.get("author") or {}).get("username"),
                  "published_at": item.get("published_at"),
                  "likes_count": metrics.get("likes_count"),
                  "views_count": metrics.get("views_count"),
                  "collected_at": item.get("collected_at")})
    if item.get("type") == "photo_carousel":
        for position, media in enumerate(item.get("media") or [], start=1):
            if media.get("type") == "image":
                images.append({"post_id": post_id, "media_position": position,
                               "image_url": media.get("url"),
                               "width": media.get("width"), "height": media.get("height")})

write_csv("tiktok-search.csv", ["post_id", "type", "text", "url", "username",
          "published_at", "likes_count", "views_count", "collected_at"], posts)
write_csv("tiktok-carousel-images.csv", ["post_id", "media_position", "image_url",
          "width", "height"], images)
python3 export_search.py

JSON preserves all collected records. The post CSV deduplicates posts by ID, while the image CSV saves post IDs and media positions for rebuilding carousel order. Records without IDs are retained separately; confirm their source posts before joining them to other datasets.

Keep both post URLs and media URLs to open the source post and access its media. Preserve empty values for missing image addresses. CSV escapes formula-like public text; import post IDs as text to retain every digit.

Turn the Collected Posts into a Topic Review

For a coffee-recipe review, classify the collected posts as image cards or video demonstrations. Read both captions and media when assigning topics. Extracting the full text shown inside images requires a separate text-recognition step.

Keep the query, filters and capture time with each comparison. Label a local likes sort as "likes ranking within this sample," and report the sample size and collection scope alongside it.

For audio-led discovery, see the TikTok music chart tutorial. For profile, known-video and comment workflows, use the TikTok scraping guide.

Build One Research Dataset for Videos and Images

SocQ Top Search uses one request workflow for videos and photo carousels, with standard fields to identify each format. The export code creates both a post table and an ordered image table, giving your topic library or review interface the source links and slide positions it needs.

Open Top Search and try your keyword.

FAQ

Can the TikTok Search API return photo carousels?

Top Search returns videos and photo carousels, distinguished by type, with media in media. The separate TikTok Search endpoint is for video search.

Can I search only TikTok photos?

Collect the results, then select type=photo_carousel. Photo filtering happens in your application; the collection cap counts both formats.

Does Top Search return top search keywords or search volumes?

Top Search takes your keyword and returns post records. Keyword search volumes and trending-query lists are separate data types and are not included in this response.

Does region identify where the creator lives?

region adjusts content availability for the search. Verify creator residence or post location separately.

Can I get every post that matches a keyword?

The endpoint returns the posts selected by that search, up to results_limit. Reading every result page retrieves the task's complete saved result set; its topic coverage is defined by those records.

Why does a photo post have no duration or play count?

Read photo carousels as image entries. Preserve null for missing duration or play measurements, and preserve 0 when the source returns zero.

Top Search retrieves existing public content. Publishing carousels uses a separate posting workflow. See the Top Search API page for this endpoint's inputs, fields and billing.

TIKTOK API

Test the workflow with a public TikTok URL

Submit public inputs and receive normalized records with traceable source context.

Explore TikTok APIs