Skip to main content
New

The YouTube API is live.

Try it
Python tutorial

How to track your competitors on TikTok using Python

By the Tapline teamLast updated 8 min read

By tracking TikTok competitors, you can identify the topics, formats, and hooks that get attention in your niche and use that evidence to decide what to create next. To build a TikTok competitor tracker you can rerun, you need a steady sample of recent videos and a ranking that is easy to justify. This walkthrough uses Tapline's Python client to pull five videos per account, compute a public engagement score, and export the output as a timestamped CSV.

The example relies on the public duolingo and babbel accounts. When you run the script, replace those handles with the accounts you want to compare.

Because the official client sends the Tapline request for you, this workflow requires no TikTok cookies, browser automation, or proxy setup.

Sample output

Each video is ranked by the tracker using likes + comments * 5 + shares * 10. Below are the first five rows of the captured CSV.

RankAccountPostPostedViewsScore
1@duolingodressed up like jinshi but people keep mistaking me for ah-duo…2026-10-231,300,000890,230
2@duolingoleave everything in the past except ur streak2026-10-26997,900355,805
3@duolingomake my own group, call it K/DUO2026-10-26411,600333,720
4@duolingoima start a streak, im a streakstarter2026-10-27313,900215,485
5@duolingocould've been us if u did ur lesson2026-10-26282,70086,335

The scoring stays intentionally simple: comments and shares signal stronger public interaction than a view, so they carry more weight. Keep the raw columns in the CSV so you can adjust the weighting later without issuing another request. The tested Python script is available for download alongside it.

Prerequisites

You need Python 3.10 or later, a Tapline account with an API key, and the exact tested client version tapline==0.2.18. The only dependency the script requires is the official Tapline package.

install
pip install "tapline==0.2.18"

Send the Tapline request

The get_profile_videos method retrieves a user's public videos. Provide a single handle or numeric user ID, then pass the returned max_cursor in a follow-up request while has_more remains true. Before keeping its five newest videos, the script orders the first page by UTC timestamp, which prevents a pinned item from pushing out a recent video.

profile_videos.py
import os
from tapline import SyncTaplineClient
with SyncTaplineClient(api_key=os.environ["TAPLINE_API_KEY"]) as tapline:
page = tapline.tiktok.get_profile_videos(
handle="duolingo",
sort_by="latest",
region="US",
)
posts = page.videos

Each video carries the typed statistics object the ranking relies on, plus the video URL, UTC timestamp, description caption, and a stable video ID. Any count TikTok leaves out arrives as None, so the script reads it as zero.

Assemble the script

Store this as track_tiktok_competitors.py. For each account it requests the same five-video window, orders by UTC timestamp, catches a Tapline error per account so one unavailable profile does not wipe out the rest, and writes rows using a single consistent schema.

