TikTokHow-to

Export TikTok Shop reviews to CSV: API and Python script

Get a TikTok Shop product's reviews as JSON, 20 per call for 1 credit, and save them to CSV. A list ends near 3,000 reviews.

5 min read

Short answer

  • TikTok Shop's official API gives an app the data of shops that authorized it, so it is built for your own shop, not for reading other sellers' reviews.
  • Our reviews route returns 20 reviews a call with rating, text, photos, date and verified-purchase flag, and the script below writes them to CSV.
  • On two large products the newest-first list ended near 3,000 reviews, and each star filter is a separate list. A call costs 1 credit, so 1,000 reviews cost 50 credits.
On this page

You get a product's TikTok Shop reviews as JSON, 20 per call, with rating, text, photos, date and a verified-purchase flag. Pass the product ID or its URL to /v1/tiktok-shop/product/reviews, follow next_page, and the script below writes a CSV. TikTok Shop's official API is built for your own shop: an app gets the data of shops that authorized it.

What one call returns

We make ToolzerHub. Our TikTok API reads public TikTok Shop product pages with one API key. The reviews route takes product_id, region, page, sort (recommended or most_recent) and filter (a star rating, with_media or verified_purchase).

bash
curl "https://api.toolzerhub.com/v1/tiktok-shop/product/reviews?product_id=1729718141631565851&sort=most_recent" \
  -H "x-api-key: $TOOLZERHUB_API_KEY"

One review from the response, without the avatar and image links:

json
{
  "data": {
    "product_reviews": [
      {
        "review_id": "7702390543619507981",
        "product_id": "1729718141631565851",
        "review_rating": 5,
        "review_time": "1793352606606",
        "is_verified_purchase": true,
        "is_incentivized_review": false,
        "reviewer_name": "N**k",
        "review_text": "Used for a day. And skin felt so good all day. No dryness. Can’t wait to see my outcome in week two",
        "review_images": [],
        "sku_specification": "Default",
        "review_country": "US"
      }
    ],
    "total_reviews": "80585",
    "has_more": true,
    "next_page": 2
  }
}

review_time is in milliseconds. reviewer_name comes masked, the way TikTok shows it. total_reviews follows the filter, so asking for 1_star returns the number of 1-star reviews. In the US a page holds 20 reviews whatever count you send.

Export TikTok Shop reviews to CSV

The script takes product IDs or product URLs, pages each list until it ends or hits your page cap, and writes one row per review ID. It needs Python 3 and requests. Review and product IDs have 19 digits, so import those columns into Excel as Text.

python
import csv
import os
import re
import sys
import time
from datetime import datetime, timezone

import requests

API = "https://api.toolzerhub.com/v1/tiktok-shop/product/reviews"
HEADERS = {"x-api-key": os.environ.get("TOOLZERHUB_API_KEY", "")}
FIELDS = ["product_id", "review_id", "rating", "posted", "verified", "incentivized", "sku",
          "text", "images", "country"]
calls = 0


def cell(value):
    # Spreadsheets run text that starts with = + - or @ as a formula; an apostrophe keeps it text.
    if isinstance(value, str) and value[:1] in ("=", "+", "-", "@", "\t", "\r"):
        return "'" + value
    return value


def get(params, tries=5):
    # 429 and 503 are retryable; the error body may say how long to wait.
    global calls
    for attempt in range(tries):
        r = requests.get(API, headers=HEADERS, params=params, timeout=90)
        calls += 1
        if r.status_code not in (429, 503) or attempt == tries - 1:
            r.raise_for_status()
            return r.json().get("data") or {}
        try:
            wait = r.json()["error"]["details"]["retryAfter"]
        except (ValueError, KeyError, TypeError):
            wait = 5 * (attempt + 1)
        time.sleep(min(wait, 60))


