Back to Blog

TikTok Shop Product Research: Compare a Product Watchlist

Ava Wilson
Ava Wilson

Expert in Web Scraping Technologies

02-Sep-2026

TL;DR:

  • TikTok Shop product research needs a supplied watchlist. The Shop page actor evaluates known products; it does not discover every trending or high-potential item.
  • Comparable rows require category and market context. Group similar products and retain returned region and currency before comparing price.
  • Product and SKU records answer different questions. A displayed product price cannot represent every variant automatically.
  • sold_count has no shared recent-sales window in the documented response. It should not decide which product is selling faster now.
  • Ratings and review counts need coverage labels. Missing values remain unknown and do not become zero-quality scores.
  • Free to start. New Scrapeless accounts include free credit through the Scrapeless Dashboard.

Introduction: product research begins before the API call

A research table is only as good as the candidate list and comparison rules behind it. Mixing unrelated categories, regions, currencies, and variant structures creates a ranking that looks precise but answers no stable business question.

This workflow starts with a user-curated TikTok Shop product watchlist. It collects public product snapshots, separates product and SKU fields, checks comparison scope, and produces a table for human review. It does not claim automatic product discovery or a universal “winning product” score.

Use the TikTok Shop price tracking tutorial when the decision depends on changes across repeated observations rather than one watchlist review.

Pipeline at a Glance

Stage Research question Output
Frame Which category, market, and decision are being studied? Research brief
Watch Which known products belong in scope? Candidate watchlist
Collect What does each public product page expose now? Raw snapshots
Normalize Which fields are product-level or SKU-level? Comparable tables
Review Which conclusions are supported or unresolved? Decision worksheet

The pipeline supports evidence collection for a known candidate set. Search, trend discovery, margin, conversion, and supplier validation require additional data.

Prerequisites

  • A Scrapeless account and API token from the Scrapeless Dashboard
  • A CSV watchlist with product ID, request region, category group, and internal notes
  • A written comparison policy for currency, variants, and missing values
  • A live token in SCRAPELESS_API_KEY for the collection block

The API example is a prerequisite gap because a live credential and product watchlist belong to the reader. The code does not contain a hidden example product or fabricated response.

Stage 1: Define the Research Question and Watchlist

Begin with a decision that can be reviewed: compare the public offer structure of selected products in one category and market, or inspect which candidates have the required variant and shipping information.

The watchlist should contain:

  • candidate_id, an internal string key
  • product_id, stored as text
  • request_region
  • category_group
  • inclusion_reason
  • optional internal cost, compliance, or supplier-review fields kept outside the public response

Do not ask the collector to decide which products are “best.” The roster records why each candidate entered the study and lets a reviewer identify selection bias.

Stage 2: Collect a Current Product Snapshot

The scraper.tiktok.shop.page actor accepts product_id and region. A response can include product identity, resolved region, seller, name, sold_count, nested price data, product stock, rating, review count, images, options, SKUs, categories, and shipping details.

Save the raw response with a collection timestamp before building the research table. A later parser change can then be applied without pretending the transformed row was the original source.

The HTTP request uses JSON and the x-api-token header. HTTP Semantics defines the request-response model, while Python's JSON module documentation covers the serialization used below.

Start Scraping with Scrapeless

Power up your web scraping and automation workflow with Scrapeless!
Sign up today and get $5 in free creditno credit card required.

Claim your free credit now in the Scrapeless Dashboard.

Stage 3: Build Product and SKU Research Tables

Product rows hold the current display context: product ID, returned region, seller ID, name, category, sale and original price, currency, aggregate stock, rating, review count, sold count, and collection time.

SKU rows hold variant context: product ID, returned region, SKU ID, option pairs, SKU-level price, available quantity, in-stock flag, and collection time.

TikTok Shop's inventory-search interface distinguishes product and SKU identifiers, reinforcing the need for two tables. The ISO currency-code reference explains why the currency code must travel with every numeric price.

Note: The code below requires a live Scrapeless API token in SCRAPELESS_API_KEY and a product-watchlist.csv supplied by the reader.

python Copy
import csv
import json
import os
from datetime import datetime, timezone
from urllib.request import Request, urlopen

ENDPOINT = "https://api.scrapeless.com/api/v1/scraper/request"
TOKEN = os.environ["SCRAPELESS_API_KEY"]


def fetch_product(product_id, region):
    data = json.dumps({
        "actor": "scraper.tiktok.shop.page",
        "input": {"product_id": str(product_id), "region": region},
    }).encode()
    request = Request(
        ENDPOINT,
        data=data,
        headers={"x-api-token": TOKEN, "content-type": "application/json"},
        method="POST",
    )
    with urlopen(request, timeout=60) as response:
        return json.load(response)


with open("product-watchlist.csv", newline="", encoding="utf-8") as source:
    watchlist = list(csv.DictReader(source))

product_rows = []
sku_rows = []