track_tiktok_competitors.py
"""Rank recent public TikTok posts from several accounts."""
from __future__ import annotations
import argparse
import csv
import os
import sys
from dataclasses import dataclass
from datetime import datetime, timezone
from pathlib import Path
from tapline import SyncTaplineClient, TaplineError
from tapline.tiktok import TikTokStatistics, TikTokVideo
POSTS_PER_ACCOUNT = 5
DEFAULT_ACCOUNTS = ("duolingo", "babbel")
OUTPUT_PREFIX = "tiktok-competitors"
@dataclass(frozen=True)
class RankedPost:
account: str
post_id: str
posted_at: str
caption: str
url: str
views: int
likes: int
comments: int
shares: int
engagement_score: int
def read_statistics(post: TikTokVideo) -> TikTokStatistics:
"""Counts TikTok leaves out read as zero, so one sparse post can't break the ranking."""
return post.statistics or TikTokStatistics()
def engagement_score(stats: TikTokStatistics) -> int:
"""Weight comments and shares more heavily than passive views or likes."""
return (stats.digg_count or 0) + (stats.comment_count or 0) * 5 + (stats.share_count or 0) * 10
def collect_account(
tapline: SyncTaplineClient, account: str, limit: int = POSTS_PER_ACCOUNT
) -> list[RankedPost]:
page = tapline.tiktok.get_profile_videos(handle=account, sort_by="latest", region="US")
recent_posts = sorted(page.videos, key=lambda post: post.create_time or 0, reverse=True)
ranked: list[RankedPost] = []
for post in recent_posts[:limit]:
stats = read_statistics(post)
ranked.append(
RankedPost(
account=account,
post_id=post.aweme_id or "",
posted_at=post.create_time_utc or "",
caption=post.description or "",
url=post.url or "",
views=stats.play_count or 0,
likes=stats.digg_count or 0,
comments=stats.comment_count or 0,
shares=stats.share_count or 0,
engagement_score=engagement_score(stats),
)
)
return ranked
def write_csv(posts: list[RankedPost], output_dir: Path) -> Path:
output_dir.mkdir(parents=True, exist_ok=True)
timestamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
output_path = output_dir / f"{OUTPUT_PREFIX}-{timestamp}.csv"
fields = [
"rank",
"account",
"post_id",
"posted_at",
"caption",
"url",
"views",
"likes",
"comments",
"shares",
"engagement_score",
]
with output_path.open("w", newline="", encoding="utf-8") as output:
writer = csv.DictWriter(output, fieldnames=fields)
writer.writeheader()
for rank, post in enumerate(
sorted(posts, key=lambda item: item.engagement_score, reverse=True), start=1
):
writer.writerow({"rank": rank, **post.__dict__})
return output_path
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("accounts", nargs="*", help="TikTok handles without the @")
parser.add_argument(
"--output-dir",
type=Path,
default=Path("."),
help="Directory for the timestamped CSV (default: current directory)",
)
return parser.parse_args()
def main() -> int:
args = parse_args()
accounts = tuple(args.accounts) or DEFAULT_ACCOUNTS
posts: list[RankedPost] = []
with SyncTaplineClient(api_key=os.environ["TAPLINE_API_KEY"]) as tapline:
for account in accounts:
try:
posts.extend(collect_account(tapline, account))
except TaplineError as exc:
print(f"Skipping @{account}: {type(exc).__name__}", file=sys.stderr)
if not posts:
raise SystemExit("No posts were returned. Check the handles and API key.")
output_path = write_csv(posts, args.output_dir)
print(f"Wrote {len(posts)} posts to {output_path}")
return 0
if __name__ == "__main__":
raise SystemExit(main())

Execute the script

Place your key in TAPLINE_API_KEY and then run the downloaded file. Optional handles override the defaults, and --output-dir sets where the timestamped CSV is saved.

terminal
pip install "tapline==0.2.18"
export TAPLINE_API_KEY="your-api-key"
python track_tiktok_competitors.py
custom accounts
python track_tiktok_competitors.py duolingo babbel --output-dir ./data

Work with the results

Start with the top-ranked URLs and sort them by topic, format, recurring character, or call to action. Then compare those groupings across accounts and pick the patterns worth examining more closely in TikTok and in your own content plan.

Keep the ranking understandable

Views, likes, comments, shares, and the computed score sit side by side in the CSV. That lets you sort by any single metric, experiment with a different weighting, or add another score without re-fetching the videos.

Practical constraints

Each profile-videos page holds up to 35 videos and consumes one credit. This script deliberately uses the first page, orders it by create_time, and keeps five rows per account. To reach older videos, follow max_cursor while has_more is true; every extra page counts as another request. Public counts of 10,000 or higher may be rounded, and private, deleted, or unavailable videos are excluded from results.

Track TikTok competitors

You now have a typed Tapline request, a full Python tracker, and a timestamped CSV ready for review or scheduling. Create a Tapline account, open the TikTok API docs, and run the example with your own list of accounts.

02try it live

TikTok live demo.

Run a live request. No account or API key needed.

Profile

Current public data

Profile

Use Run to fetch a live response from the Tapline API.

Run a request to fetch a live response.
Get started

Build With TikTok Data

Try the live demo. Sign up for 100 free credits when you are ready.

Try TikTok data on a real account.
Run live