TikTok Ads Library Dataset Monitor & Alerts avatar

TikTok Ads Library Dataset Monitor & Alerts

Pricing

from $10.00 / 1,000 completed monitor checks

Go to Apify Store
TikTok Ads Library Dataset Monitor & Alerts

TikTok Ads Library Dataset Monitor & Alerts

Monitor TikTok Ads Library exports for competitor changes. Detect new ads and verified changes to creatives, copy, CTAs, landing pages, targeting, reach and status. Use authorized Apify Datasets or JSON—no TikTok API key, browser, proxy or extractor lock-in; ready for schedules and webhooks.

Pricing

from $10.00 / 1,000 completed monitor checks

Rating

0.0

(0)

Developer

Vadim Bezrukov

Vadim Bezrukov

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

This Actor turns authorized ad exports into conservative, webhook-ready competitor alerts. It remembers the last successful state for every monitor and distinguishes a new observation from a verified change.

This Actor does not scrape or contact TikTok. Supply ad snapshots inline or by Apify Dataset ID. That keeps the monitoring contract stable when an upstream provider changes and lets you use a source you are authorized to use.

To try it, keep the prefilled one-ad sample and click Start. The run makes no external request, writes a BASELINE event plus a monitor-health row, and costs $0.0101.

Use from AI agents with MCP

Connect the public Actor directly at https://mcp.apify.com?tools=automa-flow/tiktok-ads-dataset-monitor. Ask your agent to compare an authorized complete ad snapshot with the previous successful state and act only on the Actor's verified change status.

How TikTok competitor ad monitoring works

  1. Run any TikTok Ads Library source you are authorized to use.
  2. Pass its complete Dataset—or your own JSON snapshot—to this Actor.
  3. The first successful run creates a baseline. Later complete runs emit only candidate or confirmed changes by default.
  4. Send confirmed event rows to Slack, email, Make, n8n, a sheet, or your own webhook workflow.

The result is a source-independent changefeed. You can replace an upstream extractor without replacing the alerting and state contract.

What you get

  • BASELINE on the first successful run, never a flood of fake new ads;
  • NEW_AD, creative, copy, CTA, landing-page, targeting, reach and status events;
  • CANDIDATE versus CONFIRMED verification;
  • optional corroboration from two independent snapshots for one monitor;
  • one explicit status row per monitor, including valid NOT_FOUND, PARTIAL and FAILED outcomes;
  • last-good KVS state that is not overwritten by failed or incomplete feeds;
  • stable IDs, normalized URLs, semantic fingerprints and previous values.

An ad disappearing from a result list never becomes AD_BECAME_INACTIVE. Inactivity requires an observed active: false value from a feed whose authoritativeStatus you explicitly enabled.

Who it is for

  • agencies receiving daily client/competitor ad exports;
  • performance marketing and creative-strategy teams;
  • users chaining an existing TikTok Ads Actor into a reliable monitor;
  • data pipelines that need an auditable changefeed rather than periodic dumps.

If you need this Actor to fetch TikTok itself, it is the wrong product. TikTok's official API requires approved access, while the public library currently restricts unapproved automated extraction. This Actor deliberately stays on the processing side of that boundary.

Quick start with an inline snapshot

{
"feeds": [
{
"monitorId": "nike-de",
"externalId": "nike",
"sourceName": "my-authorized-export",
"isComplete": true,
"priority": 10,
"observations": [
{
"adId": "123456789",
"adDetailsUrl": "https://library.tiktok.com/ads/detail/?ad_id=123456789",
"advertiserName": "Nike",
"title": "Example creative",
"description": "Example copy",
"callToAction": "SHOP_NOW",
"status": "active",
"destinationUrl": "https://example.com/product?utm_source=tiktok",
"videoUrl": "https://cdn.example/video/creative.mp4?expires=123",
"country": "DE"
}
]
}
],
"mode": "monitor",
"outputMode": "changesOnly",
"verificationMode": "safe",
"stateNamespace": "agency-client-a"
}

The first successful run emits BASELINE. If the next complete run contains a new ad, safe mode emits it as NEW_AD / CANDIDATE. The following consecutive complete run confirms it. Two independent feeds containing the same new ad ID confirm it immediately.