def row(review):
    ms = int(review.get("review_time") or 0)
    return {
        "product_id": review["product_id"],
        "review_id": review["review_id"],
        "rating": review.get("review_rating"),
        "posted": datetime.fromtimestamp(ms / 1000, timezone.utc).date().isoformat() if ms else "",
        "verified": review.get("is_verified_purchase"),
        "incentivized": review.get("is_incentivized_review"),
        "sku": cell(review.get("sku_specification") or ""),
        "text": cell((review.get("review_text") or "").replace("\n", " ")),
        "images": " ".join(review.get("review_images") or []),
        "country": review.get("review_country"),
    }


def export(writer, product_id, max_pages, sort, region):
    params = {"product_id": product_id, "sort": sort, "region": region}
    seen, total = set(), None
    for _ in range(max_pages):
        data = get(params)
        total = total or data.get("total_reviews")
        for review in data.get("product_reviews") or []:
            if review["review_id"] not in seen:  # pages can repeat a review
                seen.add(review["review_id"])
                writer.writerow(row(review))
        if not data.get("has_more") or not data.get("next_page"):
            break
        params["page"] = data["next_page"]
    print(f"{product_id}: {len(seen)} reviews saved of {total} listed")
    return len(seen)


def main(products, max_pages="10", sort="most_recent", region="US", out="tiktok_shop_reviews.csv"):
    # Accept product IDs or product page URLs; the ID is the long number in the URL.
    ids = [m for p in products.split(",") for m in re.findall(r"\d{15,30}", p)]
    with open(out, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=FIELDS)
        writer.writeheader()
        saved = sum(export(writer, pid, int(max_pages), sort, region) for pid in ids)
    print(f"wrote {saved} rows to {out} in {calls} calls")


if __name__ == "__main__":
    if len(sys.argv) < 2:
        sys.exit("usage: python tiktok_shop_reviews.py PRODUCT_ID[,PRODUCT_ID] [max_pages]"
                 " [most_recent|recommended] [region] [file.csv]")
    if not HEADERS["x-api-key"]:
        sys.exit("set TOOLZERHUB_API_KEY first")
    main(*sys.argv[1:])
bash
export TOOLZERHUB_API_KEY=your_key
python tiktok_shop_reviews.py "1729718141631565851,1729717811293949979,1729717561093951515" 10 most_recent US tts_reviews.csv
text
1729718141631565851: 200 reviews saved of 80585 listed
1729717811293949979: 68 reviews saved of 68 listed
1729717561093951515: 200 reviews saved of 16132 listed
wrote 468 rows to tts_reviews.csv in 24 calls

What came out

We ran the script on three Dr.Melaxin skincare products with a 10-page cap, and it took 80 seconds. The toner's list ended at 68 of 68 reviews. The other two stopped at the 10-page cap, and their newest 200 reviews covered two and five days of buying.

Most reviews are a star rating with no words. Text appeared on 33.5% to 43.0% of rows, photos on 6% at most, and 97.5% or more were verified purchases. A text review had a median of 6 to 9 words.

The star filters give the full rating breakdown in five calls. On the eye balm they add up to the 80,585 total:

Rating Reviews Share
5 stars 54,106 67.1%
4 stars 7,891 9.8%
3 stars 6,329 7.9%
2 stars 3,388 4.2%
1 star 8,871 11.0%

The newest-first list ended near 3,000 reviews on both large products: after page 150 on the eye balm and page 149 on the cream. Each star filter is a separate list, and the eye balm's 1-star filter also ran to page 150, 3,000 of its 8,871. Only 2,749 of the eye balm's reviews carry photos or video, yet the first recommended page of both products had photos on all 20 reviews.

What it costs

Each call is 1 credit for 20 reviews, so 1,000 reviews cost 50 credits and a list of about 3,000 costs 150. You get 100 free credits a month; $19 buys 10,000 credits that never expire, and plans for higher volume cover more products. Set your key and your first product is a CSV in under a minute.

For the product list itself, see export TikTok Shop products; for what the official API covers, see the TikTok Shop API. For app reviews, see the Google Play reviews API.

We are not affiliated with TikTok.

Get this data from your own code

The TikTok API returns it as JSON with one x-api-key header. 100 free credits monthly.