jsonscraper

How to Find Early Signals of TikTok Trends: Automated Search Monitoring

Capture recurring search-result snapshots, compare video metrics, and turn changes into verifiable signals for your content team.

Editorial Policy Report an error

A content team notices a new TikTok topic when competitors are already talking about it. The reason is often simple: searches are checked manually and irregularly, while discovered links sit in a chat without a shared spreadsheet, collection date, or comparable metrics. To spot changes earlier, turn search into a repeatable process: record queries, regularly save the videos returned, and compare only the results actually observed.

Article: How to Find Early Signals of TikTok Trends: Automated Search Monitoring
Summary: Manual TikTok searches are poorly suited to regular analysis: results change quickly, and individual videos can easily be mistaken for trends. Learn how to build daily keyword monitoring with the TikTok Scraper API from jsonscraper, preserve raw responses, normalize data, and identify topics for further review.
Image role: cover — the central idea
Section: 
Visual subject: A phy
© jsonscraper · AI-generated illustration

Below is a Python-based monitoring workflow using the jsonscraper TikTok Scraper API. It can suit, for example, an agency tracking several topic-related queries for its publishing calendar, or a brand looking to see which public videos on a subject are receiving notable views and reactions. The API returns TikTok search results, including video descriptions, creators, publication dates, links, and available counters. The script archives each response and creates a CSV snapshot for analysis.

The key principle is to track changes in your own observation log, rather than an abstract “trend”: which videos appeared in the sample, which previously known videos changed their public counters, and which phrases recur in descriptions. This approach gives the content team a verifiable queue of topics for manual review and preserves the provenance of every finding.

Why manual searching makes for weak monitoring

Search results are a changing sample, not a stable catalog of posts. If an employee finds ten videos for a term today and runs the search again next week, comparing the results is difficult: old links may have been lost, the result set may be different, and counters will have accumulated new values. Without saved snapshots, you cannot reconstruct exactly what the team saw on a particular day.

Even a simple daily collection process solves part of this problem. Each run saves the observation date, search term, video ID, creator, description, link, and available metrics. On the next run, records can be matched by video ID and differences between counter values calculated, if both versions contain the relevant fields.

Treat these values as public metrics for videos seen in the API response—not as TikTok’s total reach or a definitive popularity ranking. Search results can change, individual fields may be missing, and metrics depend on when they are collected. The pipeline’s goal is therefore to create a reproducible working sample and flag candidates for review, not to declare a topic a universal trend based on a single number.

Solution outline: search, archive, compare

The pipeline has five parts: keyword configuration, an API request, an unmodified JSON archive, a normalized record layer, and a change report. This separation lets you check each step independently. If the response schema changes or some fields are missing, the original JSON remains available for reprocessing.

  1. Choose your queries. Use specific phrases related to your product, industry, or audience needs. For example, a kitchen appliance brand might track “meal prep,” “air fryer recipes,” and the name of a specific product category. Keep the query list in a configuration file rather than hard-coding it into the processing logic.
  2. Set collection rules. Choose a schedule and a small result set for the pilot. Record the date, region, and search parameters. For comparisons over time, repeating the settings matters more than trying to collect the broadest possible response in each run.
  3. Store the raw response. Save the JSON along with the run time and search term. The archive lets you recover the original record and fix normalization without making another API call.
  4. Normalize confirmed fields. Extract only fields present in the response: ID, caption, publication time, creator, link, and available statistics. Leave missing values blank; do not replace them with zero.
  5. Compare snapshots. Match videos by ID and store each observation separately. You can then identify posts that are new to the archive and calculate differences between observed metric values.

For the initial test, choose two or three queries and a small number of results. Check how well descriptions and creators match your needs, which fields are actually returned, and how consistent the result set is under the same conditions. Only then should you expand the list of terms and schedule the runs.

What you can request with the TikTok Scraper API

