# TikTok Shop Scraper with Sold Counts (`wheaten_steelpan/tiktok-shop-scraper`) Actor

Scrape TikTok Shop products with real sold counts: keyword search, bestseller lists, full product details with SKUs and stock, and store catalogues. Flat rows with price, discount, rating, reviews, seller and units sold. Pay per row, no start fee; failed inputs are free.

- **URL**: https://apify.com/wheaten_steelpan/tiktok-shop-scraper.md
- **Developed by:** [Vanja V](https://apify.com/wheaten_steelpan) (community)
- **Security:** Limited permissions
- **Stats:** 12 total users, 8 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 product rows

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## TikTok Shop Scraper with Sold Counts

Get TikTok Shop products with the units sold that TikTok Shop reports, as flat rows: keyword search, bestseller lists, full product pages with SKUs and stock, and whole store catalogues. Each row has the price, discount, rating, review count, seller and `soldCount`.

**$1.00 per 1,000 product rows** from search, bestsellers and stores, and **$3.00 per 1,000 product details**. No start fee, and inputs that fail cost nothing.

![Output rows: image, title, price, units sold, rating, reviews, discount, seller, brand and position for each product](https://api.apify.com/v2/key-value-stores/VT3JFtRN6QObhEIdW/records/output-example.png)

### What it's for

- **Find products that sell.** Rank a keyword's results or a bestseller list by `soldCount` before you source or list a product.
- **Watch competitors.** Pull a store's whole catalogue with sold counts, followers and rating, or check its listings every day.
- **Track sales over time.** Turn on *Track units sold since last run* and schedule the actor: each row gets the units sold since the previous run (see below).
- **Check variants and stock.** Product details list every SKU with its price, discount, stock count and image, plus the category path and shop stats.
- **Give an AI agent TikTok Shop data**, through Apify's MCP server or the API (examples below).

### What people use it for

- **TikTok Shop best sellers.** Pull the US or UK best-seller list, ranked by units sold, as a CSV or Excel file.
- **TikTok Shop product research.** Search a keyword and compare price, discount, rating and `soldCount` across the results.
- **TikTok Shop competitor analysis.** Export a store's whole catalogue with sold counts, followers and rating.
- **TikTok Shop sales tracker.** Schedule the actor and read `soldSinceLastRun` to see which products are speeding up.
- **TikTok Shop data for your own tools.** Send the rows to a spreadsheet, a BI dashboard or an AI agent through the API or MCP.

### Example: TikTok Shop best sellers export

Input:

```json
{
  "mode": "bestsellers",
  "bestsellersRegion": "US",
  "maxResults": 30
}
```

The first row of the US bestseller list on 5 October 2026 (image link shortened). The run returned 30 rows in 37 seconds:

```json
{
  "rowType": "product",
  "productId": "1729405526044283782",
  "title": "Renew Her Oil For Hydrated, Yummy, Glowing Skin",
  "url": "https://www.tiktok.com/shop/pdp/renew-body-oil-by-renew-hydrating-plant-based-formula-for-sensitive-skin/1729405526044283782",
  "image": "https://p16-oec-general-useast5.ttcdn-us.com/…/57c3e3c086704348b13438e1ed501a2b~tplv-fhlh96nyum-crop-webp:1080:1080.webp",
  "price": 22.03,
  "originalPrice": 39.99,
  "discountPercent": 45,
  "currency": "USD",
  "rating": 4.6,
  "reviewCount": 21362,
  "soldCount": 300940,
  "sellerId": "7495314676173147014",
  "sellerName": "Her Fantasy Box",
  "sellerUrl": "https://www.tiktok.com/shop/store/her-fantasy-box/7495314676173147014",
  "brand": "HER FANTASY BOX",
  "labels": ["Flash sale", "Fall Deals"],
  "videoUrl": null,
  "videoAuthor": null,
  "videoPlays": null,
  "videoLikes": null,
  "position": 1,
  "region": "US",
  "sourceMode": "bestsellers",
  "input": "all categories",
  "scrapedAt": "2026-10-05T06:06:08.682Z"
}
```

### Modes and markets: TikTok Shop search, best sellers, product details and stores

| Mode | Markets | You give it | You get |
|---|---|---|---|
| Search by keyword (`search`) | US | Keywords | One row per product found, in search order |
| Bestsellers (`bestsellers`) | US, UK | Nothing for the whole market, or category links or ids | One row per product, ranked by units sold, up to 100 per list |
| Product details (`product`) | US, UK | Product links or ids | One detailed row per product |
| Store catalogue (`store`) | US | Store links or seller ids | One summary row per store, then one row per product |

Any row's `sellerId` works as a store input, and any product detail's `categoryIds` work as bestseller categories.

### What you get: TikTok Shop product data as CSV, JSON or Excel

Every product row has:

| Field | What it holds |
|---|---|
| `productId`, `title`, `url` | The product's id, title and link |
| `image` | Main product image |
| `price`, `originalPrice`, `discountPercent`, `currency` | Current price as a number, the price before discount and the discount in percent where the listing shows them, and USD or GBP |
| `rating`, `reviewCount` | Average stars out of 5 and number of reviews |
| `soldCount` | Units sold, as TikTok Shop reports it |
| `soldSinceLastRun`, `hoursSinceLastRun` | Units sold since an earlier run saw the same product, and the hours in between. Present only when *Track units sold since last run* is on |
| `sellerId`, `sellerName`, `sellerUrl` | The store selling it |
| `brand`, `labels` | Brand where named, and badges such as *Free shipping* or *Flash sale* |
| `videoUrl`, `videoAuthor`, `videoPlays`, `videoLikes` | The TikTok video a search result is bound to, where search returns one. None of our test searches returned one |
| `position` | Rank in the search results or bestseller list |
| `region`, `sourceMode`, `input`, `scrapedAt` | Market, mode, the keyword, link or id the row came from, and when it was fetched |

Product details add `description`, `images`, `available`, `categories` and `categoryIds`, `attributes`, `skus` (each with `skuId`, `properties`, `price`, `originalPrice`, `discountPercent`, `availableQuantity`, `inStock` and `image`) and the shop's `shopSoldCount`, `shopFollowers`, `shopRating`, `shopProductCount` and `shopReviewCount`.

Store runs add one row per store with `rowType: "store"`: the store's name, link, logo, rating, review count, total units sold, product count, followers and video count.

The `SUMMARY` record in the run's key-value store lists every input with its status (`ok`, `no-results`, `partial`, `failed`, `unavailable`, `not-found`, `unsupported`, `invalid` or `not-scraped`), its row count and the reason when something went wrong. `unavailable` means the data service behind the actor didn't deliver, usually during one of its outages; nothing is charged and trying again a few minutes later usually works. The run's status message gives the same totals. A run that returns no rows because inputs were invalid or not found ends as failed. When the data service didn't deliver or every input came back empty, the run ends as succeeded and its status message says to try again: the service sometimes returns empty results during its outages.

Download the rows as CSV, Excel or JSON from the Output tab, or read them through the API. The Output tab has three views: *Products*, *Product details* and *Stores*.

### Input

| Field | Default | What it does |
|---|---|---|
| What to scrape (`mode`) | `search` | `search`, `bestsellers`, `product` or `store`. Fill in the section for that mode; the others are ignored. |
| Max products per keyword, list or store (`maxResults`) | 30 | Stop each keyword, bestseller list or store after this many products, up to 1,000. Bestseller lists hold at most 100. |
| Track units sold since last run (`trackSoldSinceLastRun`) | off | Adds `soldSinceLastRun` and `hoursSinceLastRun`. Free. |
| Search keywords (`keywords`) | | One US search per keyword. |
| Bestsellers market (`bestsellersRegion`) | `US` | `US` or `GB`. |
| Categories (`bestsellersCategories`) | whole market | Category links or ids, e.g. `https://www.tiktok.com/shop/c/beauty-personal-care/601450` or `601450`, one list each. |
| Products (`products`) | | Product links or ids, e.g. `https://www.tiktok.com/shop/pdp/…/1732714053565124892` or `1732714053565124892`. |
| Product market (`productRegion`) | `US` | `US` or `GB`. |
| Stores (`stores`) | | US store links or seller ids, e.g. `https://www.tiktok.com/shop/store/glowwinner-us/7496322034243111196`. |

Duplicate inputs are scraped once. Short `vm.tiktok.com` links don't work: open them in a browser and copy the full link.

### Track units sold over time: a TikTok Shop sales tracker

With *Track units sold since last run* on, the actor saves each product's `soldCount` and the time it read it. The next run that sees the same product fills in:

- `soldSinceLastRun`: today's `soldCount` minus the saved one.
- `hoursSinceLastRun`: hours between the two reads, to one decimal.

Schedule the actor daily or hourly on the same keywords, lists or stores to get a sales rate for each product. Both fields are empty the first time a product is seen.

- The counts live in a key-value store named `tiktok-shop-sold-history` in your own Apify account, shared by all your runs of this actor. Delete it to start over.
- Search and bestseller lists can lag the product page: in one test a listing showed 61 sold in search and 247 on its product page. So each kind of source (lists, product pages, store summaries) is compared only with itself.
- In tests, 20 of 36 products had a higher count 2 hours later (2026-10-04), and 22 of 31 a day later (2026-10-05). Every product with more than 1,000 sold moved within a day; about half of those under 1,000 did. Daily sales among products that moved ranged from 1 to about 3,200, median about 40.

### Pricing

| Event | Price | Charged for |
|---|---|---|
| Product row | $1.00 per 1,000 ($0.001 each) | Each product from search, bestsellers or a store |
| Product detail | $3.00 per 1,000 ($0.003 each) | Each product page in product details mode |

| Rows | Search, bestsellers, stores | Product details |
|---|---|---|
| 100 | $0.10 | $0.30 |
| 1,000 | $1.00 | $3.00 |
| 10,000 | $10.00 | $30.00 |

- Apify's platform usage is included, and there's no start fee.
- You pay for rows you get. Inputs that fail, find nothing or are invalid cost nothing; an input that stops partway is charged only for the rows it returned.
- The store summary row and sold-since-last-run tracking are free.
- To cap what a run can cost, set a maximum cost when you start it (`maxTotalChargeUsd` in the API). The actor stops once the cap is reached and lists the inputs it didn't get to in `SUMMARY` as `not-scraped`, free of charge.
- On Apify's free plan, a run stops after 100 products (10 in product details mode). The run ends normally with the rows it got, and the status message says it hit the free-plan limit, which the actor's developer set. Paid Apify plans have no limit beyond the maximum cost you set.

### Use it through the API: a TikTok Shop data API

Run it and get the rows back in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/wheaten_steelpan~tiktok-shop-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode": "search", "keywords": ["led strip lights"], "maxResults": 60}'
```

That call waits at most 5 minutes. For bigger runs, the Apify clients start the run and wait for it to finish.

JavaScript (`npm install apify-client`):

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('wheaten_steelpan/tiktok-shop-scraper').call({
    mode: 'product',
    products: ['https://www.tiktok.com/shop/pdp/1732714053565124892'],
    productRegion: 'US',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const sku of items[0].skus) console.log(sku.properties, sku.price, sku.availableQuantity);
```

Python (`pip install apify-client`):

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("wheaten_steelpan/tiktok-shop-scraper").call(run_input={
    "mode": "store",
    "stores": ["https://www.tiktok.com/shop/store/glowwinner-us/7496322034243111196"],
    "trackSoldSinceLastRun": True,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row.get("title") or row["sellerName"], row["soldCount"], row.get("soldSinceLastRun"))
```

### Use it from an AI agent (MCP)

Add Apify's MCP server with this actor as its tool, for example in Claude Desktop, Cursor or VS Code:

```json
{
  "mcpServers": {
    "tiktok-shop": {
      "url": "https://mcp.apify.com?tools=wheaten_steelpan/tiktok-shop-scraper"
    }
  }
}
```

Clients that support OAuth sign you in to Apify on first use. Other clients can send your token in a header: `"headers": { "Authorization": "Bearer <APIFY_TOKEN>" }`. The agent gets a tool that takes a mode and its inputs and returns the rows.

### Speed and limits

- The actor works on three inputs at a time, and rows appear in the dataset as each page arrives.
- Typical run times on Apify in our tests: a keyword with 30 rows 5–9 seconds, a store about 5, a product page about 5, a bestseller list 35 seconds to 2 minutes.
- Search pages hold up to 30 products and store pages up to 50. Some keywords return fewer pages than others, so a keyword can end below your maximum.
- Bestseller lists sometimes come back empty with "no best-seller data". The actor tries each list three times; a list that still fails is marked `unavailable` in `SUMMARY` and costs nothing.
- A product id that doesn't exist, or a product that was removed, comes back as `unavailable`, the same as during a data service outage. If one product keeps failing while others work, its listing is likely gone.
- Markets: search and stores cover the US; bestsellers and product details cover the US and UK. Other markets and product reviews aren't included. UK product pages and bestseller lists fail more often than US ones; failed items show as `unavailable` and cost nothing.

### FAQ

**Does TikTok Shop have an API? Why not use it?**
TikTok Shop has an official Open API, reached through an app registered in TikTok's Partner Center, with access granted by the sellers whose shops it manages. It is built for running your own shop. This actor reads public listings, so it needs no developer account, seller account or API key from TikTok, and it works on stores you don't own.

**How do I find best-selling products on TikTok Shop?**
Use the bestsellers mode. Leave the categories empty for the whole market or give category links. You get up to 100 products per list, ranked by units sold, for the US or the UK.

**How do I track TikTok Shop sales?**
Turn on *Track units sold since last run* and schedule the actor on the same keywords, lists or stores. Each row then carries `soldSinceLastRun` and `hoursSinceLastRun`. The counts are what TikTok Shop reports. In our tests about half of the products under 1,000 sold didn't change within a day.

**Can I export TikTok Shop products to CSV or Excel?**
Yes. Run the actor, open the Output tab and download the rows as CSV, Excel or JSON.

**Can I analyze a competitor's TikTok Shop store?**
Yes, in the store catalogue mode (US stores). Paste the store link or its seller id. You get one summary row for the store and one row per product.

**Do I need a TikTok account or an API key?**
No. The inputs are keywords, links and ids.

**Which countries does it cover?**
Search and stores cover the US. Bestsellers and product details cover the US and the UK.

**How much does it cost?**
$1.00 per 1,000 product rows and $3.00 per 1,000 product details. A 100-product best-seller list costs $0.10. Set a maximum cost on the run to cap spend.

**Can I run it from Python or JavaScript?**
Yes, see the API section above for curl, JavaScript and Python examples.

### Related Actors

- [Threads Scraper](https://apify.com/wheaten_steelpan/threads-scraper): Threads posts by keyword or profile, no login. Search it for what people say about a product or brand.
- [Instagram Reels Transcript Scraper](https://apify.com/wheaten_steelpan/instagram-reel-transcript-scraper): turns reel speech into text, for product and ad research on short video.

### Notes

- This actor reads public TikTok Shop listings and isn't affiliated with TikTok or ByteDance.
- Found a problem or need a field or market? Open an issue in the Issues tab.

# Actor input Schema

## `mode` (type: `string`):

Search: products matching keywords. Bestsellers: a market's best-selling products, ranked by units sold. Product details: full pages for product links or ids, with SKUs, stock, categories and shop stats. Store: a store's stats and product catalogue. Fill in the section for the mode you pick; the others are ignored. On Apify's free plan, a run stops after 100 products (10 in product details mode).

## `maxResults` (type: `integer`):

Stop each keyword, bestseller list or store after this many products. Search pages hold 30 products and store pages 50. Bestseller lists hold at most 100. Not used for product details. On Apify's free plan, a whole run stops after 100 products.

## `trackSoldSinceLastRun` (type: `boolean`):

Adds "Sold since last run" and "Hours since last run" to each row: the change in units sold since an earlier run of this actor saw the same product. Turn it on for scheduled runs. The counts are kept in a key-value store named tiktok-shop-sold-history in your account, shared by all your runs. Empty on a product's first run. Free.

## `keywords` (type: `array`):

One search per keyword in the US TikTok Shop, e.g. led strip lights. Each product found is one row.

## `bestsellersRegion` (type: `string`):

The market whose best-selling products you want.

## `bestsellersCategories` (type: `array`):

Category links or ids to rank within, one list each, e.g. https://www.tiktok.com/shop/c/beauty-personal-care/601450 or 601450. Leave empty for the whole market.

## `products` (type: `array`):

Product links or ids, e.g. https://www.tiktok.com/shop/pdp/…/1732714053565124892 or 1732714053565124892. One row each. Short vm.tiktok.com links aren't supported; open them and copy the full link.

## `productRegion` (type: `string`):

The market the products are sold in.

## `stores` (type: `array`):

US store links or seller ids, e.g. https://www.tiktok.com/shop/store/glowwinner-us/7496322034243111196. Any product row's seller id works. Each store gives one summary row (free) and one row per product.

## Actor input object example

```json
{
  "mode": "search",
  "maxResults": 30,
  "trackSoldSinceLastRun": false,
  "keywords": [
    "led strip lights"
  ],
  "bestsellersRegion": "US",
  "productRegion": "US"
}
```

# Actor output Schema

## `products` (type: `string`):

One row per product. Product-detail runs add SKUs, categories and shop stats; store runs add one store-summary row per store. Download as CSV, JSON or Excel from the Export button.

## `summary` (type: `string`):

What happened to each keyword, list, product or store: ok, no results, incomplete, failed, unavailable (the data service didn't deliver; try again later) or not scraped, with its row count and the reason.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keywords": [
        "led strip lights"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("wheaten_steelpan/tiktok-shop-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "keywords": ["led strip lights"] }

# Run the Actor and wait for it to finish
run = client.actor("wheaten_steelpan/tiktok-shop-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": [
    "led strip lights"
  ]
}' |
apify call wheaten_steelpan/tiktok-shop-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,wheaten_steelpan/tiktok-shop-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/4w4H1No6z1QNbhUWn/builds/MmgMo0oSZe5ElZ4vR/openapi.json
