# TikTok Ads Research Service (`diamade/tiktok-ads-research-service`) Actor

Research TikTok ads by product, topic, or verified competitor across 32 supported European markets.

- **URL**: https://apify.com/diamade/tiktok-ads-research-service.md
- **Developed by:** [Diamade Group LLC](https://apify.com/diamade) (community)
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## 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 Research Service

Find the ads, messages, advertisers, markets, hashtags, calls to action, and landing
pages that matter to your research — without turning a public ad library into a
spreadsheet-cleaning project.

Use **Product / Topic** to study how a market is being advertised, or use **Specific
Competitor** to research ads belonging to a safely resolved advertiser or brand
group. Start with a real **Preview of up to 12 canonical ads with no result fees**,
then move to Full research when the result set is useful.

> TikTok Ads Research Service is an independent research tool and is not affiliated
> with or endorsed by TikTok.

### What can you use it for?

- **Explore a product or market topic.** Find materially relevant ads for a product,
  category, topic, or keyword across supported European markets.
- **Research a competitor.** Resolve the advertiser safely before collecting ads, so
  a similar company name is not silently treated as the competitor you meant.
- **Compare market activity.** Search one country, a selected group, or all 32
  supported countries while keeping the market provenance of each ad.
- **Study messaging and creative strategy.** Review ad copy, dates, audience signals,
  hashtags, calls to action, campaign goals, and destinations.
- **Prepare data for analysis or automation.** Export a clean Dataset or consume the
  same contract through the Apify API.

### The fastest way to start

1. Choose **Product / Topic** or **Specific Competitor**.
2. Enter the product, topic, keyword, brand, or advertiser name.
3. Select **Preview — up to 12 rows, no result fees**.
4. Choose one market for a quick first run, or keep all supported countries for broad
   coverage.
5. Run the Actor and open **Research report** for the readable overview or
   **Canonical ad results** for the Dataset.

Preview returns real results in the same core schema as Full research. It is a capped
sample, so its completeness is always marked `preview_only`. Apify platform usage may
still apply according to your Apify plan; Preview itself does not create successful
result or enrichment fees.

### Choose the right research type

#### Product / Topic

Use this for queries such as `running shoes`, `electric vehicles`, or `summer sale`.
With **Keep only materially relevant ads** enabled, the query must be a substantial
subject of the ad. If removing the query mention would leave the ad's purpose almost
unchanged, the ad is excluded as incidental.

Product / Topic research discovers relevant advertising. It does not claim that a
keyword match proves exact advertiser identity or that every historical ad is present
in the public archive.

#### Specific Competitor

Use this when you want ads that belong to a company or brand. A competitor can be a
verified brand cluster containing several related legal advertiser identities — for
example, regional entities belonging to the same brand. Each ad still retains the
specific advertiser identity that supplied it.

If the name matches unrelated advertisers and they cannot be safely joined, the run
does not guess. It returns a clear refinement step so you can choose the intended
competitor.

### Preview and Full research

| Mode | Best for | Depth |
| --- | --- | --- |
| **Preview** | Checking relevance and output quality before a larger run | Up to 12 canonical rows across the whole request; no result fees |
| **Full** | A requested research scope for export, analysis, or enrichment | Optional limit per country, or all source-available results in the date range |

Leaving **Maximum results per country** empty in Full mode requests all results that
the public source makes available. This can take longer and use more platform
resources, especially across many markets. For a first Full run, select one or two
countries and enter a modest limit.

### Dates and market coverage

Search all available history, or enter a From and To date. Both fields accept
`DDMMYYYY`, `DD.MM.YYYY`, `DD/MM/YYYY`, and `YYYY-MM-DD`. For the current end date,
use `recent`, `now`, or `today`. Invalid, impossible, future, and reversed ranges are
rejected before research begins, with a plain-language correction.

The launch scope covers 32 supported European markets. A fixed To date includes the
entire UTC day. `First seen`, `Latest seen`, and `Observed window` describe public
source observations; they do not prove uninterrupted activity between those dates.

### Optional value layers

#### Ad Detail

Detail enriches the same canonical row with successfully available destination, CTA,
campaign goal, targeting, and media information. You do not have to join a second ad
table. If Detail cannot be verified for an ad, the valid base row remains available
and its `detailStatus` explains what happened.

#### Advertiser Report

Available for Specific Competitor research. The report is country-scoped and returned
in a stable envelope. A successful country remains useful when another country has no
report data or is temporarily unavailable.

### What you receive

#### Readable result

Open **Research report** for an HTML overview of the run, its outcome, the useful
results, and any action you need to take next.

#### Canonical Dataset

Each accepted creative appears once, even when the source exposes it under several
ad IDs or in multiple countries. Source IDs, country observations, instance evidence,
and provenance are retained rather than overwritten. Exact duplicates are collapsed
before result limits and billing are applied. The Overview view contains 12 research
columns:

1. Advertiser
2. Ad message
3. Market
4. First seen
5. Latest seen
6. Estimated audience
7. Observed window
8. Hashtags used
9. Call to action
10. Campaign goal
11. Traffic destination
12. Audience targeting

#### Supporting outputs

- **Advertisers** — advertiser identities connected to returned ads.
- **Hashtag summary** — Unicode-safe hashtag counts derived from returned ad text.
- **Rejected candidates** — machine-readable exclusions for audit and support.
- **Run summary** — outcome, completeness, counts, warnings, and next action.
- **Run manifest** — normalized input and technical provenance for automation or
  troubleshooting.
- **Advertiser report** — optional country-scoped report for a verified competitor.

Native Dataset export supports JSON, CSV, Excel, XML, RSS, and other Apify formats.

### Result states you can act on

- `SUCCESS_WITH_RESULTS` — usable ads were delivered.
- `VALID_EMPTY` — the requested scope completed successfully but contained no usable
  rows.
- `PARTIAL_RESULT` — useful output exists, but part of the requested scope did not
  complete. The summary says what remains and what to retry.
- `BLOCKED_FAILURE` — the run could not produce a trustworthy result. It is never
  presented as an empty success.
- `INVALID_INPUT` — one or more fields need correction before research can begin.
- `TARGET_REFINEMENT_REQUIRED` — unrelated advertiser candidates were found; select
  the verified competitor you intended.

The Actor does not fail silently: every blocked, invalid, or partial run provides a
reason and a recommended next step in `SUMMARY.json` and the human-readable report.

### Common questions

#### Does this provide every TikTok ad ever published?

No. It researches the ads the public source makes available for the selected scope.
The Actor makes completeness explicit and never labels a source failure as “no ads”.

#### Is Product / Topic the same as exact competitor research?

No. Product / Topic finds materially relevant advertising about a subject. Specific
Competitor first establishes a trusted advertiser or brand-cluster identity.

#### What happens when one selected country has no data?

Useful results from other countries remain available. The summary identifies the
empty or unavailable country and, for a temporary source problem, recommends trying
that country separately later.

#### Are duplicate ads exported twice?

The default Dataset contains one canonical row per accepted creative. When the source
exposes that creative under several ad IDs or in several markets, the instances are
merged into that row. `sourceAdIds`, `adInstanceCount`, and `adInstances` preserve the
underlying evidence without charging or exporting duplicate customer rows.

#### Does a missing ad mean that it was deleted or stopped?

No. One absence can be caused by the selected window, market scope, filters, or public
source visibility. The debut research release does not present one missing observation
as proof that an ad was removed.

#### Is scheduled Watch / Delta monitoring included?

Not in this debut Store surface. Its independent baseline, comparison, notification,
and billing lifecycle is being completed separately so ordinary research runs cannot
silently create or change monitoring state.

### Support

Open `SUMMARY.json` first. It explains what completed, what did not, and what to do
next. If something does not work as expected, write to us through the Actor's Apify
support channel. We read every report and will respond as quickly as we can with a
practical answer, a fix, or a clear update.

If a missing feature would make the product more useful to you, tell us about it. We
cannot promise every request, but we may add it when it fits the product and can be
delivered reliably.

Please include the run link whenever possible. Never post passwords, API tokens,
identity documents, or other credentials in a support message.

### Release notes

See [CHANGELOG.md](./CHANGELOG.md) for customer-visible changes. The public release
will use bounded daily health checks to verify a non-empty Preview without turning a
maintenance test into an expensive Full run.

# Changelog

This Actor's version history is a separate document: https://apify.com/diamade/tiktok-ads-research-service/changelog.md

# Actor input Schema

## `researchType` (type: `string`):

Product / Topic finds ads where your subject is materially relevant. Specific Competitor safely resolves an advertiser or related brand cluster before collecting its ads.

## `query` (type: `string`):

Enter the phrase exactly as you want it researched, for example running shoes, electric vehicles, or Nike. For a competitor, use the clearest brand or legal advertiser name you know. The original text is preserved in the output.

## `resultMode` (type: `string`):

Preview returns up to 12 real canonical rows with no result fees. Full collects the requested depth and can take longer or use more platform resources.

## `relevantOnly` (type: `boolean`):

Used only for Product / Topic. An ad is kept only when the query is a substantial subject, not a passing mention. Turn this off only when you intentionally want broader source-defined matches. Specific Competitor uses verified advertiser membership instead and ignores this switch.

## `countryMode` (type: `string`):

All supported countries searches the current 32-market launch set. Selected countries is faster and easier to estimate for a first Full run.

## `countries` (type: `array`):

Used only with Selected countries. Leave this empty when All 32 supported countries is selected.

## `maxResults` (type: `integer`):

Full mode only. A number applies separately to each country. Leave empty for all source-available results in the date range; this may take substantially longer and use more platform resources. Preview always uses one global 12-row cap.

## `fromDate` (type: `string`):

Optional. Type DDMMYYYY, DD.MM.YYYY, DD/MM/YYYY, or YYYY-MM-DD. Leave empty to use all history the public source makes available (not a guarantee of archive completeness).

## `toDate` (type: `string`):

Optional and inclusive. Use the same date formats, or type recent, now, or today. Leave empty for the current run time.

## `detail` (type: `boolean`):

Optional value layer, OFF by default. Successful Detail adds destination, CTA, campaign goal, targeting, and media information to the same ad row. If Detail is unavailable, the valid base row remains and the status explains why.

## `advertiserReport` (type: `boolean`):

Specific Competitor only, OFF by default. Adds a country-scoped advertiser report. Results from successful countries remain available if another country has no data or a temporary source problem.

## `competitorClusterId` (type: `string`):

Advanced. Use only when a previous Specific Competitor run found unrelated advertisers and asked you to choose. Paste the returned verified cluster ID here, then rerun the same competitor query.

## Actor input object example

```json
{
  "researchType": "product_topic",
  "query": "running shoes",
  "resultMode": "full",
  "relevantOnly": true,
  "countryMode": "ALL_SUPPORTED_COUNTRIES",
  "fromDate": "01012026",
  "toDate": "recent"
}
```

# Actor output Schema

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

One canonical delivered ad per row.

## `advertisers` (type: `string`):

Advertiser identities and their related canonical ads and markets.

## `hashtags` (type: `string`):

Hashtags aggregated across the delivered canonical ads.

## `rejectedCandidates` (type: `string`):

Candidates excluded by identity, semantic relevance, or country validation, with reasons.

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

Outcome, completeness, counts, warnings, and actionable failure information.

## `report` (type: `string`):

Overview table and run context in HTML.

## `advertiserReport` (type: `string`):

Optional country-scoped Specific Competitor report envelope.

## `runManifest` (type: `string`):

Normalized input, source request telemetry, merge diagnostics, and output contract.

# 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 = {
    "researchType": "product_topic",
    "resultMode": "full",
    "relevantOnly": true,
    "countryMode": "ALL_SUPPORTED_COUNTRIES",
    "detail": false,
    "advertiserReport": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("diamade/tiktok-ads-research-service").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 = {
    "researchType": "product_topic",
    "resultMode": "full",
    "relevantOnly": True,
    "countryMode": "ALL_SUPPORTED_COUNTRIES",
    "detail": False,
    "advertiserReport": False,
}

# Run the Actor and wait for it to finish
run = client.actor("diamade/tiktok-ads-research-service").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 '{
  "researchType": "product_topic",
  "resultMode": "full",
  "relevantOnly": true,
  "countryMode": "ALL_SUPPORTED_COUNTRIES",
  "detail": false,
  "advertiserReport": false
}' |
apify call diamade/tiktok-ads-research-service --silent --output-dataset

```

## MCP server setup

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

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/fzyIqaxmJC92igT64/builds/iBbqFzo8LIeR7MvT9/openapi.json