for candidate in watchlist:
    raw = fetch_product(candidate["product_id"], candidate["request_region"])
    collected_at = datetime.now(timezone.utc).isoformat()
    product_id = str(raw.get("product_id") or candidate["product_id"])
    region = str(raw.get("region") or "")
    price = raw.get("price") or {}
    stock = raw.get("stock") or {}

    with open(f"{candidate['candidate_id']}-raw.json", "w", encoding="utf-8") as output:
        json.dump(raw, output, ensure_ascii=False, indent=2)

    product_rows.append({
        "candidate_id": candidate["candidate_id"],
        "category_group": candidate["category_group"],
        "collected_at": collected_at,
        "product_id": product_id,
        "region": region,
        "seller_id": str(raw.get("seller_id") or ""),
        "name": raw.get("name"),
        "currency": price.get("currency"),
        "sale_price": price.get("sale_price"),
        "original_price": price.get("original_price"),
        "available_quantity": stock.get("available_quantity"),
        "in_stock": stock.get("in_stock"),
        "rating": raw.get("rating"),
        "review_count": raw.get("review_count"),
        "sold_count": raw.get("sold_count"),
    })

    for sku in raw.get("skus") or []:
        sku_price = sku.get("price") or {}
        sku_rows.append({
            "candidate_id": candidate["candidate_id"],
            "product_id": product_id,
            "region": region,
            "sku_id": str(sku.get("sku_id") or ""),
            "options": " | ".join(
                f"{v.get('name', '')}={v.get('value', '')}"
                for v in (sku.get("options") or [])
            ),
            "currency": sku_price.get("currency"),
            "sale_price": sku_price.get("sale_price"),
            "available_quantity": sku.get("available_quantity"),
            "in_stock": sku.get("in_stock"),
            "collected_at": collected_at,
        })

for filename, rows in (("products.csv", product_rows), ("skus.csv", sku_rows)):
    if not rows:
        continue
    with open(filename, "w", newline="", encoding="utf-8") as output:
        writer = csv.DictWriter(output, fieldnames=rows[0].keys())
        writer.writeheader()
        writer.writerows(rows)

The two exports preserve their level of detail. A product can have one displayed price while individual SKUs expose their own price or availability.

Stage 4: Apply Comparison Rules Before Ranking

Compare candidates only when the research question supports it:

Check Safe treatment
Category Compare products within the declared category group
Region Use the returned region and avoid cross-market availability claims
Currency Compare raw prices only within the same currency
Variant coverage Report SKU count and price range rather than one arbitrary SKU
Missing rating Keep unknown; do not convert to zero
Sold count Preserve as a cumulative-looking page field with no shared recent window

sold_count does not establish recent velocity, net sales, refunds, revenue, or GMV. Two products can have different ages and observation windows, so a larger value does not prove stronger current demand.

Stage 5: Create the Product Research Worksheet

The final worksheet should support a human decision rather than hide it behind a score. Include:

  • Candidate identity and inclusion reason
  • Returned market and currency
  • Current product price plus SKU price range
  • Product-level and variant-level availability coverage
  • Rating and review count with missing-value flags
  • Sold-count field with a scope warning
  • Seller, category, and shipping fields needed by the research brief
  • Reviewer conclusion: proceed, hold, reject, or evidence insufficient

External costs, commission, margin, supplier reliability, regulatory checks, and conversion data must be joined from appropriate first-party or internal sources. The Shop snapshot alone cannot answer those questions.

Handle Product Research Responsibly

Store only the public product fields needed by the project. Keep internal supplier or reviewer notes access-controlled, and avoid copying product imagery when a source URL is sufficient. The NIST Privacy Framework provides general guidance for defining collection purpose, access, and retention.

Scrapeless provides Shop snapshots through Scraping API. Review the current pricing page before collecting a larger watchlist.

Conclusion: keep the decision outside the collector

TikTok Shop product research works best when the watchlist, category rules, and decision criteria are explicit. The actor supplies current public product and SKU observations; the research worksheet preserves scope, uncertainty, and the evidence still missing before a commercial decision.

Ready to Compare a Product Watchlist?

Join the Scrapeless Discord or Telegram community to discuss product-table designs. Create an account in the Scrapeless Dashboard when the candidate list is ready.

FAQ

Q: Can the Shop actor discover trending products automatically?

The Shop page actor evaluates a known product ID and region. Product discovery and trend ranking require a separate candidate source and methodology.

Q: Which fields belong in a TikTok Shop product comparison?

A comparison can include returned region, currency, product and SKU prices, variant availability, rating, review count, categories, seller fields, and shipping details when present.

Q: Does a larger sold count prove stronger recent sales?

A larger sold count does not prove stronger recent sales because the documented response does not supply a shared recent reporting window, refunds, or a complete order ledger.

Q: Should missing ratings be stored as zero?

Missing ratings should remain unknown. Zero is a definite value and would distort filtering or ranking.

Q: Do I need to manage a proxy or product-page parser?

The actor handles its collection surface behind the API request. The caller defines the watchlist, comparison rules, storage, and review process.

Q: Is collecting public product data legal?

Legality depends on jurisdiction, market, purpose, access method, and applicable terms. Use public data for a permitted purpose and obtain legal advice for the intended workflow.

At Scrapeless, we only access publicly available data while strictly complying with applicable laws, regulations, and website privacy policies. The content in this blog is for demonstration purposes only and does not involve any illegal or infringing activities. We make no guarantees and disclaim all liability for the use of information from this blog or third-party links. Before engaging in any scraping activities, consult your legal advisor and review the target website's terms of service or obtain the necessary permissions.

Most Popular Articles

Catalogue