In the official jsonscraper documentation, the GET /searchVideo route is intended for searching videos by keyword. The required parameter is keyword. Documented optional parameters include count, cursor, date_posted, sort_by, region, and cache_timeout. For date_posted, the documentation describes values such as this-week and this-month; for sort_by, it lists relevance, most-liked, and date-posted. Exact parameter names and purposes are provided in the TikTok API endpoint reference.

The service’s base address is https://tiktok.evelode.com; the key is passed as the license_key query parameter. In the example below, the key is stored in the JSONSCRAPER_TIKTOK_LICENSE_KEY environment variable. This keeps the secret out of the source code and execution logs.

Parse the response with its nested structure in mind. First check the outer status, then access the tiktok object. Search results may contain videos in either of two list formats: directly in tiktok.aweme_list, or in aweme_info objects inside elements of tiktok.search_item_list. In a search response, aweme_list may be empty even when videos appear in search_item_list. The script below supports both formats.

The documentation and a verified sample response show fields such as aweme_id, desc, create_time, share_url, creator details, and a statistics object. Statistics may include view, like, comment, and share counters. Check the specific set and meaning of fields in each response: the code leaves missing fields blank. An example route and its documented parameters are available in the TikTok Scraper API description.

A working example in Python

This example is designed for Python 3.8 and later and uses the requests package. Install it with python -m pip install requests. Save the code in a file named collect_tiktok.py, set the key in your environment, and run the script with a search term. The script creates a data directory, saves the raw JSON, and appends normalized observations to a CSV.

import csv
import json
import os
import sys
from datetime import datetime, timezone
from pathlib import Path
from urllib.parse import urlparse

import requests

BASE_URL = "https://tiktok.evelode.com"
ARCHIVE = Path("data/raw")
OUT_CSV = Path("data/observations.csv")


def get_videos(tiktok):
    """Collect videos from confirmed searchVideo response formats."""
    videos = []

    aweme_list = tiktok.get("aweme_list") or []
    if isinstance(aweme_list, list):
        videos.extend(item for item in aweme_list if isinstance(item, dict))

    search_items = tiktok.get("search_item_list") or []
    if isinstance(search_items, list):
        for item in search_items:
            if not isinstance(item, dict):
                continue
            aweme_info = item.get("aweme_info")
            if isinstance(aweme_info, dict):
                videos.append(aweme_info)

    # Remove duplicates while preserving order and records without an ID.
    result = []
    seen = set()
    for video in videos:
        video_id = video.get("aweme_id")
        if video_id and video_id in seen:
            continue
        if video_id:
            seen.add(video_id)
        result.append(video)
    return result


def fetch(keyword, count=20, region="US"):
    license_key = os.environ.get("JSONSCRAPER_TIKTOK_LICENSE_KEY")
    if not license_key:
        raise RuntimeError("Set JSONSCRAPER_TIKTOK_LICENSE_KEY in the environment")

    params = {
        "license_key": license_key,
        "keyword": keyword,
        "count": count,
        "region": region,
        "sort_by": "relevance",
    }
    response = requests.get(
        f"{BASE_URL}/searchVideo", params=params, timeout=60
    )
    response.raise_for_status()
    payload = response.json()

    if payload.get("status") != "ok":
        raise RuntimeError("TikTok API returned a non-ok status")

    tiktok = payload.get("tiktok")
    if not isinstance(tiktok, dict):
        raise RuntimeError("Response does not contain a TikTok result object")
    return payload, tiktok


def write_rows(keyword, videos, collected_at):
    OUT_CSV.parent.mkdir(parents=True, exist_ok=True)
    fields = [
        "collected_at", "keyword", "aweme_id", "create_time",
        "author_id", "author_name", "author_username", "description",
        "share_url", "play_count", "digg_count", "comment_count",
        "share_count", "collect_count",
    ]
    write_header = not OUT_CSV.exists()

    with OUT_CSV.open("a", newline="", encoding="utf-8") as file:
        writer = csv.DictWriter(file, fieldnames=fields)
        if write_header:
            writer.writeheader()

        for video in videos:
            author = video.get("author") or {}
            stats = video.get("statistics") or {}
            writer.writerow({
                "collected_at": collected_at,
                "keyword": keyword,
                "aweme_id": video.get("aweme_id"),
                "create_time": video.get("create_time"),
                "author_id": author.get("uid"),
                "author_name": author.get("nickname"),
                "author_username": author.get("unique_id"),
                "description": video.get("desc"),
                "share_url": video.get("share_url"),
                "play_count": stats.get("play_count"),
                "digg_count": stats.get("digg_count"),
                "comment_count": stats.get("comment_count"),
                "share_count": stats.get("share_count"),
                "collect_count": stats.get("collect_count"),
            })


