# TikTok Ads Monitor - New Competitor Ads Tracker (`seemuapps/tiktok-ads-monitor`) Actor

Track competitors' TikTok ads on a schedule and get only new ads each run: video creatives, ad copy, run dates and audience reach, with built-in dedupe.

- **URL**: https://apify.com/seemuapps/tiktok-ads-monitor.md
- **Developed by:** [Seemu Scraping](https://apify.com/seemuapps) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 new ads

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 Ads Monitor - New Competitor Ads Tracker

Track your competitors' TikTok ads on autopilot. Add the brands and keywords you care about, put the actor on a schedule, and every run returns **only the ads that are new** since the last check, with the video creative, ad copy, run dates and estimated audience reach. Duplicate checking is built in and free: ads you've already received are never output or charged again.

No login, no cookies, no TikTok account needed. Data comes from the public TikTok ad library.

### What you get

Every new ad is one row in the dataset:

- **Creative**: direct video URL, cover image and any additional images
- **Ad copy**: the ad text shown with the creative
- **Advertiser**: the advertiser's name as declared to TikTok, plus its stable advertiser ID (`advBizId`)
- **Ad library link**: a public link to the ad's TikTok ad library page
- **Run dates**: when the ad was first and last shown
- **Estimated audience reach**: TikTok's disclosed audience band (e.g. `10K-100K`), plus impressions and spend where TikTok discloses them
- **Monitoring fields**: which advertiser or keyword matched (`target`), `status` (`new`, `baseline` or `existing`), `isNew` and `detectedAt`

Each run also writes a **run summary** (the `OUTPUT` record in the Key-value store) with counts of ads checked, new ads found and rows output for every advertiser and keyword, so you can see at a glance which competitor launched what.

### Use cases

- **Competitor ad monitoring**: get alerted the day a rival launches a new TikTok campaign
- **Creative swipe file**: automatically collect every new TikTok ad creative in your niche
- **Messaging and offer tracking**: spot new promotions, product launches and positioning shifts
- **Agency client reporting**: run one monitor per client and send each a weekly list of new competitor ads
- **Market and trend research**: watch a keyword like `protein powder` to see every new advertiser entering a category

### How to use

1. Add one or more **Advertisers to monitor** (e.g. `Gymshark`) and/or **Keywords to monitor** (e.g. `protein powder`)
2. Leave **Only output new ads** on
3. Run the actor once. This first run records the ads that are currently live as your **baseline**. They're output with `status: "baseline"`, or turn on **Skip output on the first run** to record them silently and pay nothing per ad
4. Put the actor on a schedule (see below). Every later run outputs only ads that are new since monitoring started

#### Tips

- **Monitor ID** keeps separate memories of already-seen ads. Use one ID per client or project (e.g. `client-acme`) so monitors don't interfere. Change it to start over with a fresh baseline.
- To lock onto one exact advertiser, paste its ID from the TikTok ad library "See all ads" link after a pipe: `GYMSHARK LTD | 7647240890083328016`. Otherwise the best-matching advertiser is picked on the first run and remembered.
- **Max ads per advertiser/keyword** (default 50) limits how deep each check goes. Raise it for very active advertisers.
- Turn **Only output new ads** off to get every live ad each run, with `isNew` marking the fresh ones.

### Run it on a schedule

1. In Apify Console, open **Schedules** → **Create new**
2. Set how often to check, e.g. daily at 9:00 (`0 9 * * *`) or every 6 hours (`0 */6 * * *`)
3. Under **Actors**, add this actor and paste in the same input you used for your first run, including the same **Monitor ID**
4. Save. Each scheduled run picks up where the last one stopped

Daily checks suit most brands. Very large advertisers that launch dozens of ads a day are best checked every few hours.

### Get alerts in Slack, email or your own app

- **Slack**: on the actor's **Integrations** tab, add the Slack integration and post a message to a channel when a run succeeds. Link to the run's dataset so your team can open the new ads.
- **Email**: add the email integration on the **Integrations** tab to receive a message with the results after each run.
- **Webhooks, Zapier, Make or n8n**: add a webhook on the **Integrations** tab for the `Run succeeded` event. Your endpoint receives the run details, and the new ads are at the dataset items URL (`.../datasets/{defaultDatasetId}/items`). Skip runs with nothing new by checking `totals.output` in the `OUTPUT` summary record.
- **Google Sheets**: use the Google Sheets integration to append every run's new ads to a running sheet.

### Output format

Each dataset record:

```json
{
  "monitorId": "default",
  "target": "Gymshark",
  "targetType": "advertiser",
  "status": "new",
  "isNew": true,
  "detectedAt": "2026-10-01T05:31:44.265Z",
  "adId": "1876412004121618",
  "adLibraryUrl": "https://library.tiktok.com/ads/detail/?ad_id=1876412004121618",
  "advertiser": "GYMSHARK LTD",
  "resolvedAdvertiserName": "GYMSHARK LTD",
  "advBizId": "7647240890083328016",
  "adText": null,
  "imageUrl": null,
  "videoUrl": "https://library.tiktok.com/api/v1/cdn/...",
  "coverImageUrl": "https://p16-common-sign.tiktokcdn.com/...",
  "images": [],
  "adFormat": "2",
  "auditStatus": "1",
  "estimatedAudience": "10K-100K",
  "impressions": 0,
  "spend": null,
  "firstShownAt": "2026-10-01T00:01:49.000Z",
  "lastShownAt": "2026-10-01T00:01:49.000Z"
}
```

Run summary (`OUTPUT` in the Key-value store):

```json
{
  "monitorId": "default",
  "onlyNew": true,
  "totals": { "targets": 3, "adsScanned": 36, "newAds": 1, "baselineAds": 0, "output": 1, "errors": 0 },
  "targets": [
    { "target": "Gymshark", "targetType": "advertiser", "baseline": false, "adsScanned": 24, "newAds": 1, "pushed": 1, "stopReason": "no new ads on page" }
  ]
}
```

### How "new" is decided

An ad counts as **new** when it hasn't been output by this monitor before **and** TikTok first showed it on or after the day you started monitoring. Older ads that a check happens to come across for the first time are recorded quietly as `existing` and not output, so the "new" list contains real new launches, not old ads resurfacing. The monitor remembers up to the 5,000 most recent ad IDs per advertiser or keyword.

### Free plan limits

To keep the actor available to everyone, free runs are limited to:

- **25 ads and 3 brands or keywords per run**
- **1 run every 30 minutes**
- **3 runs per day**

If you hit a limit, the run finishes with a message explaining what happened and nothing is charged. Upgrade to a paid Apify plan to remove these limits.

A daily schedule fits comfortably inside these limits.

### Pricing

Pay-per-event:

- **Per new ad** output to your dataset. Ads you've already received, and ads skipped as already seen, are free.
- **A small fee per advertiser or keyword checked**, so a scheduled check that finds nothing new costs very little.

### FAQ

**Does the first run cost more?** The first run outputs the current live ads as a baseline (capped by **Max ads per advertiser/keyword**). Turn on **Skip output on the first run** if you only want ads launched from now on.

**Can I monitor many brands at once?** Yes. Add as many advertisers and keywords as you like; each one is checked and tracked separately.

**What happens if a run is cut short?** Ads already output are remembered, and anything not yet output is picked up by the next run.

# Actor input Schema

## `advertisers` (type: `array`):

Advertiser or brand names to watch, one per line, e.g. 'Gymshark'. To lock onto one exact advertiser, add its ID from the TikTok ad library 'See all ads' link after a pipe: 'GYMSHARK LTD | 7647240890083328016'.

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

Phrases to watch across all advertisers' ads, one per line, e.g. 'protein powder'. Every advertiser running a matching ad is covered.

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

When on (recommended for scheduled runs), each run outputs only ads that are new since monitoring started and have not been output before. When off, every ad found is output with an isNew flag.

## `skipBaselineOutput` (type: `boolean`):

The first run for each advertiser or keyword records the ads currently live as a baseline. Turn this on to record the baseline silently (no rows, no per-ad charge) so you only ever receive ads that launch afterwards.

## `monitorId` (type: `string`):

Name for this monitor's memory of already-seen ads. Use a different ID for each separate monitor (e.g. one per client) so they track new ads independently. Change it to start over with a fresh baseline.

## `maxAdsPerTarget` (type: `integer`):

Upper limit on ads checked per advertiser or keyword in one run (new ads when 'Only output new ads' is on). Also sizes the first-run baseline. Set 0 for no limit.

## `maxItems` (type: `integer`):

Upper limit on rows output across all advertisers and keywords in one run. Ads not output because of this limit are kept unseen and output on the next run. Set 0 for no limit.

## Actor input object example

```json
{
  "advertisers": [
    "Gymshark",
    "Duolingo"
  ],
  "onlyNew": true,
  "skipBaselineOutput": false,
  "monitorId": "default",
  "maxAdsPerTarget": 50,
  "maxItems": 500
}
```

# Actor output Schema

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

One ad per record. Fields: monitorId, target, targetType, status (new/baseline/existing), isNew, detectedAt, adId, adLibraryUrl, advertiser, resolvedAdvertiserName, advBizId, adText, imageUrl, videoUrl, coverImageUrl, images, adFormat, auditStatus, estimatedAudience, impressions, spend, firstShownAt, lastShownAt.

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

OUTPUT record in the default key-value store: totals plus per advertiser/keyword counts of ads scanned, new ads and rows output.

# 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 = {
    "advertisers": [
        "Gymshark",
        "Duolingo"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("seemuapps/tiktok-ads-monitor").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 = { "advertisers": [
        "Gymshark",
        "Duolingo",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("seemuapps/tiktok-ads-monitor").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 '{
  "advertisers": [
    "Gymshark",
    "Duolingo"
  ]
}' |
apify call seemuapps/tiktok-ads-monitor --silent --output-dataset

```

## MCP server setup

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

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/Y3LwXWrIZn53lqblh/builds/OGtsHuZi4WnZqUSXG/openapi.json
