Collecting TikTok Shop Product Data for Market Research

Official routes first: what the TikTok Shop Partner API and Research API really expose, when licensed data wins, and how to read public product pages slowly and in the right market.

Collecting TikTok Shop Product Data for Market Research
In this article

If you need TikTok Shop product data for pricing or assortment research, the official routes come first. The TikTok Shop Partner API gives you full catalogue and order data, but only for shops that authorise your app. The TikTok Research API returns product, price and sold-count fields for EU shops, but only to approved non-commercial researchers. Most commercial teams studying competitors end up with licensed data from analytics vendors, or a slow, polite collector that reads the structured data public product pages already publish, routed through IPs in the market being studied.

This guide is written for market research. It is not affiliated with or endorsed by TikTok, and it does not cover TikTok's private, signed internal APIs.

What TikTok Shop product data teams actually need

Most research questions come down to about eight fields: product title, current price, list price (and so the discount), sold count, shop, rating and review count, category, and which creators are promoting the item.

  • Pricing research. Current price, list price, currency and active promotions, compared across sellers of the same or equivalent product. This needs consistent timestamps and a fixed market. A price from the UK storefront and one from Germany are different observations, not one noisy one.
  • Assortment analysis. Which categories a shop covers, how many SKUs and variants it lists, and where its prices sit in the category. Weekly snapshots are usually enough.
  • Trend detection. Changes in sold count and review count over time, by category. The absolute numbers matter less than the slope, which is lucky, because displayed sales numbers are imprecise (more on that below).
  • Creator and affiliate mapping. Which creators link to a product. This is the field with the most legal weight, because it is about people, not products.

If you have built price trackers for other marketplaces, the shape is familiar. Our guides on automated competitor price monitoring and tracking prices across markets cover the pipeline side. What is different on TikTok Shop is how much of the catalogue is gated by market and by login.

Official routes to TikTok Shop data

There are three legitimate sources of structured TikTok Shop data, and none of them simply hands a commercial team its competitors' catalogues. Check them first anyway: the first two are free if you qualify, and the third often costs less than building.

TikTok Shop Partner Center and the TTS API

The TikTok Shop Partner Center is where developers register apps for the TikTok Shop Open Platform. TikTok's own overview describes the TTS API as giving access to "authorized TikTok Shop data, including catalogs, orders, shipments, payments, and more". Its categories include Product, Order, Fulfillment, Return & Refund, Logistics, Promotion, Finance, Seller, Authorization, Events, Data Reconciliation and Supply Chain APIs.

The word that matters is authorized. The docs list three authorization types: seller (a shop grants your app access), creator, and partner. Every one of them depends on the data owner opting in. If you are a seller, or a tool vendor whose customers are sellers, this is the best data you can get: exact prices, real inventory and real order counts for those shops. It is not a way to look at shops that have not connected your app. The docs also list supported regions and locales, with a note that availability changes as markets open.

TikTok Research API, which does include EU shop data

The TikTok Research API is mostly known for public videos, comments and accounts. It also has three TikTok Shop endpoints that many people miss. The shop info endpoint returns shop rating, review count, items sold and a performance value. The shop products endpoint returns product name, price, description, sold count, review count and a 1–5 star breakdown. The product reviews endpoint returns review text, rating and timestamps. All three are scoped to shops and products available in the EU, and they return at most 10 results per call.

The catch is eligibility. Access goes to academic institutions in the US, EEA, UK, Canada and Switzerland, to not-for-profit research organisations in the EU, and to some Brazilian institutions studying youth safety. Applicants must be "independent of commercial interests". The Research API FAQ gives a standard quota of 1,000 requests per day. A university group studying EU social commerce should apply; a brand's pricing team is not eligible and should not borrow a research partner's access.

Licensed data from analytics vendors

There is a whole category of TikTok Shop analytics products that sell product rankings, estimated sales, creator-to-product links and category trends through a dashboard or an API. Before you buy, ask three things. Which markets are covered? Are sales figures observed or modelled? Can you redistribute the data internally? A vendor that cannot say where its numbers come from is giving you estimates, and you should treat them that way.

RouteWho can get itWhat it coversCompetitor data?
TTS API (Partner Center)Sellers, and app developers authorised by sellers, creators or partnersFull catalogue, prices, inventory, orders, promotions, finance for authorised shopsNo, only shops that connected your app
Research API, TikTok Shop endpointsApproved non-commercial researchersEU shops: shop rating and sales, product price and sold count, reviewsYes, but non-commercial research only
Analytics vendorsAnyone who paysRankings, estimated sales, creator links, historyYes, within the licence; accuracy varies
Public product pagesAnyone in a served marketWhatever the page shows a logged-out visitorYes, subject to ToS and robots.txt

Public TikTok Shop pages: what exists on the open web