def main():
    if len(sys.argv) 

Pass the key through the environment. In a Bash shell, the command for the current session looks like this:

export JSONSCRAPER_TIKTOK_LICENSE_KEY="your_key"
python collect_tiktok.py "meal prep"

In Windows PowerShell, you can set the variable for the current process with $env:JSONSCRAPER_TIKTOK_LICENSE_KEY="your_key" and then run the same Python file. Do not add the key to a repository, CSV, response archive, or error messages. Because the API accepts the key as a query parameter, be aware that the full request URL may end up in HTTP client and infrastructure logs; configure logging to exclude secrets.

How to read the code and verify the results

The fetch function passes documented parameters and checks the HTTP status, outer status, and presence of the tiktok object. It does not treat every syntactically valid response body as a successful result: if the format is unexpected, execution stops with a clear error. This makes it easier to distinguish an empty result set from an access problem or a changed response structure.

The get_videos function combines items from the direct aweme_list and records nested in search_item_list[].aweme_info. It then removes duplicates by aweme_id, because a video may appear in both collections. If an ID is missing, the record is retained; this lets you examine the original result without inserting an invented value.

Normalization uses safe access to nested objects. Creator or statistics fields may be missing, so the code substitutes an empty object before reading them. The corresponding CSV cells remain blank. This distinction matters: a blank cell means the value was not present in the observation, while zero is a numeric value actually returned by the API.

The archive receives a separate JSON file for each request. Its name includes the UTC time and a sanitized version of the search term. The CSV contains flat records for analysis, while the raw JSON remains the reference for examining new fields or reprocessing. This dual format is useful both for a local prototype and for a later migration to a database or object storage.

To verify the first run, open the JSON and confirm that status is ok, that a tiktok object is present, and that one or both supported collections contain items. Then compare several CSV values with the source object. In particular, check that counters have not been turned into malformed strings, publication dates are preserved in their original form, and links belong to the same videos as the IDs.

If a valid response contains no videos, record it as an empty result for that run, not as a code failure. If the outer status or HTTP response indicates an error, do not add it to the analytical observations: first resolve the cause and rerun. For a production process, also record the HTTP status code, search term, time, and a short error message, excluding the key and full URL containing the secret.

Pagination and repeatable collection

Search supports a cursor parameter for scrolling through results. To fetch the next page, take the cursor from the previous response and pass it through unchanged. The cursor is an opaque API value: the application should store and return it as is, not calculate it from the number of rows or treat it as a page number.

For initial monitoring, you can limit collection to one request per keyword and use the same count. This is easier to interpret: the team knows that each run saves a limited snapshot of the results. If you add pagination, save every page and cursor, and set a page limit for each run. This limit protects the task from an unbounded loop if an unexpected response occurs.

The date_posted parameter lets you limit the search to one of the periods listed in the documentation; sort_by lets you choose sorting by relevance, publication date, or likes. When analyzing changes, record these settings alongside each run. Comparing queries with different periods or sort orders may reflect changed search conditions rather than a change in the topic itself.

The cache_timeout parameter controls response caching. The documentation describes a default cache window of 3,600 seconds and a value of 0 to disable caching. Choose settings deliberately for scheduled monitoring and save them in the configuration. If a series of requests runs more often than once an hour and you need to distinguish responses within that window, check caching behavior separately before interpreting repeated results as a lack of change.

