# TikTok Shop Scraper - Products, Sales & Shops (`jmlp/tiktok-shop-scraper`) Actor

Scrape TikTok Shop (US) products by keyword, store, category or product link. Get prices and discounts, sold counts, ratings, reviews, shops, brands, variants with stock, shipping and the TikTok video that sells each product. No login.

- **URL**: https://apify.com/jmlp/tiktok-shop-scraper.md
- **Developed by:** [Mary Lou](https://apify.com/jmlp) (community)
- **Categories:** E-commerce, Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $0.15 / 1,000 products

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

Scrape products from **TikTok Shop (US)**:

- search by keyword
- scrape whole stores
- crawl categories
- get full details for product links

For every product you get the price and discount, units sold, rating and
reviews, the shop, the brand, the badges, and the TikTok video that sells it.
Turn on details for:

- the description and all images
- every variant, with its price and stock
- specifications and the category path
- shipping and the seller's location
- the rating breakdown and top reviews

No login, no TikTok account.

***

### What you can do with it

- **Product research**: find what sells on TikTok Shop for a keyword or in a
  category, with units sold, ratings and reviews
- **Competitor and brand monitoring**: every product a store sells, with its
  prices, discounts and sales
- **Price and discount tracking**: run it on a schedule and compare
- **Dropshipping and sourcing**: seller locations, shipping times and fees,
  stock per variant
- **Creator and affiliate research**: the products alongside the TikTok
  videos that sell them, with plays and likes
- **Market analysis**: whole categories down to their smallest
  subcategories, with the shops behind them

***

### How to scrape TikTok Shop

**1.** Enter **Search keywords** (`phone case`, `stanley cup`), paste
**TikTok Shop links**, or both.

**2.** Optionally turn on **Scrape product details**.

**3.** Set **Max products**, then press Start.

```json
{
  "searchQueries": ["phone case", "led face mask"],
  "startUrls": [
    "https://shop.tiktok.com/us/store/goli-nutrition/7495794203056835079",
    "https://shop.tiktok.com/us/c/beauty-personal-care/601450",
    "https://shop.tiktok.com/us/pdp/1729527313880355335"
  ],
  "maxProducts": 500,
  "scrapeProductDetails": true
}
```

***

### What each input gives

| You give | You get |
| --- | --- |
| A search keyword | The products TikTok Shop's search finds for it, in its order: typically 150 to 250 |
| A store link | Every product the store has on sale |
| A category link | The category's top products, then each subcategory's, all the way down: hundreds to thousands for a top-level category |
| A product link or id | That product, with every detail |
| A keyword page link (`/us/k/...`) | Read as a search for its words |
| The home page (`shop.tiktok.com/us`) | Its featured products, then every category (just the categories when TikTok refuses the home page itself) |

`www.tiktok.com/shop/...` links, `tiktok.com/view/product/...` share links
and `vm.tiktok.com` short links all work. A product found by several
searches or links appears once.

***

### Output

One row per product. Export as **JSON, CSV, Excel, XML or RSS**. The
dataset has views for an overview, the shops, the promoting videos and the
product details.

```json
{
  "product_id": "1729527313880355335",
  "title": "Goli Ashwagandha & Vitamin D Gummy - Mixed Berry, KSM-66, Vegan, Plant Based, Non-GMO, Gluten-Free & Gelatin Free",
  "url": "https://shop.tiktok.com/us/pdp/ashwagandha-gummies-by-goli-ksm-66-mixed-berry-vegan-non-gmo/1729527313880355335",
  "price": 19.47,
  "original_price": 24.7,
  "discount": "21%",
  "currency": "USD",
  "rating": 4.5,
  "review_count": 94407,
  "sold_count": 1303951,
  "brand": "Goli",
  "labels": ["Free shipping"],
  "shop_name": "Goli Nutrition",
  "shop_url": "https://shop.tiktok.com/us/store/goli-nutrition/7495794203056835079",
  "shop_rating": 4.6,
  "shop_followers": 600953,
  "shop_sold_count": 5773064,
  "categories": ["Health", "Nutrition & Wellness", "Vitamins, Minerals & Wellness Supplements", "Vitamins Supplements"],
  "variants": [{"sku_id": "1729527298861535751", "options": {"Size": "1 Bottle"}, "price": 19.47, "stock": 337626, "available": true}],
  "shipping": {"fee": 0, "free": true, "min_days": 3, "max_days": 6, "service": "Standard shipping"},
  "rating_breakdown": {"1": 5778, "2": 1513, "3": 3727, "4": 7809, "5": 75580},
  "source_type": "store",
  "source": "Goli Nutrition",
  "position": 1,
  "has_details": true
}
```

| Field | Notes |
| --- | --- |
| `price`, `original_price`, `discount` | What a buyer pays now, the price before the discount, and the discount TikTok shows. `price_max` is the dearest variant's price |
| `sold_count`, `rating`, `review_count` | TikTok's own counts. Units sold are counted since the product was listed, minus returns |
| `shop_*` | The shop's name, page, logo, rating, followers, units sold and products on sale |
| `labels` | The badges on the product card: Free shipping, Flash sale, seasonal deals |
| `video` | The TikTok video shown with the product: link, caption, plays, likes, length and date posted |
| `source_type`, `source`, `position` | What found the product (search, store, category, home or product link), which one, and the product's rank in it |
| `description`, `images`, `specifications` | With details: the full listing |
| `variants`, `variant_options` | With details: every variant's options, price, stock and availability |
| `categories`, `category_id` | With details: the category path, top level first |
| `shipping`, `seller_location` | With details: fee, free or not, delivery days, service; the business address the seller declares |
| `rating_breakdown`, `top_reviews` | With details: reviews per star rating, and the reviews the product page shows first |

**Scrape product details** opens each product's own page, one extra request
per product. Product links always get them.

***

### Reliable on big runs

- **Inputs are read forgivingly.** Links in any of TikTok's forms, bare
  product ids and keyword pages all work. Anything that cannot be read is
  skipped with a note in the log, not the whole run.
- **Refusals are retried.** A refused request moves to a new IP. Searches,
  stores and categories still refused at the end get a second pass on a US
  residential proxy, and one that fails costs only itself.
- **No failed runs for blocks.** If TikTok refuses everything, the run ends
  normally and its status message says why.
- **Resumable.** Progress is saved every 30 seconds.

***

### FAQ

**Do I need a TikTok account?**
No. TikTok Shop's pages are public, and the scraper reads them as a
signed-out visitor.

**Which countries are covered?**
The US TikTok Shop. The other countries' shops do not serve their pages to
scrapers yet, so their links are skipped with a note.

**Why does a search stop at around 200 products?**
That is as far as TikTok Shop's search goes. For more, use more keywords or
more specific ones, or a category link. A product found twice is kept once.

**How many products does a category give?**
TikTok shows the first 10 to 20 products of each category. With **Include
subcategories** on, every subcategory adds its own, so a top-level category
gives hundreds to thousands of products.

**Which proxy should I use?**
The default: a US residential proxy. TikTok Shop answers US visitors only
and refuses many datacenter IPs. A proxy set to another country is switched
to the US.

**Can I run it on a schedule?**
Yes. Schedule the same input daily or weekly to track prices, discounts and
units sold.

***

### Related scrapers

- **TikTok Creative Center Top Ads Scraper**: TikTok's best-performing ads,
  with CTR, likes and landing pages
- **TikTok Ad Library Scraper**: every ad an advertiser ran in the EU and UK
- **Meta Ads Library Scraper**: Facebook and Instagram ads
- **Website Contact Scraper**: emails, phones and social profiles from any
  website

# Actor input Schema

## `searchQueries` (type: `array`):

What you would type into TikTok Shop's search, one per line: 'phone case', 'stanley cup', 'led face mask'. Each search pages through its results until TikTok has no more.

## `startUrls` (type: `array`):

Paste links straight from your browser: a product (shop.tiktok.com/us/pdp/...), a store (shop.tiktok.com/us/store/...) for all its products, a category (shop.tiktok.com/us/c/...) or a keyword page (shop.tiktok.com/us/k/...). www.tiktok.com/shop links, share links and bare product ids work too.

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

Stop after this many unique products across every search and link. Caps both runtime and cost. Empty means every product found.

## `maxProductsPerSearch` (type: `integer`):

Cap each search, store or category separately, so one big search does not use up 'Max products' alone.

## `scrapeProductDetails` (type: `boolean`):

Open each product's page for the description, all images, specifications, every variant with its price and stock, the category path, shipping, the rating breakdown, top reviews and the seller's location. One extra request per product. Product links always get them.

## `includeSubcategories` (type: `boolean`):

For a category link, also scrape each of its subcategories, all the way down. TikTok shows the first products of each category, so this is what makes a category link go deep.

## `maxConcurrency` (type: `integer`):

How many pages to load in parallel, 1 to 20, each on its own exit IP.

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

TikTok Shop's US pages answer US visitors only, and refuse most datacenter IPs. A US residential proxy is the default and what works; another country is switched to the US.

## `resume` (type: `boolean`):

Save progress every ~30s so a run that gets migrated or restarted by the platform picks up where it stopped, without repeating products.

## `continueFromLastRun` (type: `boolean`):

If your previous run with the same input was interrupted, scrape only what it missed. Products already collected stay in THAT run's dataset.

## Actor input object example

```json
{
  "searchQueries": [
    "phone case"
  ],
  "maxProducts": 100,
  "scrapeProductDetails": false,
  "includeSubcategories": true,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  },
  "resume": true,
  "continueFromLastRun": false
}
```

# Actor output Schema

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

One record per unique product.

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

How many products and shops were found, what each search, store and category gave, and whether anything was refused or not found.

# 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 = {
    "searchQueries": [
        "phone case"
    ],
    "maxProducts": 100,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("jmlp/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 = {
    "searchQueries": ["phone case"],
    "maxProducts": 100,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("jmlp/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 '{
  "searchQueries": [
    "phone case"
  ],
  "maxProducts": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call jmlp/tiktok-shop-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jmlp/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/DYL0ReEa9CNcRwPO4/builds/Cl2NiVf1Ad3afr5xw/openapi.json