TikTok Shop is mostly an in-app experience, but there is a browser storefront at shop.tiktok.com, organised by market, with product detail pages under a /pdp/ path. The market you see depends on where you connect from. When we requested a www.tiktok.com/shop/pdp/… URL from a server in Germany, it returned a 301 redirect to shop.tiktok.com/de/pdp/…. The bare www.tiktok.com/shop path, requested from the same machine, redirected to shop.tiktok.com/us.

On market coverage: TikTok's newsroom announced that Austria, Belgium, the Netherlands and Poland would launch on 15 June 2026, joining France, Germany, Ireland, Italy, Spain and the UK. The Partner Center region list (last updated 6 July 2026) also includes the US, Mexico, Brazil, Japan, Indonesia, Malaysia, the Philippines, Singapore, Thailand and Vietnam. That gives 20 markets with an official source. Third-party lists name more, but we could not confirm those against TikTok's own pages, so they are left out here.

Three things follow for collection:

  • Geography decides what you see. The same product can have a different price, currency, availability or seller in each market, or not exist at all. To collect the UK storefront, your traffic has to come from the UK. This is the main reason residential IPs with country targeting matter here, such as USERNAME-country-GB on a residential proxy. It has nothing to do with disguise.
  • The pages rely heavily on JavaScript. The storefront is a client-rendered app. Response headers from shop.tiktok.com include x-processed-by: Modern.js, which is ByteDance's open-source web framework. Expect a real browser to be needed.
  • There is an interstitial. From our datacenter test box, both shop.tiktok.com/de and shop.tiktok.com/robots.txt returned an HTML page titled "Security Check" that loads a CAPTCHA script. We stopped there. Solving or bypassing that challenge is out of scope, and if your collector hits it repeatedly, the right response is to slow down or stop.

Where the data lives on a product page