Monitor an Apify Dataset

Select the upstream run's Dataset and give that inventory a stable monitor ID:

{
"datasetIds": ["UPSTREAM_DEFAULT_DATASET_ID"],
"datasetMonitorId": "nike-de",
"datasetExternalId": "nike",
"datasetSourceNames": ["primary-export"],
"datasetIsComplete": true,
"mode": "monitor",
"outputMode": "changesOnly",
"verificationMode": "safe",
"stateNamespace": "agency-client-a"
}

A practical recurring workflow is:

upstream Task succeeds
-> webhook starts this Actor with resource.defaultDatasetId in datasetIds
-> confirmed event rows trigger Slack, email, Make, n8n or another webhook

Keep one logical advertiser/query inventory in each Dataset workflow. If an upstream Dataset contains several advertisers, split or transform it before this Actor; otherwise those ads would intentionally be treated as one inventory. The native Dataset picker grants this Actor read-only access only to the Datasets you select. Candidate rows can trigger an n8n/Make verification branch that runs a second source and calls this Actor again with both snapshots, so expensive corroboration stays on demand.

Do not schedule this Actor repeatedly against one immutable Dataset ID—that only rechecks the same snapshot. Schedule the upstream Task, then start this Actor from the upstream run's Succeeded integration so every check receives the new defaultDatasetId.

Dataset IDs must be supplied through the top-level datasetIds field. A legacy nested feeds[].datasetId cannot receive read permission under the Actor's limited-permissions policy, so that feed is returned as invalid with a migration hint while other inline feeds continue.

Dataset views intentionally show all rows because Apify view transformations do not filter records. In exports and integrations, select confirmed events with record_type = ad_event and verification_status = CONFIRMED, candidates with verification_status = CANDIDATE, and health rows with record_type = monitor_status.

Only mark datasetIsComplete: true when every selected Dataset completed its required pagination. For inline failures, send status: "FAILED" without observations. A valid complete zero-ad Dataset is NOT_FOUND; it is not FAILED and does not erase known ads.

Independent source verification

Select several Datasets for the same inventory and give them distinct source names in the same order:

{
"datasetIds": ["DATASET_A", "DATASET_B"],
"datasetMonitorId": "nike-de",
"datasetSourceNames": ["primary-export", "verification-export"],
"datasetIsComplete": true,
"verificationMode": "safe"
}

The first Dataset supplies the canonical observation. Other sources provide evidence. Inline feeds can override this ordering with priority. A new ad ID seen by two distinct sources is confirmed even if one source exposes fewer optional fields. A semantic change requires identical new normalized content from two sources or the same primary source on two consecutive complete runs.

Verification modes

ModeNew or changed dataDisappearance
safe (default)confirmed by two sources or two consecutive complete runsnever treated as inactive
fastone complete feed confirms immediatelynever treated as inactive

safe is recommended for alerts. fast is useful when the upstream already provides contractual completeness and correctness guarantees.

Compatible fields

The automatic normalizer recognizes common camelCase and snake_case fields, including:

  • adId, ad_id, source_id, or an ID in adDetailsUrl;
  • advertiserName, advertiser_name, or advertiser.name;
  • description, creativeText, text, ad_text;
  • callToAction, cta, call_to_action;
  • destinationUrl, landingUrl, landing_url;
  • videoUrl(s), imageUrl(s), coverImageUrl;
  • firstShownDate, lastShownDate, active, status;
  • countries, targeting, estimatedAudience, impressions.

A stable ad ID is mandatory. Rows without one make the feed PARTIAL; valid rows are reported in its diagnostics but cannot advance monitoring state. Signed media query parameters and common tracking parameters (utm_*, ttclid, gclid) do not affect fingerprints.

Output contract

Every Dataset contains:

  1. one monitor_status row per logical monitorId;
  2. zero or more ad_event rows.

Important fields:

record_type, source, source_id, source_url, scraped_at,
schema_version, fingerprint, external_id, monitor_id,
status, change_type, changed_fields, verification_status,
ad_id, advertiser_name, text, cta, active, landing_url,
media_ids, countries, targeting, reach, impressions,
source_metadata, previous, error

