Arcadium Data Scrapers
Home / Guides / TikTok Shop Scraper

How to use TikTok Shop Scraper

Step by step: in the Apify Store, over the API, from JavaScript or Python, in n8n, and from AI agents through MCP or LangChain.

$22.50 per 1,000 products on the Free plan, down to $13.50 on higher plans (live Apify price on 2026-11-02).

1. In the Apify Store (no code)

  1. Open arcadium/tiktok-shop-products and sign in to Apify (a free account works).
  2. Fill in the input form. The fields below are the ones the example uses.
  3. Set a maximum cost per run in the run options if you want a hard cap.
  4. Start the run. Rows appear in the Output tab as they arrive.
  5. Export the dataset as JSON, CSV or Excel, or connect an integration.
Input fieldTypeDescription
startUrlsarrayProduct URLs or ids (https://www.tiktok.com/shop/pdp/1729541517648171786 or 1729541517648171786) give full product details. Store URLs (https://www.tiktok.com/shop/store/asterwood/7495384600901552906) read the store's products; category URLs (https://shop.tiktok.com/us/c/beauty-personal-care/601450) a sample of the category. Give at least one; no keyword search. Also accepted as url (pratikdani), productUrls / shopUrls (unseenuser), productIds, storeUrls or urls.
maxProductsPerUrlintegerProducts read per store or category URL, e.g. 20 (the default). A store page lists its first ~20 products; a category page shows a changing sample, which is reloaded until it stops adding new products. Also accepted as maxResults (0 = 500, the maximum) or maxProducts.
maxItemsintegerOptional cap on charged products for the whole run, e.g. 500. Empty means no cap beyond the per-URL limit. Also accepted as limit.

Example input:

{
  "startUrls": [
    "https://shop.tiktok.com/us/pdp/ghk-cu-peptide-serum-by-asterwood-collagen-boosting-hydrating/1729541517648171786"
  ],
  "maxProductsPerUrl": 20,
  "maxItems": 50
}

2. Over the Apify API

The synchronous endpoint runs the actor and returns its rows in one call (for runs up to about five minutes; use the asynchronous run endpoint for longer ones).

curl -X POST "https://api.apify.com/v2/acts/arcadium~tiktok-shop-products/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"startUrls":["https://shop.tiktok.com/us/pdp/ghk-cu-peptide-serum-by-asterwood-collagen-boosting-hydrating/1729541517648171786"],"maxProductsPerUrl":20,"maxItems":50}'

3. From JavaScript

// npm install apify-client
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('arcadium/tiktok-shop-products').call({
  "startUrls": [
    "https://shop.tiktok.com/us/pdp/ghk-cu-peptide-serum-by-asterwood-collagen-boosting-hydrating/1729541517648171786"
  ],
  "maxProductsPerUrl": 20,
  "maxItems": 50
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

4. From Python

# pip install apify-client
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("arcadium/tiktok-shop-products").call(run_input={
    "startUrls": ["https://shop.tiktok.com/us/pdp/ghk-cu-peptide-serum-by-asterwood-collagen-boosting-hydrating/1729541517648171786"],
    "maxProductsPerUrl": 20,
    "maxItems": 50,
})
items = client.dataset(run.default_dataset_id).list_items().items  # apify-client 3.x returns a Run object
print(items)

5. In n8n

Paste this node into a workflow (it is a plain HTTP Request node). Create a Header Auth credential with name Authorization and value Bearer <APIFY_TOKEN>; each returned row becomes one item for the next node.

{
  "nodes": [
    {
      "name": "Run arcadium/tiktok-shop-products",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        0,
        0
      ],
      "parameters": {
        "method": "POST",
        "url": "https://api.apify.com/v2/acts/arcadium~tiktok-shop-products/run-sync-get-dataset-items",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "{\"startUrls\":[\"https://shop.tiktok.com/us/pdp/ghk-cu-peptide-serum-by-asterwood-collagen-boosting-hydrating/1729541517648171786\"],\"maxProductsPerUrl\":20,\"maxItems\":50}",
        "options": {
          "timeout": 300000
        }
      }
    }
  ],
  "connections": {}
}

6. From an AI assistant (MCP)

Add Apify’s MCP server to Claude Desktop, Cursor, VS Code or any MCP client, limited to this actor:

{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com/?tools=arcadium/tiktok-shop-products",
      "headers": {
        "Authorization": "Bearer <APIFY_TOKEN>"
      }
    }
  }
}

More on the MCP page.

7. From LangChain

# pip install langchain-apify   (reads APIFY_API_TOKEN from the environment)
from langchain_apify import ApifyActorsTool

tool = ApifyActorsTool("arcadium/tiktok-shop-products")
rows = tool.invoke({"run_input": {
    "startUrls": ["https://shop.tiktok.com/us/pdp/ghk-cu-peptide-serum-by-asterwood-collagen-boosting-hydrating/1729541517648171786"],
    "maxProductsPerUrl": 20,
    "maxItems": 50,
}})
# or give `tool` to an agent: create_react_agent(llm, [tool])

Sample output

One row, from the example in the actor’s README. Long text is shortened and lists are cut to two items.

