# TikTok Shop Competitor Intelligence — Airtable Sync (`nexascout/tiktok-shop-intelligence-sync`) Actor

Monitor TikTok Shop US competitors in Airtable. Track product and SKU prices, keep observation history, and flag comparable changes. Connect your own Airtable base with an encrypted token. Includes a ready-to-copy dashboard template.

- **URL**: https://apify.com/nexascout/tiktok-shop-intelligence-sync.md
- **Developed by:** [NexaScout](https://apify.com/nexascout) (community)
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $12.00 / 1,000 verified product checks

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 Competitor Intelligence — Airtable Sync

Watch the TikTok Shop products that matter to you and keep a clean record of
their price, sales, reviews, and rating in Airtable — no code required.

This Actor reads a list of product pages you choose, then writes into the output
tables of your Airtable base:

- **Products** — one row per product (current price, sold count, reviews,
  rating, and SKU details).
- **Price History** — an append-only log of every observation, so you can see
  how a product changes over time.
- **Monitor Runs** — a record of every sync (success / partial / error) for
  auditing.
- **Market Signals** — actionable alerts: price drops and rises, sales spikes,
  review/rating changes, new products, and catalog changes.

The ready-made base template copies **six tables** into your workspace: two
onboarding/help tables plus the four output tables above (the four output
tables back the four dashboard pages). The Actor writes only to the four output
tables.

Your tables are updated **only when the Actor runs** — manually or on a schedule
you enable yourself. It does not run in the background and does not stay
"always up-to-date" on its own.

It **never invents a price**: if a listing only shows a range or an approximate
figure, that is stored as-is and never turned into a fake exact number.

***

### What you need before you start

1. **An Apify account** (free to start) —
   [sign up here](https://console.apify.com/sign-up?fpr=dcnqef).
   *That sign-up link is a partner link; if you use it we may earn a small
   commission, at no extra cost to you.*
2. **An Airtable account** (free) — [sign up at Airtable](https://airtable.com/signup).
3. **A copy of the ready-made base template** —
   [open the template and copy it into your own Airtable workspace](https://airtable.com/appZxz2pq0ZS8pVsJ/shrmmcVyJT2zvvRkH).
   This gives you the six tables (two onboarding tables plus the four output
   tables) with the right fields already set up.

### Try the prefilled preview

The Store input starts with **Preview only** enabled and a sample product URL
already in the **Product URLs** list. You can run it without Airtable
credentials to see real product results in the Apify dataset. **The normal
product-check and start fees apply.** This preview makes no Airtable requests or
writes. Replace the sample URL with your chosen products. To write to Airtable,
follow the setup below and turn preview off.

### Setup

The simple path is to paste product URLs — no IDs, labels, or JSON required.

1. Copy the base template into your own Airtable workspace (link above).
2. In Airtable, create a **personal access token (PAT)** scoped to *your copy*
   of the base, with the **`data.records:read` and `data.records:write`** scopes.
3. In Apify, open this Actor and fill in the input:
   - **Product URLs** — paste one TikTok Shop US product page URL per line
     (e.g. `https://shop.tiktok.com/us/pdp/…` or
     `https://www.tiktok.com/shop/pdp/…`). Current-format links are normalized
     to the US storefront; availability is checked during extraction. Only
     the US market is supported. Shortened links, seller/shop pages and
     explicit non-US storefront links are rejected
     before product fetching or Airtable writes.
   - **Airtable base** — paste the `app…` base ID or the full Airtable URL of
     *your* copy of the base. The Actor extracts the base ID for you.
   - **Airtable personal access token (PAT)** — paste your PAT. It is stored as a
     secret (encrypted at rest), used only at runtime, and never written to logs
     or to the dataset.
   - **Preview only** — turn this **off** to write to Airtable.
     If validation rejects an input after the Actor starts, the platform start
     fee may still apply; no product-check event is charged for rejected input.
4. Run the Actor. The first run records a **baseline** for each product; later
   runs compare against it and produce changes and alerts.

> **Airtable connection — OAuth is NOT YET AVAILABLE.** This Actor connects to
> Airtable with a personal access token (PAT) you paste yourself; there is no
> "Connect Airtable" OAuth button. A one-click Airtable OAuth connection is a
> possible future improvement but is not implemented yet.

#### Advanced: legacy watchlist (JSON)

If you already use the older JSON watchlist (or a saved task), it keeps working
unchanged. Do **not** fill in both **Product URLs** and the **Watchlist** at the
same time — the Actor refuses that combination so it never silently monitors
extra products. The legacy watchlist lives under **Advanced options**.

#### Save a private task and (optionally) schedule it

To re-run the same input without re-entering it:

1. Save this Actor as a **private task** (in Apify Console, create a task from
   this Actor with your input). The task keeps your input — including your token
   reference — private to your account.
2. If you want automatic refreshes, **you** can enable a schedule on that task
   (for example, daily). The Actor never schedules itself and never starts any
   recurring charge on its own; a schedule exists only once you enable it.

#### Legacy watchlist JSON format

For the advanced legacy path, each product is one entry:

```json
[
  {
    "watchId": "buyer-body-01",
    "url": "https://shop.tiktok.com/us/pdp/medicube-body-care-set-exfoliating-brightening-k-beauty/1732052189676081387",
    "label": "Body care set",
    "selectedSkuId": "1732606169427448043"
  },
  {
    "watchId": "buyer-balm-01",
    "url": "https://shop.tiktok.com/us/pdp/medicube-pdrn-pink-collagen-volume-multi-balm-anti-aging/1729508370969629931",
    "label": "PDRN Collagen Multi Balm",
    "selectedSkuId": "1732293572420341995"
  }
]
```

- `watchId` — any stable, unique ID you choose. **Keep it the same across runs**
  so history and baselines stay attached to the right product.
- `url` — the product page URL (US TikTok Shop).
- `label` — a short, human-friendly name.
- `selectedSkuId` *(optional)* — track one specific variant/SKU of a listing.

> The example URLs and SKU IDs above are illustrative only. Product
> availability and prices change continuously; these examples are **not** a
> guarantee that any product is available or that any listed price is current.

> Only the **US** TikTok Shop storefront is currently supported.

***

### How to read the results

- **First run = baseline.** The first time a product is seen, the Actor records
  its starting state. It does **not** produce change or trend signals from a
  single data point.
- **A change** (for example a price drop or rise) needs **two observations of
  the *same SKU*, at least 6 hours apart** (default minimum gap). A change in
  the set of SKUs on a page is reported separately as a *catalog change*, never
  as a price change.
- **A trend** needs **at least 3 comparable exact sold-count points spanning at
  least 24 hours** (defaults). Velocity and trend figures are estimates derived
  from changes in TikTok's cumulative sold counter between observations.
- **Default SKU price.** The grounded default-SKU price is taken from the
  source's explicit selection; when the source does not expose it, it is left
  empty rather than guessed. The **Min/Max** range reflects the range of
  *listed* variants/SKUs on the page — including variants currently listed as
  unavailable — and the starting/reference price is the lowest SKU, **not** the
  price you would necessarily pay at checkout. A single exact price is recorded
  only when the page gives one; otherwise the range is kept as-is.
- **"Sold" is cumulative, not revenue.** TikTok shows a running total of units
  sold. This Actor records that figure as-is. It is **not** revenue and **not** a
  per-period sales number.

### Airtable free plan

The Airtable **Free** plan allows **1,000 records per base** and **1,000 API
calls per workspace per month**. This Actor's API usage varies with the size of
your watchlist and the number of changed records, so the fixed example setup is
**not** guaranteed to stay within the free API-call limit — monitor your usage
if you track many products or run frequently. If your base grows beyond the
record limit you will need a paid Airtable plan. This Actor does not require,
and is not tied to, any particular Airtable plan or add-on.

### Cost

This Actor uses **pay-per-event pricing**. You pay a small fee only for the
product checks that actually succeed, plus a tiny platform start fee each run.

- **Product check — $12.00 per 1,000 checks ($0.012 each).** One check is billed
  per distinct product (and SKU) that the Actor successfully reads a *usable*
  metric from — an exact price, a price range, an exact sold count, a review
  count, or a rating. Failed, empty, or unreadable results produce **no
  product-check event** (that check is not billed), but the actor start fee
  below still applies to the run. A single listing counts as one check even if
  it is written to several output rows, and re-reading the same product within
  one run is de-duplicated to a single check.
- **Actor start — $0.00005 per started GB (minimum one)**, charged automatically
  once when the run starts (a standard Apify platform event). A 512 MB run still
  counts as one started GB, so the minimum start fee applies per run.
- **Platform usage** (Apify compute and memory for the run): standard platform
  usage is **included** — there is no additional usage fee on top of the event
  fees.

There is **no recurring subscription**. You are billed only when the Actor runs
(manually, or on a schedule you enable yourself) and only for the product checks
it actually performs. Result rows written to the output dataset or to your
Airtable base are **not** billed separately.

Worked examples (US storefront, one 512 MB run per day for 30 days):

| Watchlist | Product checks | Check fees | Start fees (30 runs) | **Total event fees** |
| --- | --- | --- | --- | --- |
| 10 products | 300 | $3.60 | $0.0015 | **$3.6015** |
| 50 products | 1,500 | $18.00 | $0.0015 | **$18.0015** |

Each distinct product/SKU you watch counts as one check per run. Your first run
records a **baseline** for each product — that is a real, billable useful check
(you received a usable observation). Change alerts and trends require multiple
comparable observations over time and are **not guaranteed**.

You can cap your spend per run with a **maximum total charge**
(`maxTotalChargeUsd`) in Apify; the Actor respects that cap and bounds its work
to the remaining budget, stopping early when the cap is reached. A failed check
or a duplicate observation can still consume some processing capacity without a
product-check event being billed. **Data-only mode** (results to the dataset
instead of Airtable) uses the same per-check pricing. **Dry runs** also bill
useful checks and save planned results to the dataset, without writing to Airtable.

### Advanced options

The default **`pdp`** data source needs no extra setup. Two optional sources
remain available for power users:

- **`apify-monitor`** — run a *separate* downstream monitor Actor for
  observation. ⚠️ **This is a different Actor with its own, separate fees that
  are NOT covered by this Actor's per-check price or its `maxTotalChargeUsd`
  cap.** You bring your own Apify token and are billed by that monitor Actor
  directly for whatever it charges. Use it only if you understand its separate
  pricing. (This Actor still bounds the watchlist it hands to the monitor to
  your product-check budget, so the monitor's input size is limited — but the
  monitor's own per-run charges are entirely separate.)
- **`inline`** — pass observations directly in the input.

Tuning knobs (alert thresholds, minimum gap, etc.) are available under the
advanced input fields; the defaults are sensible for most users.

### Privacy

Your Airtable PAT and Apify token are stored as secrets, **encrypted at rest**,
used only at runtime, and **never written to logs or to the dataset**. While the
token is in use it necessarily exists in the running process's memory; it is not
persisted, logged, or emitted anywhere else.

# Actor input Schema

## `productUrls` (type: `array`):

Paste one direct TikTok Shop product page URL per line. US shop.tiktok.com/us/pdp/… and current tiktok.com/shop/pdp/… links are accepted. Current links are normalized to the US storefront; product availability is checked during extraction. Shortened, seller, category and non-US storefront links are refused before product fetching or Airtable writes. A platform start fee may still apply after starting; refused input has no product-check charge.

## `airtableBaseId` (type: `string`):

Your Airtable base. Paste the app… base ID or the full Airtable URL of your copy of the template (the Actor extracts the base ID automatically). Never use the template's own base ID — use your own copy.

## `airtableToken` (type: `string`):

Your own Airtable personal access token. It must have the data.records:read and data.records:write scopes for your base copy only. Paste it here — it is stored as a secret and never logged or written to the dataset.

## `dataOnly` (type: `boolean`):

The prefilled Store input (a sample product URL list) runs a paid dataset-only preview without Airtable credentials. Turn this off to sync to your own Airtable base. Product-check pricing applies to previews.

## `adapter` (type: `string`):

How product data is collected. "pdp" (default) fetches each US TikTok Shop product page directly — no extra setup. "apify-monitor" and "inline" are advanced options.

## `watchlist` (type: `array`):

Advanced alternative to Product URLs. Each entry needs a stable unique watchId, a direct US product URL, and a short label. Optional selectedSkuId tracks one specific SKU of a listing. Do not provide this together with Product URLs.

## `inlineObservations` (type: `array`):

Used only with the inline data source. Advanced/testing only.

## `apifyToken` (type: `string`):

Only needed with the apify-monitor data source. Leave blank — your own Apify token is used automatically. Never logged.

## `monitorActorId` (type: `string`):

Only used with the apify-monitor data source. Leave as default.

## `region` (type: `string`):

Storefront region. Only US is currently supported.

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

Parallel workers for the apify-monitor data source only.

## `navigationTimeoutSecs` (type: `integer`):

Per-page navigation timeout for the apify-monitor data source only.

## `maxAttemptsPerProduct` (type: `integer`):

Maximum attempts per product for the apify-monitor data source only.

## `runTimeoutSecs` (type: `integer`):

Maximum time to wait for a monitor run to finish (apify-monitor only).

## `dryRun` (type: `boolean`):

Compute results without writing to Airtable. Useful for a first test.

## `minDeltaGapHours` (type: `number`):

Changes are only computed from repeated observations at least this many hours apart.

## `maxDeltaWindowHours` (type: `number`):

A baseline older than this many hours is treated as stale and never produces a change. Set to 0 to disable.

## `priceDropPercentThreshold` (type: `number`):

Raise an alert when a price falls by at least this percent.

## `priceRisePercentThreshold` (type: `number`):

Raise an alert when a price rises by at least this percent.

## `salesSpikePercentThreshold` (type: `number`):

Raise an alert when the sold count rises by at least this percent.

## `reviewSpikePercentThreshold` (type: `number`):

Raise an alert when the review count rises by at least this percent.

## `ratingChangeThreshold` (type: `number`):

Raise an alert when a rating moves by at least this many stars.

## `minVelocityGapHours` (type: `number`):

Sales velocity is only derived from two exact sold counts at least this many hours apart.

## `minTrendPoints` (type: `integer`):

A trend requires at least this many comparable exact sold counts.

## `minTrendSpanHours` (type: `number`):

A trend requires the series to span at least this many hours.

## `counterResetPercentThreshold` (type: `number`):

A sold-count decrease is treated as a counter reset or relisting, never a genuine sales drop.

## `newProductFloodThreshold` (type: `integer`):

When this many or more products are first seen in one run, new-product alerts are combined into a single summary.

## `velocityHotUnitsPerDay` (type: `number`):

Sold units per day that maps to a full sales-velocity sub-score.

## `maxSeriesPoints` (type: `integer`):

Maximum comparable history points kept per product for velocity and trend.

## Actor input object example

```json
{
  "productUrls": [
    "https://shop.tiktok.com/us/pdp/medicube-body-care-set-exfoliating-brightening-k-beauty/1732052189676081387"
  ],
  "dataOnly": true,
  "adapter": "pdp",
  "monitorActorId": "6EAxcKlzd0X1nb63D",
  "region": "US",
  "maxConcurrency": 1,
  "navigationTimeoutSecs": 45,
  "maxAttemptsPerProduct": 2,
  "runTimeoutSecs": 1800,
  "dryRun": false,
  "minDeltaGapHours": 6,
  "maxDeltaWindowHours": 720,
  "priceDropPercentThreshold": 5,
  "priceRisePercentThreshold": 5,
  "salesSpikePercentThreshold": 20,
  "reviewSpikePercentThreshold": 10,
  "ratingChangeThreshold": 0.5,
  "minVelocityGapHours": 6,
  "minTrendPoints": 3,
  "minTrendSpanHours": 24,
  "counterResetPercentThreshold": 50,
  "newProductFloodThreshold": 5,
  "velocityHotUnitsPerDay": 100,
  "maxSeriesPoints": 30
}
```

# Actor output Schema

## `results` (type: `string`):

The run's default dataset, including its sync and billing summary and any product preview records.

# 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 = {
    "productUrls": [
        "https://shop.tiktok.com/us/pdp/medicube-body-care-set-exfoliating-brightening-k-beauty/1732052189676081387"
    ],
    "dataOnly": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("nexascout/tiktok-shop-intelligence-sync").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 = {
    "productUrls": ["https://shop.tiktok.com/us/pdp/medicube-body-care-set-exfoliating-brightening-k-beauty/1732052189676081387"],
    "dataOnly": True,
}

# Run the Actor and wait for it to finish
run = client.actor("nexascout/tiktok-shop-intelligence-sync").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 '{
  "productUrls": [
    "https://shop.tiktok.com/us/pdp/medicube-body-care-set-exfoliating-brightening-k-beauty/1732052189676081387"
  ],
  "dataOnly": true
}' |
apify call nexascout/tiktok-shop-intelligence-sync --silent --output-dataset

```

## MCP server setup

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

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/tIMljKqrsd6dFm3yM/builds/6TzGNI7ZEZNQ1zVT5/openapi.json
