After an app or new feature launches, feedback quickly spreads across short videos. A marketer manually finds a few clips and shares the links in chat, while an analyst later cannot tell which posts have already been counted or how their view counts changed. A practical solution is to regularly collect search results for several consistent queries, save the original responses, and build a report from verified fields.

This guide sets up collection for a specific use case: a team has released a new feature and wants to track public TikTok videos weekly whose descriptions mention the product name, a key feature, or a typical user problem. This monitors a search sample: the API returns results for a query and its parameters, not a guaranteed list of every post about the launch.
First, decide what signal the team needs
A high view count alone does little to explain what to do next. The team will find it more useful to know which questions recur, which use cases people demonstrate, and which videos receive notable public engagement. So start by defining a few search phrases and deciding which fields to include in the report.
For example, for the launch of a social media scheduling tool, you could try the queries “product name,” “content planner,” and “how to schedule TikTok.” These phrases should reflect different ways people might describe the same topic. Record them alongside the monitoring start date and region so that later exports can be compared using consistent settings.
A basic table might contain collection time, search phrase, video ID, link, description, creator name, creator ID, and available view, like, and comment counts. The TikTok Scraper API documents fields for search results such as aweme_id, desc, share_url, creator information, and some statistics. Check each object for a specific field: individual metrics may be missing.
Use the documented search endpoint
To search for videos, use the GET route \/searchVideo at the base address https:\/\/tiktok.evelode.com. The documentation lists the required keyword parameter and optional count, cursor, date_posted, sort_by, region, and cache_timeout parameters. Available date filter values include this-week, and sorting options include relevance, most-liked, and date-posted. Check their purpose and names in the TikTok API endpoint reference.
Pass the license key as the license_key query parameter. In a production script, read it from the JSONSCRAPER_TIKTOK_LICENSE_KEY environment variable; do not put the secret in source code or print it in logs. This example is for Python 3.8+ and uses the requests package:
import os
import requests
BASE_URL = "https:\/\/tiktok.evelode.com"
API_KEY = os.environ["JSONSCRAPER_TIKTOK_LICENSE_KEY"]
def search_videos(keyword, cursor=None):
params = {
"license_key": API_KEY,
"keyword": keyword,
"count": 20,
"date_posted": "this-week",
"sort_by": "date-posted",
"region": "US",
}
if cursor is not None:
params["cursor"] = cursor
response = requests.get(
f"{BASE_URL}\/searchVideo",
params=params,
timeout=30,
)
response.raise_for_status()
payload = response.json()
if payload.get("status") != "ok":
raise RuntimeError("TikTok API returned a status other than ok")
return payload["tiktok"]
result = search_videos("content planning app")
print("Objects found:", len(result.get("aweme_list", [])))
The script checks for HTTP errors and the response's top-level status. A successful HTTP response alone does not guarantee that the search found videos: the list may be empty. For the first run, it is useful to save the complete response in secure storage so you can compare actual objects with the table of normalized fields.
Handle both search response formats
Search results have an important structural detail. Videos may be located directly in tiktok.aweme_list, or they may arrive inside tiktok.search_item_list[].aweme_info. A handler that reads only the first list could miss results present in the second format.
Add a small normalizer that supports both structures and safely skips items without a nested video object:
def extract_awemes(tiktok):
items = list(tiktok.get("aweme_list") or [])
for item in tiktok.get("search_item_list") or []:
aweme = item.get("aweme_info")
if aweme:
items.append(aweme)
return items
def normalize(aweme, keyword, collected_at):
author = aweme.get("author") or {}
stats = aweme.get("statistics") or {}
return {
"collected_at": collected_at,
"keyword": keyword,
"video_id": aweme.get("aweme_id"),
"posted_at": aweme.get("create_time"),
"description": aweme.get("desc"),
"share_url": aweme.get("share_url"),
"author_id": author.get("uid"),
"author_name": author.get("nickname"),
"views": stats.get("play_count"),
"likes": stats.get("digg_count"),
"comments": stats.get("comment_count"),
"shares": stats.get("share_count"),
}
Leave missing values as None. Do not replace them with zero: zero means a value was measured, while None preserves the fact that the field was not returned. This distinction affects averages, proportions, and any conclusions the team draws.
Keep a history, not just the latest snapshot
To see changes over time, store separate observation records. A video ID works for deduplicating posts, but not for deleting history: the same video appearing in the next collection gives you a new observation point. For example, a unique key for an observations table could consist of video_id and collected_at, with the link and description stored in the record for easy review.
A basic SQLite schema is useful for a prototype:
import sqlite3
conn = sqlite3.connect("tiktok_observations.sqlite3")
conn.execute("""
CREATE TABLE IF NOT EXISTS observations (
video_id TEXT NOT NULL,
collected_at TEXT NOT NULL,
keyword TEXT NOT NULL,
posted_at INTEGER,
description TEXT,
share_url TEXT,
author_id TEXT,
author_name TEXT,
views INTEGER,
likes INTEGER,
comments INTEGER,
shares INTEGER,
PRIMARY KEY (video_id, collected_at, keyword)
)
""")
conn.commit()
In practice, normalize collection times to UTC, save the original JSON separately, and add a schema version column. The original response helps you verify the transformation if the structure of new objects differs from what you expect. For posts found through multiple queries, store the matching search phrases in a separate linked table or combine them when generating the report.
Pagination: continue only with the cursor from the response
The cursor parameter is intended to continue a search. Take its value from the previous response and pass it back unchanged. Stop when has_more no longer indicates that more results are available or when you reach a set limit. Treat the cursor as opaque: do not calculate it yourself or replace it with a page counter.
def collect_pages(keyword, max_pages=3):
cursor = None
collected = []
for _ in range(max_pages):
page = search_videos(keyword, cursor)
collected.extend(extract_awemes(page))
if not page.get("has_more"):
break
cursor = page.get("cursor")
if cursor is None:
break
return collected
Limiting the number of pages makes the recurring job's request volume predictable. Log the number of pages and the value of has_more: this provides context for the sample in the report. Even with pagination, the results describe the API responses received and the collection limit you set; they are not an estimate of every post on the platform.
Create a repeatable report
Schedule collection weekly, or more often if the team needs more frequent signals. For each run, record the query list, parameters, time, number of objects received, and number of unique IDs. Separately count posts first seen in that run and posts that have appeared before.
Four simple views are useful in a report:
- New videos: Links, descriptions, posting dates, and the search phrase that found each video.
- Recurring themes: Group descriptions into manually defined categories, such as “setup issue,” “feature request,” and “use-case walkthrough.”
- Public engagement: Available views, likes, comments, and reposts, shown alongside the observation time.
- Signals to review: New wording, frequent questions, or videos that a team member should examine.
Do not call the difference between two snapshots “new likes” without checking the meaning and freshness of the values in the response. A more accurate description is “metric value in the latest response received” and “difference between saved snapshots.” That way, the team can see exactly what was calculated and open the original post before making a decision.
Add AI for classification, not as a replacement for collection
After normalization, you can send video descriptions to a model to classify them into predefined categories. Send only the text fields needed and ask for a structured result: category, brief rationale, confidence level, and the description excerpt supporting the label. Keep the original post alongside the label so an analyst can review questionable cases.
The workflow stays simple: a scheduler starts collection; Python validates the response and saves the JSON; a separate task normalizes new records; a classifier processes only new descriptions; and a report is generated from the database and sent to a team-selected channel. The TikTok Scraper API itself provides search data. Classification and report delivery are your integration logic, which you can implement in Python, n8n, or Make.
To reduce noise, define a category vocabulary before sending text to the model, and periodically review a manually labeled sample. For short or ambiguous descriptions, use a “not enough context” status rather than forcing a category choice. AI labels help sort the review queue, but conclusions about user problems should be confirmed by reading posts and comparing multiple observations.
Errors, retries, and keeping the key secure
A network request may time out, fail temporarily, or return a response that cannot be parsed as JSON. Separate processing into stages: request, HTTP status check, JSON parsing, top-level status check, normalization, and storage. For temporary failures, use a limited number of retries with increasing delays; log persistent errors for later investigation rather than marking the run as successful.
Store the key in a runtime secret manager or environment variable. Because the API accepts license_key in the query string, avoid logging the complete URL and query parameters, which would expose the secret. For diagnostics, log the route, response code, duration, search phrase, and job ID, while removing the key from logs.
Set the schedule and sample size according to your needs and the platform's terms of use. Collection of public data should be limited to what is actually needed for analysis; the team's internal policies should describe how descriptions, links, and creator IDs are stored. API responses and metrics may be incomplete or change between observations, so the report should record the collection time and provenance of every row.
The result: from manually shared links to a verifiable history
Once configured, the team gets a regularly updated list of discovered videos, original responses for auditing, a table of available public metrics, and an overview of recurring themes. This helps the team spot questions about a new feature sooner, find examples of user workflows, and choose posts for manual analysis. Comparing snapshots shows how the saved values for previously discovered videos change, while the query log explains how the sample was formed.
Start with one query and a low page limit, check the actual response structure, then add more phrases and a schedule. Before moving the prototype into production, define deduplication, storage, and error-handling rules. Current routes and parameters are available in the official API documentation; an overview of features and a way to start testing are on the TikTok Scraper API page.