How to Scrape TikTok User Data with Python

Published on May 29, 2026

Introduction

Python is the most popular language for web scraping and data analysis - and TikTok is one of the richest social-media datasets on the planet. In this tutorial we'll connect Python to the TikLiveAPI REST API to pull TikTok user profiles, posts, follower counts, and engagement metrics in just a few lines of code.

You'll learn how to:

  • Authenticate against the API with the X-Api-Key header
  • Fetch a user's profile by username or numeric user ID
  • Paginate through a user's posts
  • Handle errors and rate limits the production way
  • Scale to bulk operations with httpx and async I/O

Prerequisites

  • Python 3.8 or newer
  • A TikLiveAPI key - grab one on the pricing page (the entry tier is enough to follow along)
  • The requests library: pip install requests

Step 1: Get Your API Key

Register a TikLiveAPI account, pick a credit plan, and copy your API key from the profile dashboard. The key is a single string that you pass on every request via the X-Api-Key header.

Keep secrets out of source control by reading the key from an environment variable:

export TIKLIVEAPI_KEY="paste-your-key-here"

Then in Python:

import os

API_KEY = os.environ["TIKLIVEAPI_KEY"]
BASE_URL = "https://api.tikliveapi.com"
HEADERS = {"X-Api-Key": API_KEY}

Step 2: Fetch a User's Profile

The /userinfo-by-username/ endpoint returns a user's display name, bio, follower and following counts, total likes, and avatar URLs in a single call.

import requests

def get_user(username: str) -> dict:
    response = requests.get(
        f"{BASE_URL}/userinfo-by-username/",
        params={"username": username},
        headers=HEADERS,
        timeout=10,
    )
    response.raise_for_status()
    return response.json()

profile = get_user("tiktok")
print(profile["user"]["nickname"])
print(f"Followers: {profile['stats']['followerCount']:,}")
print(f"Likes: {profile['stats']['heartCount']:,}")
print(f"Videos: {profile['stats']['videoCount']:,}")

Two things worth noting:

  • response.raise_for_status() throws on 4xx and 5xx - we'll wrap this for production below.
  • The response is a standard Python dict - the user object holds profile data and stats holds the counters.

Step 3: Get a User's Recent Posts

Most analytics workflows need a user's posts, not just their profile. The /user-posts/ endpoint takes a numeric userid (not a username), so we first resolve the ID with the /userid/ endpoint:

def get_userid(username: str) -> str:
    response = requests.get(
        f"{BASE_URL}/userid/",
        params={"username": username},
        headers=HEADERS,
        timeout=10,
    )
    response.raise_for_status()
    return response.json()["id"]

def get_posts(userid: str, count: int = 30) -> list:
    response = requests.get(
        f"{BASE_URL}/user-posts/",
        params={"userid": userid, "count": count},
        headers=HEADERS,
        timeout=15,
    )
    response.raise_for_status()
    return response.json().get("videos", [])

userid = get_userid("tiktok")
videos = get_posts(userid, count=30)

for video in videos[:5]:
    print(
        f"{video['video_id']}  "
        f"views={video['play_count']:,}  "
        f"likes={video['digg_count']:,}  "
        f"comments={video['comment_count']:,}"
    )

The /user-posts/ response returns a top-level videos array. Each video carries metrics as flat play_count, digg_count (likes), comment_count, share_count, and download_count fields - plus music_info, the no-watermark play URL, and the watermarked wmplay URL.

Pagination: pulling more than 30 posts

TikLiveAPI returns a cursor field you pass back to walk older posts, and a boolean hasMore that tells you when the end is reached. Here's a generator that yields every post the API will give you:

def all_posts(userid: str, page_size: int = 30):
    cursor = "0"
    while True:
        response = requests.get(
            f"{BASE_URL}/user-posts/",
            params={"userid": userid, "count": page_size, "cursor": cursor},
            headers=HEADERS,
            timeout=15,
        )
        response.raise_for_status()
        data = response.json()
        for video in data.get("videos", []):
            yield video
        if not data.get("hasMore"):
            return
        cursor = data["cursor"]

count = sum(1 for _ in all_posts(userid))
print(f"Fetched {count} videos")

Step 4: Production-Grade Error Handling

Hitting any social-media API at scale will eventually surface timeouts, transient 5xx errors, and rate limits. A small tenacity-backed wrapper handles all three:

from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type

@retry(
    stop=stop_after_attempt(5),
    wait=wait_exponential(multiplier=1, min=1, max=30),
    retry=retry_if_exception_type((requests.Timeout, requests.ConnectionError)),
)
def safe_get(path: str, params: dict) -> dict:
    response = requests.get(
        f"{BASE_URL}{path}",
        params=params,
        headers=HEADERS,
        timeout=10,
    )
    if response.status_code == 429:
        retry_after = int(response.headers.get("Retry-After", "5"))
        raise requests.Timeout(f"Rate limited, retry in {retry_after}s")
    response.raise_for_status()
    return response.json()

