TikTok Shop Scraper - Search, Prices & Reviews avatar

TikTok Shop Scraper - Search, Prices & Reviews

Pricing

Pay per event

Go to Apify Store
TikTok Shop Scraper - Search, Prices & Reviews

TikTok Shop Scraper - Search, Prices & Reviews

Search TikTok Shop by keyword or browse its categories. Returns title, price, discount, brand, shop, rating with review count, units sold and promotion badges, plus the description and seller stats on product pages.

Pricing

Pay per event

Rating

0.0

(0)

Developer

SR

SR

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

Read TikTok Shop as structured data: title, price, the pre-promotion price and discount where one is running, currency, brand, shop, rating with its review count, units sold, and the promotion badges.

Paste category or product links, or run it with nothing and it reads six of the storefront's largest categories.

What you get per product

  • title, url, product_id, slug
  • price, currency, currency_symbol
  • original_price, discount_percent, saving — when a promotion is running
  • rating out of 5 and review_count
  • sold_count — units sold, which is the number most catalogues never publish
  • brand, seller, seller_id
  • promotion_labels such as Flash sale
  • image_url, sku_id
  • found_on and source — which category, search or product page the row came from

Rows read from a product page carry more: the full description, the category_path, and the seller's own numbers (seller_followers, seller_sold_count, seller_product_count). Those come from search results and from any product you name directly.

A product with no reviews has no rating. TikTok reports 0.0 there, which sorts as the worst item on the page; the field comes back empty instead, with review_count: 0 saying why.

sold_count is the field worth the run on its own. Rating tells you how a product was received; units sold tells you whether anyone bought it. A 4.9 on twelve reviews and a 4.5 on thirty thousand sales are different products.

An empty discount means no discount

Most products on TikTok Shop are not on promotion, and for those the storefront publishes a price and nothing else.

This Actor leaves original_price, discount_percent and saving empty on those rows rather than copying the sale price across into the "before" column. That copy is tempting because it makes the table look complete, and it would give every ordinary product a 0% discount that reads, once you sort by it, as though the product had been checked and found not to be on offer. It has not been checked. There is simply no promotion.

The run summary reports onPromotion so you can see how much of a run carried one. In testing that was 9 of 26.

Search by keyword

TikTok Shop publishes no search endpoint: /search, /us/search and /us/s/term all return 404, and the storefront offers a category tree and nothing else.

Type a keyword anyway. The matching product pages are found in a public web index, and each one is then read live from TikTok. Only the finding is second-hand: every price, rating and sold count in your results comes from TikTok at the moment of the run, which matters because a search index is weeks stale on exactly those fields.

vitamin c serum resolved to eight products with their live ratings, review counts and units sold in under a minute.

Give a keyword and categories and it works the other way instead: the keyword filters what the categories serve, and the crawl widens automatically to six passes and one subcategory level to give the filter something to work with.

The redacted prices, which is the thing to know before you trust a column

TikTok blanks out digits in the price on some product pages. Not all of them, and there is no pattern to which:

"sale_price_decimal": "2*" redacted
"sale_price_decimal": "5*" redacted
"sale_price_decimal": "27.17" real

Read carelessly, "2*" becomes 2 and a twenty-nine dollar product appears in your table at two dollars. That is not a rounding error. It is an order of magnitude, it looks entirely plausible next to real prices, and it is wrong in the direction that makes something look like a bargain.

So a redacted price is returned empty, with price_masked: true on the row and pricesRedactedByTikTok in the run summary. Everything else on that product survives: the rating, the review count, the units sold, the seller. In a sample of eight search results, three were redacted.

Category listings are not redacted, so browsing returns prices for everything.

Re-asking is the pagination

This is the other thing worth knowing, because it is not obvious and it is where the volume comes from.

A category page shows 15 products, and ?page=2 appears to fetch the next fifteen. It does not. ?p=2 returns "new" products too, and so does a made-up ?cursor=15, because the list is rotated per request rather than paged. Four fetches of the identical URL returned 55 distinct products, not 15.

So Passes per category is the real control over how much of a category you see:

passesdistinct products from one category
115
345
460

Add Subcategory depth on top and one category becomes its whole first level: that same category at depth 1 returned 117 products from 21 subcategories.

Ids are enough

Paste a category link, a product link, or just the id. https://shop.tiktok.com/us/c/-/700645 serves the same page as the full slug URL, and /us/pdp/x/<id> the same as the canonical product URL, so the slug carries no information and is ignored.

A six-to-nine digit number is read as a category, a longer one as a product. Anything shorter is refused rather than guessed at.

Leaving the input empty reads six large categories: beauty and personal care, womenswear, food and beverages, home supplies, health, and phones and electronics.

About the retries, because you will see them

The storefront is a single-page app, and asking for a page returns one of two things. Roughly three times in four you get a small shell with no products in it, at HTTP 200 with no error and nothing that looks like a refusal. The fourth time the same URL returns the full server-rendered catalogue.

So pages are simply requested again. Attempts per page defaults to 10, which clears about 90% on the measured rate, and the run summary reports requestsRetried and retriesPerPage so the cost of that is visible rather than hidden.

This is worth knowing for two reasons. A run taking longer than you expect is usually this, not a fault. And a retriesPerPage figure that climbs across scheduled runs is the early warning that something changed, well before the Actor starts failing.

A page that never comes through in its budget is reported by URL, with the number of attempts spent, rather than quietly dropped.

Filters and scale

  • Categories or products — links or bare ids, one per line
  • Maximum products — the ceiling on both time and cost, applied after duplicates are removed across pages
  • Attempts per page — raise it if a run reports pages it could not read
  • Market — two-letter code, which sets the storefront and the exit country. The United States storefront is the one this has been verified against.

A category page carries 15 to 21 products. Three pages and 26 distinct products took seven seconds in a run that needed no retries at all.

What people use this for

Trend spotting. sold_count next to rating and the promotion badges is what separates a product being pushed from a product being bought. Run the same categories daily and the movers are the rows whose sold count jumps.

Price and promotion monitoring. Because an empty discount really means no discount, a run tells you exactly which products went on offer since the last one, without having to infer it.

Competitive research. Brand and shop on every row means a category run groups directly into who is selling what, at what price, and with how much volume behind it.

Sourcing. Units sold against price is the crude but effective filter for what a category actually moves.

Notes

Prices, discounts and sold counts are live and change through the day; a run is a snapshot.

Products are read from category and product pages, so this returns what the storefront lists. Reviews are counted but not fetched: a product with 158 reviews gives you the number, not the 158 texts.

A link that is neither a product nor a category is reported by name rather than silently skipped, so a run of fifty tells you exactly which line was wrong.