{
  "rowType": "product",
  "platform": "tiktok-shop",
  "productId": "1729397565453996295",
  "detailLevel": "full",
  "region": "US",
  "url": "https://shop.tiktok.com/us/pdp/tongue-scraper-2-pack-by-gurunanda-u-shaped-stainless-steel-with-case/1729397565453996295",
  "title": "GuruNanda Tongue Scraper (2 Pack) with Travel Case, 420 Medical-grade Stainless Steel Tongue Cleaner",
  "brand": "Gurunanda",
  "currency": "USD",
  "price": 19.49,
  "priceText": "$19.49",
  "soldCount": 54204,
  "rating": 4.6,
  "reviewCount": 3715,
  "ratingCounts": {
    "1": 134,
    "2": 56,
    "3": 175,
    "4": 503,
    "5": 2847
  },
  "categories": [
    "Beauty & Personal Care",
    "Nasal & Oral Care"
  ],
  "promotions": [
    "Free shipping"
  ],
  "variants": [
    {
      "skuId": "1729397565454061831",
      "options": {
        "Specifications": "Default"
      },
      "price": 19.49,
      "stock": 826,
      "purchaseLimit": 200,
      "available": true
    }
  ],
  "totalStock": 826,
  "shipping": {
    "freeShipping": true,
    "fee": 0,
    "originalFee": 5.99,
    "deliveryMinDays": 4,
    "deliveryMaxDays": 7,
    "fulfilledByTikTok": true,
    "shipFrom": "local"
  },
  "seller": {
    "sellerId": "7495134783373216007",
    "name": "GuruNanda LLC",
    "rating": 4.5,
    "soldCount": 6413926,
    "productCount": 129,
    "followers": 278606,
    "badge": "OFFICIAL SHOP",
    "businessName": "GuruNanda LLC"
  },
  "aiKeywords": [
    "tongue scraper",
    "stainless steel tongue cleaner"
  ],
  "topReviews": [
    {
      "rating": 5,
      "text": "It's really good; it removes all the dirt, I give it a 10/10.",
      "createdAt": "2026-07-24T21:15:52.471Z",
      "variant": "Default",
      "country": "US",
      "verifiedPurchase": true,
      "incentivized": false,
      "imageCount": 6
    }
  ],
  "source": "product",
  "scrapedAt": "2026-10-22T10:34:19.179Z"
}
FieldWhat it holds
rowTypeKind of row. Filter on this first. 'product': one TikTok Shop product (charged; see detailLevel). 'error': an input could not be read; see code and message (free).
platformAlways 'tiktok-shop'.
productIdTikTok Shop product id (the long number at the end of the product URL).
detailLevel'full': read from the product page (charged as 'product'). 'card': TikTok did not serve the product page to an anonymous visitor, so the row holds only what the store or category card shows: title, price, originalPrice, discountPercent, soldCount, rating, reviewCount, seller id and name, one image (charged as 'product-card'; the other fields are null or empty).
regionMarket of the page: US or GB. Prices, stock and shipping are for this market.
urlCanonical product page URL on shop.tiktok.com.
titleProduct title as the seller wrote it.
descriptionProduct description (first 300 characters by default, full or none on request). Emails and phone numbers removed.
brandBrand from the product attributes; null when the seller set none.
currencyCurrency code of every price in the row, e.g. USD or GBP.
priceLowest current variant price (after discounts), in currency.
maxPriceHighest current variant price; equal to price for single-variant products.
originalPriceLowest variant price before discounts; null when nothing is discounted.
discountPercentDiscount of the lowest price against originalPrice, in percent; null without a discount.
priceTextPrice as displayed on the page, e.g. "$21.99 - 82.99".
soldCountItems sold since the product was listed, all markets (TikTok's own counter, excluding returns).
ratingAverage product rating, 1 to 5; null without reviews.
reviewCountNumber of product reviews.
ratingCountsReviews per star, e.g. {"5": 5366, "4": 664, "3": 294, "2": 101, "1": 326}.
categoriesCategory path from top level to leaf, e.g. ["Beauty & Personal Care", "Skincare", "Serums & Essences"].
categoryIdId of the leaf category (usable in shop.tiktok.com/us/c/<name>/<id> URLs).
promotionsPromotion labels shown on the page, e.g. "Flash sale", "Free shipping".
imagesProduct image URLs (first URL of each image).
hasVideoTrue when the product page has a product video.
videoDurationSecLength of the product video in seconds; null without video.
specificationsProduct attributes, e.g. [{"name": "Brand", "value": "Asterwood"}].
variantsPurchasable variants (SKUs): skuId, options (e.g. {"Size": "1oz"}), price, originalPrice, discountPercent, stock, purchaseLimit, available.
totalStockSum of variant stock as the page states it; null when no variant states stock.
inStockTrue when at least one variant can be bought now; null on card rows.
shippingDefault delivery option for the market: freeShipping, fee, originalFee, currency, deliveryName, deliveryMinDays, deliveryMaxDays, deliveryWindow, fulfilledByTikTok, shipFrom.
sellerThe shop as a business: sellerId, name, url, rating, soldCount, productCount, reviewCount, followers, videoCount, badge (e.g. "OFFICIAL SHOP"), businessName (legal company name, only when it is clearly a company). No owner or creator account.
aiTitleShort product title generated by TikTok for search.
aiKeywordsSearch keywords generated by TikTok for the product.
topReviewsThe reviews shown on the product page (up to 5): reviewId, rating, text (emails and phones masked), createdAt, skuId, variant, country, verifiedPurchase, incentivized, imageCount. Never reviewer names or photos.
sourceHow the product was found: 'product' (given directly), 'store' or 'category'.
inputThe URL or id from the input that led to this row.
sourceRankPosition on the store or category page (1-based); null for products given directly.
scrapedAtISO datetime when the row was read.
codeError rows only: invalid_input, not_found, blocked, unavailable or no_match.
messageError rows only: what went wrong, in plain words.

Schedule it

In Apify Console, create a Task from your input and add a Schedule (for example daily). Each run writes a new dataset; integrations can push the rows to Google Sheets, Slack, a webhook or your database.