Comparing daily observations

The CSV already provides the basis for a simple report. Group rows by search term and aweme_id, sort by collected_at, and compare only pairs of observations where both metric values exist. For example, calculate the difference in views as the latest observed value minus the previous one. Keep both original data points: the absolute difference and the time between observations are needed to interpret the result correctly.

Do not call this difference a view rate without specifying a time interval. If one run took place in the morning and the next several days later, the value represents accumulated change over that period. To compare pace, you can divide the difference by the actual time between observations, but the result is still an average rate between two snapshots, not continuous telemetry.

Track two types of signals separately. The first is new IDs appearing in the results for the current query. The second is a change in the statistics of previously observed videos. A new video may be worth reviewing regardless of its current view count, while growth in an older video can help identify a post that is still gaining reactions. These signals answer different questions and are useful in different editorial planning scenarios.

Add simple data-quality checks: the proportion of rows with an ID, the proportion with a description, whether a collection date is present, the number of unique videos per query, and the number of missing statistics. These indicators help you detect when the pipeline stops receiving the expected structure before the team draws conclusions from an incomplete file. They also show which search phrases produce a sample that is useful for your industry.

For the first report, a table with these columns is enough: term, ID, publication date, creator, description, link, current views, views in the previous snapshot, difference, and time between snapshots. Add a “new to archive” flag and a field for editorial assessment. A team member can mark brand relevance, format suitability, and potential risk of copying someone else’s idea—assessments the API itself does not make.

How not to confuse video popularity with a topic’s usefulness

Views, likes, comments, and shares help describe public reactions to a specific video. For content planning, the text itself also matters: the wording of a question, the promise at the start, a recurring explanatory format, or the type of demonstration. So give the editor the link and description along with the metrics; a single number rarely explains why a post worked.

When comparing several videos, you can calculate an engagement-to-view ratio if both counters are available. For example, the sum of likes, comments, and shares divided by views gives a simple measure of the observed share of reactions. Record the formula and do not mix videos with missing values; otherwise, the result will not be comparable. This ratio describes only the selected public counters and videos.

Do not add up metrics across multiple snapshots as if they were independent events. If the same video appears in five daily responses, its views in those rows are successive states of one counter, not five different audiences. To calculate a total across unique posts, use one consistent observation point per video—for example, the latest snapshot in the reporting period—and document the selection rule.

Another useful view is recurring words in descriptions. Simple text analysis can group posts using predefined dictionaries such as “recipe,” “review,” “before/after,” “mistake,” and “tip.” A classifier or language model can suggest categories and short summaries, but the table should retain the original description and URL so the editor can verify the interpretation against the video itself.

Automating on a schedule

Once you have checked a manual run, move collection to a scheduler: cron on your own server, GitHub Actions, or an n8n/Make workflow. The integration should run the same tested script, pass the key from a secrets store, archive the JSON, and send a notification only after successful completion. The specific scheduler implementation depends on your infrastructure; the API call and processing format stay the same.

Example cron schedule for a daily run at 08:15 machine time:

15 8 * * * cd /srv/tiktok-monitor && /usr/bin/python3 collect_tiktok.py "meal prep" >> logs/collector.log 2>&1

Before using this line, configure the environment variable in the service or shell under which cron runs, and set the host’s correct time zone. For multiple keywords, it is better to keep the list in a file and pass each query to the script in a separate run. That way, an error on one query does not have to cancel the whole set, and the archives are easier to compare.

As the number of keywords grows, move the configuration to JSON or YAML and add a run log with the status, number of videos received, and archive path. For reliability, provide a limited number of retries for temporary network errors, a timeout, and separate handling for HTTP errors. Never retry requests indefinitely: the task should finish with a visible status so the next run does not mask the problem.

If results need to go to Google Sheets, a database, or an internal dashboard, add that after reliable archiving is in place. First save the raw response, then upload the normalized rows; if the upload fails, retry it from the archive without necessarily collecting the data again. The video ID and collection time help make inserts repeatable and distinguish new snapshots from old ones.

