TikTok Shop Scraper - $1.10 per 1,000 Products
Pricing
from $1.10 / 1,000 product scrapeds
TikTok Shop Scraper - $1.10 per 1,000 Products
Units sold sits on the card of every TikTok Shop product, and it is what TikTok's own best-seller pages rank on. Search terms, collection URLs and store URLs mix in one run. Title, price, original price, discount, rating, reviews, shop, link, images. US storefront. $1.10/1,000.
Pricing
from $1.10 / 1,000 product scrapeds
Rating
0.0
(0)
Developer
Dami's Studio
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Categories
Share
TikTok Shop Scraper
Units sold sits on the card of every TikTok Shop product, and it is the number TikTok's own best-seller pages rank on. Search terms, TikTok Shop collection URLs and store URLs all go into the same run. Products come back as a table: title, price and currency, the crossed-out original price and the discount, star rating, review count, units sold, which shop sells it, the product link and the images.
No account, no API key, no browser.
- Three ways in: a plain search term, a collection page URL, or a store page URL. Mix them in one run.
- Units sold and star rating land on the same row as the price, so sorting a category by
soldCountdoesn't need a second lookup. - Sort a search by best sellers or by newest, not just the site default.
- Rows are deduplicated on product id across the whole run, so a product that matches two of your terms is charged once.
- Empty input returns one labelled sample row, free.
Price
$1.10 per 1,000 products. Plus $0.001 per run as the platform start fee, billed per gigabyte of run memory, so exactly that on the default 1 GB.
No volume tiers, no minimum spend, no subscription.
| Products | Total |
|---|---|
| 100 | $0.111 |
| 1,000 | $1.101 |
| 10,000 | $11.001 |
| 100,000 | $110.001 |
What gets charged
- One
product-scrapedevent per product row written to the dataset. Nothing else is metered per row. - Free: the sample row an empty run returns, and every diagnostic row. They all carry
"charged": false. - Duplicate products that already appeared earlier in the same run are dropped before they're charged.
- Products the page rendered but that carry no title are skipped rather than delivered as an empty row.
- A run that finds nothing costs the start fee and nothing else.
- Rows never leave the dataset without a charge and are never charged without a row. The billed event is a named one, so nothing is quietly attached to
apify-default-dataset-item.
Input
{"searchTerms": ["makeup brush","wireless earbuds"],"startUrls": ["https://shop.tiktok.com/us/k/probiotic-sodas","https://www.tiktok.com/shop/store/bk-beauty-brushes/7495182121564604692"],"sortBy": "best_sellers","maxItems": 200}
| Field | What it does |
|---|---|
searchTerms | Keywords to search TikTok Shop for. Each term is searched in turn until the run reaches maxItems. |
startUrls | TikTok Shop pages to read instead of, or as well as, search terms. Collection pages (/shop/k/...), store pages (/shop/store/<name>/<seller id>) and search pages (/shop/s/...) are all understood. A bare seller id works too. Anything else gets a free diagnostic row telling you why it was skipped. |
sortBy | How products come back for a search term or a collection URL: relevance (site default), best_sellers (most units sold first) or newest. Store pages always come back in the shop's own order. |
maxItems | Total rows across every term and URL. The budget is split evenly between targets, so four targets and 100 rows gives you 25 of each. Default 50, hard ceiling 5,000. Keep it low while testing, since you pay per product. |
proxyUrls | Leave empty. Only for callers who want traffic to leave through proxy servers they already pay for, as http://user:pass@host:port. They have to exit in a country where TikTok Shop operates. |
sessionCookies | Leave empty. Runs work with nothing filled in. See Shop pages behind a bot check. |
Run it with empty input and you get one labelled sample row, free.
Output
One row per product. This is a real row from a real run:
{"ok": true,"charged": true,"recordType": "product","productId": "1732304214281785959","title": "A set of 13 professional makeup brushes, including soft fur eyeshadow brushes, foundation brushes, and blush brushes, for creating a perfect makeup look","price": 1.72,"currency": "USD","priceFormatted": "$1.72","originalPrice": 4.19,"discountPercent": 59,"rating": 5,"reviewCount": 1,"soldCount": 24,"shopName": "Suitable beauty tools","sellerId": "8654790995160371815","shopUrl": "https://www.tiktok.com/shop/store/suitable-beauty-tools/8654790995160371815","brand": null,"productUrl": "https://shop.tiktok.com/us/pdp/professional-makeup-brush-set-13-soft-fur-brushes-perfect-makeup/1732304214281785959","imageUrl": "https://p16-oec-general-useast5.ttcdn-us.com/tos-useast5-i-omjb5zjo8w-tx/1f4954883fb143619c8fa9928ea79b4e~tplv-fhlh96nyum-crop-webp:800:800.webp","images": ["https://p16-oec-general-useast5.ttcdn-us.com/tos-useast5-i-omjb5zjo8w-tx/1f4954883fb143619c8fa9928ea79b4e~tplv-fhlh96nyum-crop-webp:800:800.webp","https://p19-oec-general-useast5.ttcdn-us.com/tos-useast5-i-omjb5zjo8w-tx/1f4954883fb143619c8fa9928ea79b4e~tplv-fhlh96nyum-crop-webp:800:800.webp"],"promotionLabels": ["Free shipping"],"stockStatus": null,"searchTerm": "makeup brush","sourceType": "search","sourceUrl": "https://www.tiktok.com/shop/s/makeup%20brush","region": "US","scrapedAt": "2026-08-16T18:14:43.486Z"}
Field notes
priceis what's actually being charged now, as a number.priceFormattedis the same figure with the symbol the site shows.originalPriceis the crossed-out "was" price. Null when the product isn't discounted, which is most of them.discountPercentis the percentage off as a number rather than the"59%"string the page renders. Null when there's no discount.ratingis stars out of five. A brand-new listing with no reviews comes back as null rather than 0.reviewCountis how many reviews the product has. 0 is a real answer for a new listing.soldCountis lifetime units sold as TikTok reports it on the card, as a number. Null on a card that doesn't carry one.shopNameis the seller's shop name.sellerIdandshopUrlon the same row let you jump to the whole catalogue, and you can feed thatshopUrlback in as astartUrlsentry.productUrlis the canonical product page, with the slug the site itself uses.imagesholds every image URL the listing card carries.imageUrlis the first, which is the one the site shows.promotionLabelsholds the promotion chips on the card, likeFree shippingorFlash sale. An empty array means the card carried none.stockStatusis set only where the listing itself publishes a stock signal, otherwise null. See the limits.searchTermsays which of your terms or URLs produced the row, so a multi-target run stays sortable.regionis the storefront the row came from, as a two-letter country code.
Real rows carry "charged": true. Sample rows carry "_sample": true, diagnostic rows carry "_diagnostic": true and an errorCode. Neither is billed.
How it works
It reads TikTok Shop's own product feed directly, the same data the product grid is filled with, instead of rendering the page. No headless browser and no login.
Each target opens its own page once to pick up the guest session the site hands any first-time visitor, then asks for products a hundred at a time. That keeps the round trips at roughly one per hundred rows. Whatever the page already rendered server-side is read out of the page and costs no extra request.
Requests leave through a rotating pool of addresses in the storefront's own country, because TikTok Shop decides which catalogue you see from where the request comes from. A thin or empty answer is treated as a throttled address rather than an empty catalogue: the run moves to a fresh address and asks again before it will accept "there is nothing here".
Shop pages behind a bot check
TikTok serves some shop pages behind a bot check to every logged-out visitor. Not to this Actor in particular, and not because of where the request comes from.
When that happens the run looks the shop up by name through search and keeps the products belonging to that seller, which usually recovers most of the shelf. Measured over 75 store reads: 72 came back with products, 3 did not. Search terms and collection URLs aren't affected. Those returned products on every one of 125 reads. If nothing at all comes back you get one uncharged BLOCKED row and pay nothing for the attempt.
If you'd rather the run retried such a page with a signed-in reader, put your own TikTok sessionid cookie into sessionCookies. It's optional and most people should leave it empty. A cookie is as good as a password for the account it belongs to, so use an account you're comfortable exposing, and expect it to stop working when you log out of that account.
What people use it for
- Product research. Pull a category, sort by units sold, see what's actually moving before you commit to stocking it. Rating and review count sit on the same row, so you can filter out the one-review listings.
- Shelf tracking. Feed in a store URL and get that seller's whole shelf with prices, discounts and sold counts. Re-run on a schedule and diff on
productId. - Price monitoring.
price,originalPriceanddiscountPercentare numbers, so a daily run turns straight into a price history without any parsing. - Affiliate sourcing. Find high-sold, well-rated products in a niche and jump to the shop behind each through
shopUrl. - Promo research.
promotionLabelsshows which listings are running flash sales right now, which is a decent proxy for what a seller is pushing.
Reading the output
- Real rows carry
"charged": trueand"recordType": "product". One billed event each. - The sample row carries
"_sample": trueand"charged": false. There's exactly one, only when the input had no terms and no URLs. - Diagnostic rows carry
"_diagnostic": true,"charged": falseand anerrorCode:NO_RESULTSwhen a term or shop returned nothing,NOT_FOUNDwhen the URL or seller id doesn't exist,BAD_INPUTwhen a URL isn't a TikTok Shop page this Actor understands,NETWORKwhen the target couldn't be reached,TIME_BUDGETwhen time ran out. Each carries plain-English text and the target it belongs to.
Filter on charged == true and you have exactly the rows you paid for.
Which URLs work
| You paste | What you get |
|---|---|
https://shop.tiktok.com/us/k/probiotic-sodas | the collection page's products, paged until maxItems |
https://www.tiktok.com/shop/store/bk-beauty-brushes/7495182121564604692 | that shop's catalogue, in the shop's own order |
https://www.tiktok.com/shop/s/makeup%20brush | the same as putting makeup brush in searchTerms |
7495182121564604692 | a bare seller id, treated as a store |
A single product page URL isn't a valid target. This returns lists of products, and a product page would be a list of one. Paste the shop URL from the product page instead, or search for the product name.
Limits
- This reads the US storefront. TikTok decides which catalogue to serve from where the request comes from, and the addresses this Actor uses land in the US. For another storefront, supply your own proxy servers exiting in that country through
proxyUrls. Theregionfield on every row tells you which storefront actually answered. - The per-unit inventory count isn't published on the product listing surface, so
stockStatusis null for most rows. It's filled in only where the listing itself says something definite. - A single product page URL isn't a supported target.
sortByapplies to search terms and collection URLs. A store page comes back in the order the shop arranges its own shelf, which the site doesn't let you re-sort.- Prices, ratings, review counts and sold counts are a snapshot at read time. They move, sometimes hourly on a flash sale.
- Search depth isn't unlimited. TikTok stops handing out more pages for a term after a few hundred products, and when it does the run stops rather than repeating rows. Narrow the term, or add more terms, to go wider.
brandis only present when the seller filled it in, which is roughly four listings in ten.- Product descriptions, variant and SKU prices, shipping cost, delivery estimates and individual reviews aren't part of a listing row.
- Hard ceilings: 5,000 rows and 20 targets per run.
- Image URLs are TikTok CDN links carrying an expiry, so download anything you want to keep rather than hot-linking it.
Questions
What happens if a term matches nothing?
One uncharged diagnostic row for that target with errorCode: "NO_RESULTS", and the run carries on.
Do I need a TikTok account, a cookie or an API key?
No. There's no API key anywhere in this and you don't have to supply a cookie. Runs read the same public feed a logged-out visitor sees.
So what is sessionCookies for?
The minority of shop pages TikTok puts behind a bot check for logged-out visitors, plus a rate limit nobody else shares if you're running heavily. Optional, and most people should leave it empty.
Do I need a proxy?
No. The run brings its own egress and its cost is already inside the price. proxyUrls exists only for callers who want traffic to leave through servers they already own, for example to reach a storefront in another country.
Will the run fail if something goes wrong?
No. A blocked, empty or broken target produces an uncharged diagnostic row and the run still finishes as succeeded. A failed run would still bill the start fee, which would mean paying to be told something went wrong.
How do I get the best sellers in a category?
Put the category as a search term, or paste a collection URL, set sortBy to best_sellers, and read the soldCount column. That's the ordering TikTok itself uses for its ranking pages.
Can I run it on a schedule?
Yes. Nothing is held between runs. Use productId to work out which rows are new and to diff prices since last time.