Install with pip install tenacity. Exponential backoff with a hard cap on attempts is the gold standard for resilient API clients.

Step 5: Scaling Up with Async Python

If you need to fetch hundreds of users - say, a daily influencer leaderboard - synchronous requests bottlenecks on network latency. httpx with asyncio can fetch 50-100 users concurrently:

import asyncio
import httpx

async def get_user_async(client: httpx.AsyncClient, username: str) -> dict:
    response = await client.get(
        "/userinfo-by-username/",
        params={"username": username},
    )
    response.raise_for_status()
    return response.json()

async def bulk_fetch(usernames: list) -> list:
    limits = httpx.Limits(max_connections=20)
    async with httpx.AsyncClient(
        base_url=BASE_URL,
        headers=HEADERS,
        timeout=10,
        limits=limits,
    ) as client:
        return await asyncio.gather(
            *[get_user_async(client, u) for u in usernames],
            return_exceptions=True,
        )

profiles = asyncio.run(bulk_fetch(["tiktok", "khaby.lame", "charlidamelio"]))
for profile in profiles:
    if isinstance(profile, Exception):
        print(f"Error: {profile}")
    else:
        print(profile["user"]["nickname"], profile["stats"]["followerCount"])

Two production tips:

  • return_exceptions=True lets one failing user not blow up the whole batch.
  • Cap max_connections below your plan's rate limit - 20 is safe on most tiers.

Real-World Example: A Daily Follower Tracker

Let's tie everything together. The script below tracks a list of usernames, pulls today's follower count, and appends to a CSV - a primitive but real analytics pipeline you can wire to cron:

import csv
from datetime import date
from pathlib import Path

TRACKED = ["tiktok", "khaby.lame", "charlidamelio", "willsmith"]
OUTPUT = Path("follower_history.csv")

def track_today():
    rows = []
    for username in TRACKED:
        try:
            profile = safe_get("/userinfo-by-username/", {"username": username})
            stats = profile["stats"]
            rows.append({
                "date": date.today().isoformat(),
                "username": username,
                "followers": stats["followerCount"],
                "likes": stats["heartCount"],
                "video_count": stats["videoCount"],
            })
        except Exception as exc:
            print(f"skip {username}: {exc}")

    if not rows:
        return

    new_file = not OUTPUT.exists()
    with OUTPUT.open("a", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=rows[0].keys())
        if new_file:
            writer.writeheader()
        writer.writerows(rows)

if __name__ == "__main__":
    track_today()

Schedule with cron, systemd timers, or GitHub Actions and you have daily growth data for every account on your list. Plug the CSV into Pandas, Grafana, or a Postgres warehouse and you are running real analytics.

Beyond User Data: What Else Is in the API

This tutorial focused on user-level data, but TikLiveAPI exposes 37 endpoints across 10 categories. A few you will likely want next:

  • Video Download - fetch the no-watermark MP4 URL for any TikTok video.
  • Hashtag (Challenge) - pull posts under a hashtag and track its rising or falling volume.
  • Music - find every video using a sound, useful for label and trend monitoring.
  • Search - run TikTok's search programmatically across users, posts, and hashtags.

All of them follow the same pattern: GET request, X-Api-Key header, JSON response. The full reference lives in the documentation.

Frequently Asked Questions

Is scraping TikTok user data legal?

TikLiveAPI only returns data that is publicly visible on TikTok - the same information any logged-out user can see by visiting a profile. We do not bypass private accounts or login walls. That said, jurisdictions vary and you remain responsible for how you use the data: GDPR, CCPA, and TikTok's own terms of service still apply on your end.

What is the rate limit?

Rate limits are credit-based, not per-second. Each API call costs one credit and your plan determines how many credits you have per month. There is no hard per-second cap, but bursting more than ~50 requests per second from a single key may briefly return 429 - the retry wrapper above handles this automatically.

Can I get historical follower counts?

TikTok itself does not expose historical follower data, so neither does this API. The follower-tracker script above is exactly how you build your own history: capture today's number daily, persist it, plot the delta over time.

Do I need a proxy?

No - TikLiveAPI handles all IP rotation, CAPTCHA solving, and session management server-side. Your script just calls api.tikliveapi.com directly with your API key. No residential proxies, no anti-bot infrastructure to maintain.

Does the API work with synchronous and async Python equally well?

Yes - it is plain HTTPS+JSON. requests works for simple scripts, httpx handles both sync and async, and aiohttp works too. Pick whatever fits the rest of your stack.

Next Steps

You now have a working Python client for TikTok user data plus the patterns to scale it. Two natural follow-ups:

Building something interesting with TikTok data? We would love to hear about it - reach out on the contact page.

Build with the TikTok API

Ready to put what you read into code? Try our endpoints live or grab the full reference.

Open Playground Read Documentation