Example confirmed change row:

{
"record_type": "ad_event",
"monitor_id": "nike-de",
"source_id": "tiktok-ad:123456789",
"status": "SUCCESS",
"change_type": "CTA_CHANGED",
"changed_fields": ["cta"],
"verification_status": "CONFIRMED",
"ad_id": "123456789",
"advertiser_name": "Nike",
"cta": "SHOP_NOW",
"previous": {"cta": "LEARN_MORE"},
"source_metadata": {
"verificationReason": "same_source_consecutive_confirmation",
"candidateRuns": 2
}
}

source_metadata explains the decision: primary source, all sources that saw the ad, exact semantic matches, disagreements, candidate run count and the verification reason. Output is append-only and suitable as a webhook payload.

Automate schedules and webhooks

In the upstream Actor or Task, open Integrations, choose this Actor, set Start when to Run succeeded, and paste this input:

{
"datasetIds": ["{{resource.defaultDatasetId}}"],
"datasetMonitorId": "nike-de",
"datasetSourceNames": ["primary-export"],
"datasetIsComplete": true,
"mode": "monitor",
"outputMode": "changesOnly",
"verificationMode": "safe",
"stateNamespace": "agency-client-a"
}

Schedule the upstream Task daily or weekly. When this monitor succeeds, read its default Dataset and route rows where record_type = ad_event and verification_status = CONFIRMED. The monitor status row remains available for health checks even when no ad changed.

Use a distinct datasetMonitorId for each advertiser/query inventory and a stable stateNamespace for each client or workflow. Serialize overlapping runs for the same pair.

Run through the Apify API

curl "https://api.apify.com/v2/acts/automa-flow~tiktok-ads-dataset-monitor/runs" \
-X POST \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @input.json

Fetch result rows after the run succeeds:

curl "https://api.apify.com/v2/datasets/DATASET_ID/items?clean=true&format=json" \
-H "Authorization: Bearer $APIFY_TOKEN"

Use the same stateNamespace and monitorId on every scheduled run. Changing either starts a separate baseline.

Failure semantics

  • SUCCESS: at least one complete source produced usable ads;
  • NOT_FOUND: at least one complete source validly produced zero ads;
  • PARTIAL: data exists but no complete usable feed is available;
  • FAILED: no feed could be verified or read.

A failed secondary source does not disable a complete primary source. It sets coverageDegraded: true; safe mode still prevents uncorroborated changes from being confirmed immediately. Dataset read errors, invalid rows, declared-total mismatches and input limits never become an empty success.

State and limits

  • compact state lives in the named Apify KVS tiktok-ads-dataset-monitor-state;
  • each monitor has an isolated key derived from stateNamespace + monitorId;
  • one feed may contain up to maxItemsPerDataset rows (default 5,000, maximum 10,000);
  • a Dataset beyond the configured cap is PARTIAL, never truncated as success;
  • one state record is capped below 6 MiB; split very large inventories into country or advertiser monitors;
  • no historical database and no media archive are created.

How much does TikTok ads monitoring cost?

Pay per event keeps quiet recurring checks cheap and makes large snapshots proportional to the output actually delivered. Actor platform usage is included; your upstream data provider or extractor is billed separately.

EventPriceCharged for
monitor-check$0.01One status row for a complete usable monitor or snapshot inventory, including a valid zero-ad result
ad-event$0.0001Each delivered snapshot, baseline, unchanged, candidate, or confirmed ad_event row
Realistic runmonitor-checkad-event rowsActor charge
Complete zero-ad or quiet repeat check10$0.0100
Included one-ad first-run demo11$0.0101
Check with 10 delivered changes110$0.0110
100-ad baseline or snapshot1100$0.0200
1,000-ad baseline or snapshot11,000$0.1100

The formula is $0.01 × complete monitors + $0.0001 × delivered ad_event rows. Snapshot and all output modes also bill every delivered ad_event row, including UNCHANGED rows. Your upstream data provider or extractor is a separate cost.

