# TikTok Shop Scraper (Exact Sold Counts, No Login) (`locaihost/tiktok-shop`) Actor

Scrape TikTok Shop products with a category filter, by keyword, category, store or product link: price, discount, exact sold count, units sold since your last run, rating, reviews and variants with stock. US and UK shops. Filtered-out products are never charged. No login. $1 per 1,000 products.

- **URL**: https://apify.com/locaihost/tiktok-shop.md
- **Developed by:** [locaihost data](https://apify.com/locaihost) (community)
- **Categories:** E-commerce, Social media, Automation
- **Security:** Limited permissions
- **Stats:** 9 total users, 7 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.55 / 1,000 products

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 (Exact Sold Counts, No Login)

Get TikTok Shop products from the US and UK shops by keyword, category, store or product link. Each product is one row with price, discount, exact sold count, rating, review count and shop, plus the units sold since your last run. You can keep only the categories you pick. Export as JSON, CSV or Excel. No login, no cookies.

What people use it for:

- Finding products that are selling now. Schedule a daily run and sort by units sold since yesterday.
- Sizing up a niche before stocking it: price range, sold counts and ratings for the products on a keyword or category page.
- Watching a competitor's store. A store link returns its products with sold counts, so you see which items move.
- Choosing products to promote as an affiliate. Filter by price, rating and units sold, and pay only for the products that pass.

### Quick start

Paste this into the **JSON** tab of the input and click **Start**:

```json
{"keywords": ["lip gloss"], "urls": ["https://shop.tiktok.com/us/c/makeup/848648"], "maxProductsPerSource": 5}
```

You get 10 products (5 from the keyword, 5 from the category) in about 30 seconds. Raise `maxProductsPerSource` (30 by default) to take everything the page shows.

### Input

| Input | What it does |
|---|---|
| `keywords` | Search phrases, read from TikTok Shop's own keyword pages (US shop). |
| `urls` | Product, store, category or keyword links, or bare product ids. |
| `categories` | TikTok Shop's top-level categories (`beauty-personal-care`, `phones-electronics`, ...). On their own they are read as category pages; with keywords or links they filter the products. See **Filter by category**. Off by default. |
| `country` | `US` (default) or `GB` for keywords, categories and bare product ids. Links keep their own country. |
| `maxProductsPerSource`, `maxProducts` | Products per keyword, store or category page (30 by default), and per run (500 by default). |
| `includeDetails` | Open each product's own page for variants, stock, category path, specifications and shop stats. Same price. |
| `onlyNew`, `onlySold` | For daily schedules: only products not returned before, or only products that sold since the last run. |
| `minPrice`, `maxPrice`, `minRating`, `minSoldCount` | Filters on the product's own values. |

### Output

| Group | Fields |
|---|---|
| Product | `productId`, `title`, `url`, `imageUrl`, `brand`, `labels` (TikTok's promo labels such as "Flash sale", "Free shipping"), `market`, `status`, `detailLevel` (`listing` or `full`) |
| Price | `price`, `priceMax`, `originalPrice`, `discountPercent`, `currency` |
| Sales | `soldCount` (exact lifetime units, not "54.3K"), `soldSinceLastRun`, `soldPerDay`, `previousSoldCount`, `previousCheckedAt` |
| Revenue estimates | `estRevenuePerDay`, `estRevenueSinceLastRun`, `estLifetimeRevenue` (estimates at today's price, see below) |
| Reviews | `rating`, `reviewCount`, `ratingBreakdown` (5 to 1 star counts, with full details) |
| Shop | `shopName`, `shopId`, `shopUrl`; with full details also `shopRating`, `shopReviewCount`, `shopFollowers`, `shopSoldCount`, `shopProductCount` |
| Full details | `variants` (each with price, stock and whether it can be bought), `variantCount`, `stockTotal`, `categoryPath`, `categoryId`, `specifications`, `description`, `images`, `freeShipping`, `shippingFee`, `deliveryDaysMin`, `deliveryDaysMax` |
| Source | `sourceType`, `sourceInput` (which keyword or link found it), `scrapedAt`, `rank` (position within that keyword or link) |

Full details come from each product's own page: turn on `includeDetails`, or give product links (they always get full details). Listing rows may already carry a few of these fields, such as `variantCount` and `freeShipping`, when the listing shows them.

One real row (US shop, keyword "lip gloss", run on 2026-10-18 by a task that also ran two days earlier, shortened):

```json
{
  "status": "ok",
  "productId": "1732023559119082090",
  "title": "Long-Lasting Moisturizing Lip Gloss Set, Non-Sticky Formula, High-Shine Glossy Finish...",
  "url": "https://shop.tiktok.com/us/pdp/kisssomeone-long-lasting-moisturizing-lip-gloss-set-high-shine/1732023559119082090",
  "market": "US",
  "currency": "USD",
  "price": 14.01,
  "soldCount": 2023,
  "soldSinceLastRun": 12,
  "previousSoldCount": 2011,
  "previousCheckedAt": "2026-10-16T03:12:10.000Z",
  "soldPerDay": 5.7,
  "rating": 4.5,
  "reviewCount": 166,
  "shopName": "Lihe Supply Chain Fa",
  "shopUrl": "https://shop.tiktok.com/us/store/lihe-supply-chain-fa/8647191398868816490",
  "brand": "KissSomeone",
  "variantCount": 6,
  "sourceType": "keyword",
  "sourceInput": "lip gloss",
  "detailLevel": "listing"
}
```

`soldSinceLastRun` is null the first time a product is returned to you. From the next run on it holds the units sold in between, with `previousSoldCount`, `previousCheckedAt` and `soldPerDay` next to it. A count that goes down (TikTok excludes cancelled and returned orders) is reported as 0 sold, never a negative number.

The dataset has four views (**Products**, **Sales since last run**, **Full details**, **Revenue estimates**) and exports to JSON, CSV, Excel or HTML. The run's `SUMMARY` record says how many products each filter left out and which pages TikTok refused.

### Pricing

You pay per product returned. There is no charge for Apify platform usage on top, and proxies are included. Full details cost the same per product.

| Row | Free and Starter | Scale | Business |
|---|---|---|---|
| Product | $1 per 1,000 | $0.75 per 1,000 | $0.55 per 1,000 |

Plus $0.00005 per run start. **Apify's free $5 monthly credit covers about 5,000 products.** Free-plan runs return up to 100 products per run; any paid Apify plan removes the cap.

**What's free:** keywords or links with no products, pages TikTok wouldn't show (including product links behind a puzzle check), products skipped by `onlyNew` or `onlySold`, products left out by a price, rating, sales or category filter (including products whose category TikTok won't show), and the same product found by two of your keywords or links (charged once per run). To cap a run's spend, set `maxProducts` or **Maximum cost per run** in the run options.

### Limits

- 5 to 30 products per page. The Actor reads what TikTok shows a logged-out visitor when the page opens: usually 25 to 30 per keyword and 10 to 20 per category or store. TikTok puts a puzzle check in front of its "load more" requests, and the Actor doesn't solve those, so it doesn't scroll. For more products, add more keywords (long-tail phrases work), sub-categories or stores.
- US and UK only. The UK shop has no keyword pages for logged-out visitors, so use `categories`, category links or store links there. The category list is the same in both shops. TikTok Shop in Singapore, Malaysia, Thailand, Vietnam, Indonesia, the Philippines, Japan, Mexico and Brazil shows logged-out visitors a puzzle check instead of any page. The Actor tries once and the run ends saying so, with nothing charged.
- Some product pages are not public. TikTok answers some product pages with a puzzle check for every logged-out visitor: about a quarter of US product pages in our tests (more in some niches) and most UK ones. Those products still come back with their listing data (price, sold count, rating, shop), just without the full details, and the run's message counts them.
- The category filter on keyword and store results reads each product's page. Keyword and store pages don't say which category a product is in, so the Actor opens each product's own page to check. Those runs are slower, and a product whose page TikTok keeps behind a puzzle check is left out (and not charged), since its category can't be checked. Products from category pages and category links are decided from the page itself, with no extra loads.
- `categories` takes top-level categories only (28 of them). For a narrower one, such as Makeup or Skincare, paste its category link into `urls`.
- Sold counts are TikTok's own and count all-time units across the shop.
- Speed: 6 pages load at a time at the default 2 GB memory. A listing page takes about 15 seconds; full details add one product page per product, so they are slower.
- No reviews or reviewer names, no buyer data, nothing behind a login.

### Filter by price, rating and sales

Find products worth stocking or promoting in one run, and pay only for those:

```json
{"keywords": ["lip gloss", "phone case"], "minPrice": 10, "maxPrice": 40, "minRating": 4.5, "minSoldCount": 1000}
```

- `minPrice` / `maxPrice`: in the shop's own currency (US dollars in the US shop, pounds in the UK shop).
- `minRating`: stars, 0 to 5. Products with no rating yet are left out.
- `minSoldCount`: all-time units sold, compared with the exact `soldCount` column.

A product outside a filter is left out before it is stored, so it is never charged. With `includeDetails` on, the listing's own values are checked first, so a product it already rules out costs no product-page load.

### Revenue estimates

Every row carries three revenue estimates, worked out from fields the row already has, at no extra cost:

| Field | Estimate |
|---|---|
| `estRevenuePerDay` | `price` × `soldPerDay` |
| `estRevenueSinceLastRun` | `price` × `soldSinceLastRun` |
| `estLifetimeRevenue` | `price` × `soldCount` |

They are **estimates at the current price**, in the shop's own currency. TikTok shows today's price, not what each unit sold for, so discounts, variant prices, returns and past price changes are not in them. Read `estLifetimeRevenue` as a rough size, not booked sales. An estimate is null when a value it needs is missing: `estRevenuePerDay` and `estRevenueSinceLastRun` start from the second run of the same task, like `soldPerDay`.

### Sort and rank

`sortBy` orders the products from each keyword, category, store or link:

- `soldCount`: most units sold first.
- `soldPerDay`: fastest sellers first (needs an earlier run of the same task; products without a figure go last).
- `price`: lowest price first.
- `rating`: highest rating first.

```json
{"keywords": ["lip gloss"], "sortBy": "soldCount", "maxProductsPerSource": 10}
```

The whole page is sorted before `maxProductsPerSource` applies, so a limit keeps the top products on the page, not the first ones. Products missing the sort value go last. Every row also gets `rank`: 1, 2, 3 within the keyword or link that found it, after sorting and filters. Without `sortBy`, rows keep TikTok's page order and `rank` follows it. Sorting happens within each source; rows from different keywords are not mixed. If a run stops early (time limit or charge limit), rows not yet delivered can come out in a second, separately sorted batch.

### Filter by category

Pick one or more of TikTok Shop's 28 top-level categories in `categories` (the **Categories** field in the form).

On its own, it reads each category's logged-out TikTok Shop page and returns the products TikTok shows there (10 to 20 per category):

```json
{"categories": ["beauty-personal-care", "health"], "country": "US"}
```

With keywords or links, it keeps only their products that are in one of the categories:

```json
{"keywords": ["phone case", "wireless earbuds"], "categories": ["phones-electronics"]}
```

How each product is checked:

- From a category page or category link: the page says which category it belongs to, so its products are kept or left out with no extra page loads.
- From a keyword or store page: those pages don't name a category, so the Actor opens each product's own page and reads its category path. The products that pass come back with full details (`categoryPath`, variants, stock) at the same price.
- A product whose category can't be read (TikTok keeps its page behind a puzzle check) is left out, since it can't be shown to match.

Products left out are never charged, and the run's message and `SUMMARY` record count them. If no product matches, the run ends with a message saying so and nothing is charged. Category names in the input can be the value (`beauty-personal-care`) or the plain name (`Beauty & Personal Care`).

### Only new since last run, and schedules

Save your input as a task and schedule it daily under **Schedules** in Apify Console. Each run compares every product's sold count with the last time that task returned it, so `soldSinceLastRun` is units sold in the last day, and the **Sales since last run** view sorts straight into a winners list.

- `onlySold: true` returns only products whose sold count moved since the last run, so a daily run charges you for the movers, not the whole list. Products seen for the first time are always returned.
- `onlyNew: true` returns only products this task has never returned before: new listings in your niche.

The memory is kept per saved task (runs without a task share one memory per account) and holds up to 100,000 products. Only products that were returned and charged are remembered.

### Integrations: API, n8n, Make and AI agents

**API.** Run it and get the rows back in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/locaihost~tiktok-shop/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keywords": ["lip gloss", "air fryer"], "minSoldCount": 1000}'
```

Apify's API clients for Python and JavaScript work the same way.

**n8n, Make, Zapier, Google Sheets, Slack, webhooks.** Apify's built-in integrations send each run's dataset wherever you need it, for example a daily sheet of the products that sold most since yesterday.

**AI agents (MCP).** Add this Actor to Claude, Cursor or any MCP client with `https://mcp.apify.com/?tools=locaihost/tiktok-shop`, then ask something like *"Which air fryers on TikTok Shop US have sold over 1,000 units and are rated 4.5 or higher?"*

### FAQ

#### How much does it cost to scrape TikTok Shop?

$1 per 1,000 products on the Free and Starter plans, less on Scale and Business, with full details at the same price. Apify's free $5 monthly credit covers about 5,000 products.

#### Can I use it through the API or from Python?

Yes. Use the `run-sync-get-dataset-items` call above, or Apify's Python and JavaScript clients. Every run's data is also available as JSON, CSV or Excel from its dataset.

#### Can I use it from an AI agent?

Yes. Through the Apify MCP server (`https://mcp.apify.com/?tools=locaihost/tiktok-shop`) any MCP client can call it with keywords or links and read the rows back.

#### Do I need a TikTok account?

No. The Actor never logs in and never uses cookies from an account.

#### Is it legal to scrape TikTok Shop?

The Actor reads public product, store, category and keyword pages the way a logged-out shopper sees them. It collects no personal data about buyers or reviewers and nothing behind a login. TikTok's terms restrict automated access, so check that your use fits them and the laws where you work. You are responsible for how you use the results.

#### Can I filter by category?

Yes. Pick TikTok Shop categories in `categories`: on their own they are read as category pages, and with keywords or links they keep only the products in those categories. Products outside them are not charged. See **Filter by category** above.

#### Why are some fields empty?

Listing rows (`detailLevel: "listing"`) don't have variants, stock, category, specifications or shop stats: turn on `includeDetails` for those. A product whose page TikTok keeps behind a puzzle check stays at listing level. `soldSinceLastRun` is null the first time a product is returned to you, and `originalPrice`/`discountPercent` are empty when there is no discount.

### More from locaihost data

- [TikTok Trends Scraper](https://apify.com/locaihost/tiktok-trends): top ads and trending hashtags by country, to see what's being promoted.
- [TikTok Creator Vetting](https://apify.com/locaihost/tiktok-creators): engagement rate and brand-deal share for creators who could sell your products.
- [Google Trends Scraper](https://apify.com/locaihost/google-trends): check whether demand for a product is growing in search too.

### Did it help?

If this saved you time, a quick rating on the Store helps other people find it.

### Support

Something not working, or a field you need? Open an issue on the **Issues** tab: we answer issues within 24 hours.

# Changelog

This Actor's version history is a separate document: https://apify.com/locaihost/tiktok-shop/changelog.md

# Actor input Schema

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

Products for a search phrase, as TikTok Shop's own keyword page shows them (usually 25 to 30 per keyword). US shop only: the UK shop has no keyword pages for logged-out visitors, so use category or store links there.

## `urls` (type: `array`):

Product, store, category or keyword links from shop.tiktok.com or www.tiktok.com/shop, or bare product ids. A store or category gives the products TikTok shows on that page (usually 10 to 20); a product link gives that product with full details. Repeats are read and charged once.

## `categories` (type: `array`):

Only products in these TikTok Shop categories. On its own, it reads each category's own TikTok Shop page (10 to 20 products each). With keywords or links, it keeps only their products in these categories: products from a category link are checked against that link's category, and products from keyword or store pages on their own product page (so they come with full details). Products outside the categories, or whose category TikTok won't show, are left out and not charged.

## `country` (type: `string`):

Which TikTok Shop to read keywords and bare product ids from. Links keep their own country (/us/, /gb/). The US and UK shops are open to logged-out visitors. The others show a puzzle check instead of their pages; we try once and say so, and never solve it.

## `maxProductsPerSource` (type: `integer`):

Most products to take from one keyword, store or category page. TikTok shows logged-out visitors 5 to 30 per page, so higher values return what the page has.

## `maxProducts` (type: `integer`):

The run stops after this many products. Each product is charged once per run, however many of your keywords or links show it.

## `includeDetails` (type: `boolean`):

Also open each product's own page for variants with stock, the category path, brand, specifications, the rating breakdown, delivery days and the shop's rating, followers and total sold. Same price per product; slower. Product links always get full details.

## `onlyNew` (type: `boolean`):

Skip products this saved task (or, without a task, your account) already received in an earlier run. Good for spotting new listings in a niche every day.

## `onlySold` (type: `boolean`):

Skip products whose sold count hasn't moved since you last received them, so a daily run returns (and charges for) only the movers. Products seen for the first time are always returned.

## `minPrice` (type: `number`):

Leave out products priced below this, in the shop's own currency (US dollars in the US shop, pounds in the UK shop). Products left out by any filter are not charged.

## `maxPrice` (type: `number`):

Leave out products priced above this, in the shop's own currency.

## `minRating` (type: `number`):

Leave out products rated below this many stars, e.g. 4.5. Products with no rating yet are left out too.

## `minSoldCount` (type: `integer`):

Leave out products with fewer units sold than this, e.g. 1000. Compared with the exact soldCount column, all-time sales across the shop.

## `sortBy` (type: `string`):

Order the products from each keyword, category, store or link: most units sold, most sold per day (needs an earlier run of the same task), lowest price first, or highest rating first. With a limit per source it keeps the top ones on the page. Leave empty for TikTok's own page order. Every row also gets a rank within its source.

## `proxyConfiguration` (type: `object`):

Apify Proxy by default. US pages start on datacenter proxies and switch to US residential only if TikTok pushes back. UK pages need a UK address, so they go through UK residential proxies. Residential exits are always pinned to the shop's country. Proxy costs are included in the price.

## Actor input object example

```json
{
  "keywords": [
    "lip gloss",
    "air fryer",
    "phone case"
  ],
  "urls": [
    "https://shop.tiktok.com/us/c/makeup/848648",
    "https://shop.tiktok.com/us/store/goddvenus-lashes/7495890306132577032",
    "https://shop.tiktok.com/us/pdp/1732285024262656776"
  ],
  "categories": [
    "beauty-personal-care"
  ],
  "country": "US",
  "maxProductsPerSource": 5,
  "maxProducts": 500,
  "includeDetails": false,
  "onlyNew": false,
  "onlySold": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One record per product: price, discount, sold count and sales since the last run, rating, shop, category, variants.

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

Pages read and what each returned, proxy tier, field-drift check and measured cost.

# 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": [
        "lip gloss"
    ],
    "urls": [
        "https://shop.tiktok.com/us/c/makeup/848648"
    ],
    "maxProductsPerSource": 5,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("locaihost/tiktok-shop").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": ["lip gloss"],
    "urls": ["https://shop.tiktok.com/us/c/makeup/848648"],
    "maxProductsPerSource": 5,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("locaihost/tiktok-shop").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": [
    "lip gloss"
  ],
  "urls": [
    "https://shop.tiktok.com/us/c/makeup/848648"
  ],
  "maxProductsPerSource": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call locaihost/tiktok-shop --silent --output-dataset

```

## MCP server setup

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

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/NZd4LEJX3IxSGrn2b/builds/ue8uR5Q5gAzjoftML/openapi.json
