How to scrape TikTok Shop products of a shop with Python

A Python script that fetches TikTok Shop products of a shop, pages through the results and saves them to a file.

Preview
The API is in early access. Ask for a key; the examples use api.socialscrape.io.

Set up

You need Python 3 and the requests package.

python -m venv .venv
source .venv/bin/activate
pip install requests
export SOCIALSCRAPE_API_KEY=ss_live_...

The script

Save as scrape.py and run python scrape.py. It calls GET /v1/tiktok/shop/products.

scrape.py
import csv
import os
import time

import requests

URL = "https://api.socialscrape.io/v1/tiktok/shop/products"
HEADERS = {"x-api-key": os.environ["SOCIALSCRAPE_API_KEY"]}
PARAMS = {
    "url": "https://www.tiktok.com/shop/store/goli-nutrition/7495794203056835079",
}
MAX_ITEMS = 100


def pick(obj, *path):
    """Follow a path through nested dicts; None if any step is missing or null."""
    for key in path:
        obj = obj.get(key) if isinstance(obj, dict) else None
    return obj


def get(params):
    """One request. Failures cost nothing; retry the ones the API marks retryable."""
    for attempt in range(3):
        body = requests.get(URL, headers=HEADERS, params=params, timeout=60).json()
        if body["ok"]:
            return body
        err = body["error"]
        if not err["retryable"] or attempt == 2:
            raise RuntimeError(f'{err["code"]}: {err["message"]}')
        time.sleep(2**attempt)


items = []
params = dict(PARAMS)
while len(items) < MAX_ITEMS:
    body = get(params)
    items += body["data"]["items"]
    if not body["has_more"]:
        break
    params["cursor"] = body["cursor"]
items = items[:MAX_ITEMS]

with open("out.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerow(["title", "id"])
    for item in items:
        writer.writerow([pick(item, "title"), pick(item, "id")])

print(f"saved {len(items)} rows to out.csv, credits left: {body['credits_remaining']}")

How it works

  1. get() sends one request and retries the failures the API marks retryable. A failed request costs nothing.
  2. The loop follows cursor until has_more is false or 100 items are collected. Each page costs its own price.
  3. pick() reads nested fields and gives None instead of crashing when the platform returned null.
  4. Rows go to out.csv, one column per field.

What you get back

These fields come from a recorded sample. The full field list is on the endpoint page.

Fields in the scriptSample
{
  "title": "Goli Ashwagandha & Vitamin D Gummy - Mixed Berry, KSM-66, Vegan, Plant Based, Non-GMO, Gluten-Free & Gelatin Free. America's #1 Ashwagandha Brand",
  "id": "1729527313880355335"
}

The short version

Without paging, saving or retries, the request is this.

import os
import requests

params = {
    "url": "https://www.tiktok.com/shop/store/goli-nutrition/7495794203056835079",
}
res = requests.get(
    "https://api.socialscrape.io/v1/tiktok/shop/products",
    headers={"x-api-key": os.environ["SOCIALSCRAPE_API_KEY"]},
    params=params,
    timeout=60,
)
body = res.json()

if body["ok"]:
    print(body["data"])
else:
    print(body["error"]["code"], body["error"]["message"])

With the SDK

The Python client does the retries and the paging for you. It is in preview and not published yet.

from socialscrape import SocialScrape

client = SocialScrape()  # reads SOCIALSCRAPE_API_KEY

for item in client.paginate(client.tiktok.shop_products, url="https://www.tiktok.com/shop/store/goli-nutrition/7495794203056835079", max_items=100):
    print(item["title"])

What it costs

1 credit. A failed request costs nothing. Add max_age_days to reuse a cached result for 0 credits. Results are kept 30 days.

Next

Get a key.

Early access keys go to developers and agent builders first.

Get early access