On modern storefronts, the fields you want rarely sit in tidy HTML. They usually live in one of three places, in descending order of stability: a JSON-LD block that follows schema.org Product/Offer (published for search engines, see Google's product markup docs), Open Graph and product meta tags, and the framework's embedded hydration state, a large JSON blob inside a <script> tag that the app uses to render without another round trip.

The technique is to read what the page already sent you. Parse any JSON-LD and meta tags as documented formats. For hydration state, inventory the JSON blobs (their IDs and sizes), look at one in a browser yourself, and map only the fields you need. Two things are explicitly out of scope: calling the private XHR endpoints the app uses behind the scenes, and reproducing their signature or token parameters. Forging their signatures is circumvention, not collection. We could not load a product page from our test machine (see the interstitial above), so we will not claim TikTok Shop pages carry JSON-LD. The code below works the same whether they do or not.

Data pointWhere it usually livesReliabilityNotes
Product titleJSON-LD name, og:title, hydration stateHighMay be localised per market; key on product ID, not title
Current priceJSON-LD offers.price, hydration stateMediumVaries by market, variant and promotion; always store the currency
List price / discountHydration state; rarely in JSON-LDMedium-lowStruck-through prices are seller-set; work out discounts yourself
Sold countHydration state, visible label; Research API (EU)Low-mediumLabels are often abbreviated; use as a trend, not as audited sales
Rating, review countJSON-LD aggregateRating, hydration stateMediumMay count reviews differently across markets; Research API has a star breakdown for the EU
Shop name / IDHydration state, visible seller blockHighStore the ID; shop names change
CategoryBreadcrumb JSON-LD, hydration stateMediumCategory trees differ by market; map them to your own taxonomy
Variants / SKUsHydration stateMediumPrice ranges hide the price of the variant shoppers actually choose
Creator / affiliate linksMostly in-app; partly in hydration stateLow on the webPersonal data; vendor or partner data is usually better here

A polite collection design

A research collector should behave like a slow, honest visitor. That means one page at a time, a fixed set of URLs, aggressive caching, and stopping on challenges. TikTok's terms and robots rules make the limits clearer than most sites do, so start there.

What robots.txt and the terms actually say

www.tiktok.com/robots.txt (fetched 3 October 2026) disallows /shop/view/product/ for all user agents, and blocks the whole site for a named list of crawlers that includes GPTBot, ClaudeBot, CCBot, PerplexityBot and Bytespider. It does not mention /shop/pdp/, and it has no Sitemap line. We could not read shop.tiktok.com/robots.txt from our test machine because it returned the HTML challenge page instead. That is a trap: Python's urllib.robotparser parses an HTML page as "no rules", which means "allow everything". The code below only trusts a plain-text 200 response.

The terms are stricter than robots.txt. The US Terms of Service (agreed with TikTok USDS Joint Venture LLC, last updated 15 July 2026) prohibit scraping or extracting data "for any purpose, from the Platform using any automated system or software… except as approved in writing". The EEA terms say much the same. Whether they bind a logged-out visitor depends on jurisdiction, but they are a strong reason to prefer the official and licensed routes.

Design rules, with the reasons

  1. Start from a known URL list, not a crawl. Research questions are about specific products or a sampled set. Crawling search and category pages is where load and ToS risk pile up, and TikTok's robots.txt disallows /search? paths anyway.
  2. Use one market per run, and pin it. Country-target the exit IP, and set the browser locale and timezone to match, so every observation in a batch is the same market.
  3. Keep the rate low. One page every 20–40 seconds per market is plenty for daily price snapshots of a few hundred products.
  4. Cache by (product ID, market, day). If you already have today's UK observation, don't fetch it again.
  5. Treat a challenge as a stop signal. Log it, wait, and lower your rate. Don't rotate IPs to get around the same block.
  6. Don't log in. Collect only what a logged-out visitor sees. Logged-in collection ties automation to an account and its terms, and touches personal data.

A careful Python example with Playwright

The script below opens each product URL through a country-targeted proxy in Chromium. It checks a real robots.txt first, stops on non-200 responses or a "Security Check" title, and extracts JSON-LD Product data, a few meta tags, and a list of embedded JSON blobs for you to inspect. It does not use any TikTok-specific selectors, because we could not verify them, and every field comes back as None if it is missing. Proxy settings follow Playwright's documented proxy option. We tested the extraction and robots logic against local fixtures with Playwright 1.55. We did not run it against live TikTok Shop pages.

import json
import random
import time
import urllib.robotparser
from urllib.parse import urlsplit

from playwright.sync_api import sync_playwright

# Country is chosen in the proxy username; match locale/timezone to it.
PROXY = {
    "server": "http://gate.proxyhat.com:8080",
    "username": "USERNAME-country-GB",
    "password": "PASSWORD",
}
UA_NAME = "acme-price-research"  # the token you'd look for in robots.txt groups

# Product URLs you already have (from your own catalogue matching, a partner
# export, or manual research), not URLs discovered by crawling search pages.
URLS = [
    "https://shop.tiktok.com/...",  # paste real product URLs as your browser shows them
]


def robots_verdict(context, url):
    """Return True/False from a real robots.txt, or None if we couldn't get one."""
    parts = urlsplit(url)
    resp = context.request.get(f"{parts.scheme}://{parts.netloc}/robots.txt")
    ctype = resp.headers.get("content-type", "")
    # An HTML challenge page parses as "no rules" (= allow everything) in
    # urllib.robotparser, so only trust a plain-text 200.
    if resp.status != 200 or "text/plain" not in ctype:
        return None
    rp = urllib.robotparser.RobotFileParser()
    rp.parse(resp.text().splitlines())
    return rp.can_fetch(UA_NAME, url)


def _types(node):
    t = node.get("@type", [])
    return t if isinstance(t, list) else [t]


def extract(page):
    """Read what the page itself publishes: JSON-LD, Open Graph/product meta,
    and an inventory of embedded JSON blobs for a human to inspect."""
    jsonld = []
    for raw in page.locator('script[type="application/ld+json"]').all_text_contents():
        try:
            data = json.loads(raw)
        except json.JSONDecodeError:
            continue
        nodes = data if isinstance(data, list) else data.get("@graph", [data])
        jsonld.extend(n for n in nodes if isinstance(n, dict))

    meta = {}
    for prop in ("og:title", "og:url", "product:price:amount", "product:price:currency"):
        loc = page.locator(f'meta[property="{prop}"]')
        if loc.count():
            meta[prop] = loc.first.get_attribute("content")

    blobs = page.evaluate(
        """() => [...document.querySelectorAll('script[type="application/json"]')]
                 .map(s => ({id: s.id || null, chars: s.textContent.length}))"""
    )

    product = next((n for n in jsonld if "Product" in _types(n)), None)
    record = {"name": None, "price": None, "currency": None,
              "availability": None, "rating": None, "review_count": None}
    if product:
        record["name"] = product.get("name")
        offers = product.get("offers") or {}
        if isinstance(offers, list):
            offers = offers[0] if offers else {}
        record["price"] = offers.get("price") or offers.get("lowPrice")
        record["currency"] = offers.get("priceCurrency")
        record["availability"] = offers.get("availability")
        agg = product.get("aggregateRating") or {}
        record["rating"] = agg.get("ratingValue")
        record["review_count"] = agg.get("reviewCount") or agg.get("ratingCount")
    return {"record": record, "meta": meta, "json_blobs": blobs,
            "has_jsonld_product": product is not None}


def main():
    results = []
    with sync_playwright() as p:
        browser = p.chromium.launch(proxy=PROXY)
        context = browser.new_context(locale="en-GB", timezone_id="Europe/London")
        page = context.new_page()
        for url in URLS:
            verdict = robots_verdict(context, url)
            if verdict is not True:
                results.append({"url": url, "status": "skipped", "robots": verdict})
                continue
            resp = page.goto(url, wait_until="domcontentloaded", timeout=45_000)
            status = resp.status if resp else None
            if status != 200 or page.title().strip().lower() == "security check":
                # Don't try to solve it. Record, slow down, move on.
                results.append({"url": url, "status": "challenge_or_error", "http": status})
                time.sleep(120)
                continue
            data = extract(page)
            data.update({"url": url, "final_url": page.url, "status": "ok",
                         "fetched_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
                         "proxy_country": "GB"})
            results.append(data)
            time.sleep(random.uniform(20, 40))  # one page at a time, slowly
        browser.close()
    print(json.dumps(results, indent=2, ensure_ascii=False))


if __name__ == "__main__":
    main()

When has_jsonld_product comes back false, look at json_blobs. Open one product in a normal browser, find the blob that holds the price, and write a small, explicit mapping for the two or three keys you need. Add a test that fails loudly when those keys move. For a broader look at the JavaScript side, see scraping JavaScript-heavy websites.

Data quality pitfalls

Most TikTok Shop datasets go wrong in analysis, not collection. Prices get compared across markets without normalisation, promotional prices get read as list prices, and rounded sold counts get treated as sales figures.

  • Region and currency. Store market, currency and the exit country with every row. Convert currencies at the observation date's rate, and never average prices across markets.
  • Flash sales and promotions. Short promotions can move the displayed price for hours. Snapshot at the same time each day, and record both the shown price and any list price, so a sale is not mistaken for a permanent cut.
  • Sold-count rounding. Displayed counts are often abbreviated, and even an exact integer in page data is the platform's figure, not an audited number. Use differences over time, and expect steps rather than smooth curves.
  • Market-specific catalogues. A product missing from one market isn't out of stock. It may simply not be sold there. Keep "not available in market" separate from "out of stock".

The same problems come up on other marketplaces we have covered. The Shein price-intelligence guide deals with regional storefronts, the Temu product-data guide with embedded JSON, and the Shopify guide with documented public product endpoints, which is a useful contrast to platforms that don't have them.

Public product listings are the lowest-risk part of this dataset. Creators are the highest. A product's price is commercial information, but a creator's handle, profile and affiliate activity are personal data under the GDPR when they relate to an identifiable person. Collecting them for EU or UK work needs a lawful basis, data minimisation and a retention limit, even when the profile is public. Aggregate where you can, for example "products promoted by more than 50 creators", instead of building profiles of individuals.

On top of that sit TikTok's terms, quoted above, and the trademark question: describe TikTok Shop factually, and don't present your dataset or tool as affiliated with it. If the research is commercial and ongoing, an official or licensed route is nearly always the more durable choice. A public-page collector works best for narrow, low-volume checks the official routes don't cover, such as confirming what a UK shopper actually sees today.

What this approach does not solve

A polite public-page collector won't give you full category coverage, creator attribution, live-stream sales or in-app-only content. It won't get past interstitials, and it shouldn't try. Over months it will also break as the frontend changes. If you need any of those, the gap is a data-licensing question, not an engineering one. For the network side of what remains, our web scraping use case page and locations list show which countries you can route through.

Frequently asked questions

Is there an official API for TikTok Shop product data?

Yes. The TikTok Shop TTS API, available through Partner Center, exposes catalogue, price, inventory and order data, but only for shops, creators or partners that authorise your app. It is not a way to read competitors' shops.

Does the TikTok Research API include TikTok Shop data?

It does for the EU. The Research API has endpoints for shop info, shop products (including price and sold count) and product reviews, limited to shops and products available in the EU. Access is only for approved non-commercial researchers, such as academic institutions and not-for-profit research bodies.

Why do TikTok Shop prices look different from another country?

TikTok Shop runs separate storefronts per market, and requests are routed to a market by location. Price, currency, seller and availability can all differ, so collect each market from an IP in that country and store the market with every observation.

Do TikTok's terms allow automated collection from TikTok Shop pages?

TikTok's US and EEA terms prohibit automated data extraction without written approval, and robots.txt on www.tiktok.com disallows /shop/view/product/ for all crawlers. Prefer official or licensed data for commercial use, and keep any public-page collection minimal, slow and logged out.

How accurate are TikTok Shop sold counts?

They are best treated as directional. Displayed counts are often abbreviated, and even exact figures are platform-reported rather than audited. Use changes over time to spot trends instead of treating them as revenue data.

Track prices and competitors without getting blocked

Reliable residential proxies for e-commerce data. Sign up and start pulling clean data.

Get started
← Back to Blog