PARTIAL, FAILED, invalid input, Dataset reads, normalization, duplicates, retries and internal work are not billed. There is no Actor-start charge. A valid complete zero-ad result costs one inventory check because it still produces a health row and a trustworthy NOT_FOUND outcome.

Set the run's maximum charge at or above the basket you expect. Delivery is atomic per monitor: if the remaining limit cannot cover one monitor's status and all of its event rows, that monitor emits one free BillingLimitReached status, keeps its previous state, and makes the run fail explicitly. Completed monitors earlier in the same batch remain delivered and saved.

The current price is the same for every Apify tier. The live Pricing tab is authoritative if prices change later.

This Actor processes data selected by the user. It does not grant rights to collect, store or redistribute the upstream data. Use only APIs, exports and Datasets you are authorized to use and review the upstream provider's terms.

The schema needs business-ad metadata, not viewer profiles, cookies or account credentials. Do not place access tokens or cookies inside observations. Media URLs are referenced, not downloaded, and may expire. The Actor is not affiliated with or endorsed by TikTok.

Frequently asked questions

Does this Actor scrape TikTok Ads Library?

No. It compares snapshots supplied by you or selected from Apify Datasets. Use an upstream source whose access and data terms permit your workflow.

How do I track new competitor TikTok ads?

Run the same complete advertiser or query inventory over time with a stable monitorId and stateNamespace. The first run creates a baseline; later runs emit NEW_AD candidates or confirmed events without re-emitting the full inventory in changesOnly mode.

Can an empty Dataset mark every known ad inactive?

No. A complete zero-ad snapshot becomes NOT_FOUND, while failed or incomplete inputs become FAILED or PARTIAL. Disappearance alone never marks an ad inactive; the source must explicitly report active: false and be declared authoritative for status.

Why are changes candidates before they are confirmed?

The default safe mode protects alerts from temporary upstream gaps and parser differences. A change is confirmed when two independent sources agree or the same complete primary source reports it on two consecutive runs. Choose fast mode only when one source already provides contractual completeness.

Can I replace the upstream TikTok Ads extractor later?

Yes. Keep stable ad IDs and monitor IDs, map the new provider's fields to any of the recognized aliases, and keep one stable primary source. The normalized output and last-successful-state contract do not depend on an extractor vendor.

Troubleshooting

SymptomWhat to check
PARTIAL / IncompleteFeedEnable the completeness field only after the upstream source finished every required page.
FAILED / DatasetReadFailedRe-select the Dataset in top-level datasetIds; do not use legacy feeds[].datasetId.
Every run creates a new baselineKeep both stateNamespace and the monitor ID unchanged between runs.
BillingLimitReachedRaise the run maximum to at least $0.01 + expected event rows × $0.0001 for that monitor.
Duplicate webhook alertsSerialize runs for the same monitor and deduplicate by monitor_id + source_id + fingerprint + change_type.
No Slack or email arrivesThis Actor creates alert-ready Dataset rows; connect them through an Apify integration, Make, n8n, or your webhook.

Offline verification

uv run python actors/tiktok-ads-dataset-monitor/scripts/local_run.py
uv run pytest actors/tiktok-ads-dataset-monitor/tests

The local example makes no network requests and shows three runs: baseline, new-ad candidate and consecutive confirmation.

Known limitations

  • upstream extraction quality and legality remain the user's/provider's responsibility;
  • optional fields cannot be compared when the current source omits them;
  • different providers may expose materially different semantics; keep one stable primary source and inspect sourceDisagreement;
  • authoritativeStatus is a user assertion, not something this Actor can prove;
  • monitoring begins when the first successful baseline is stored; no historical backfill is inferred;
  • this version sends no alerts itself—use Dataset integrations, schedules and webhooks;
  • overlapping runs for the same stateNamespace + monitorId are not supported; serialize them to avoid duplicate alerts or last-writer-wins KVS updates;
  • Dataset delivery and named-KVS state are separate Apify writes. If a rare state-save failure happens after rows were delivered, the run fails and the prior state remains; inspect the delivered Dataset before rerunning and use the stable deduplication key documented above.