Adding AI: useful for sorting, not replacing the source

Once the archive contains many descriptions, a model can help group videos by topic, identify recurring phrases, and prepare short explanations for the editor. Send the model a limited set of fields: search term, description, publication date, and public counters. Ask it to return structured categories and a brief rationale, not confident claims about causes of popularity that are not present in the data.

Store the model’s output in separate columns, such as ai_topic, summary, and review_status. Do not overwrite the original description or API values. Reprocessing should be possible on saved records if the instructions or model change; for this, it is useful to store the prompt version and classification date.

A practical task for a model is to suggest clusters for the editor: “quick recipes,” “appliance comparisons,” or “beginner mistakes.” An analyst can then check several examples in each cluster using the links and adjust the vocabulary. This human-in-the-loop process turns AI into a way to navigate the collection while keeping verifiable original observations available.

Do not ask a model to declare causality between a format and reach on the basis of a small search sample. Such a conclusion requires a predefined method, comparable posts, and additional data. In day-to-day editorial work, it is enough to rank candidates for review, suggest hypotheses about recurring themes, and provide a list of links for manual examination.

Sample quality and limits on conclusions

The pipeline saves responses obtained with the specified queries and parameters. It helps compare these observations, but search coverage is limited by the query, collection time, settings, and service response. So phrase findings precisely: “among the results returned for query X in this week’s snapshots, topic Y appeared more often,” not “TikTok as a whole is discussing Y right now.”

Compare only series with the same settings: one region, identical sorting parameters, publication period, and requested result count. If you change a query or filter, mark it as a new series. For seasonal or campaign analysis, it is useful to save a configuration version; otherwise, a change in inputs may look like a change in content.

Public metrics can update between snapshots, and videos may differ in age: a recently published video and an older video are at different stages of accumulating reactions. Consider publication date and observation interval when comparing performance. Compare posts of similar age or analyze the same ID’s changes across successive snapshots.

If a project involves competitors or creators, limit collection to the task and the minimum data needed. Do not collect sensitive information or use public metrics to judge a creator as a person. A marketing team’s report usually needs only a link, description, profile name, publication time, and aggregated metrics. Before automating, check applicable platform terms, your organization’s requirements, and data-retention rules.

Practical checklist before launch

  • Define the business question: which topics, formats, or posts do you want to spot?
  • Start with a few stable search phrases and record their exact wording.
  • Check the /searchVideo route, required keyword, and other parameters against the documentation.
  • Store the key in an environment variable and keep it out of output, logs, and the repository.
  • Check the response’s outer status and the presence of the tiktok object.
  • Handle both aweme_list and search_item_list[].aweme_info.
  • Save the raw JSON before normalization.
  • Leave missing fields blank; do not replace them with zeros.
  • Match posts by aweme_id and pass the cursor through unchanged.
  • Record the collection date and search parameters for every snapshot.
  • Manually check several videos before drawing conclusions or passing results to a model.

What you get

Once configured, the team has a repeatable process: a list of keyword queries runs on a schedule, each response is saved as raw JSON, and normalized observations are added to a CSV. An analyst can identify videos new to the archive, return to their links and descriptions, compare available public counters across snapshots, and build topic groups.

For an editor, the result is not an automatic verdict on the “biggest trend,” but a short list of verifiable candidates: new posts, videos with notable metric changes, and recurring thematic phrases. This shortens the path from manual searching to discussing a topic, while preserving a verifiable basis for deciding what to add to the content plan.

You can start with one query, a daily local run, and a CSV file. Once you have confirmed that the sample meets your needs, add a schedule, database, or description classification. You can check documented parameters and route purposes in the TikTok API documentation, and find access and product information on the jsonscraper TikTok Scraper API page.

People

No people listed for this article yet.

Keep readingTikTok Hashtag Monitoring in Python: A Working API Request
Read the next article

Turn what you read into a working integration

Explore jsonscraper's social-data APIs, test requests and build your next workflow.

Explore APIs