# Ad Transparency Search: Google, Meta and TikTok Ads by Domain (`pistachio_implementation/ad-transparency-multi-library`) Actor

Search the Google Ads Transparency Center, Meta Ad Library and TikTok Ad Library by advertiser domain or name. Every ad comes back in one normalized table: dates, format, text, media, landing page, regions and library link.

- **URL**: https://apify.com/pistachio\_implementation/ad-transparency-multi-library.md
- **Developed by:** [Hay Equipos](https://apify.com/pistachio_implementation) (community)
- **Categories:** Marketing, Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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

## Ad Transparency Search: Google, Meta and TikTok Ads by Domain

Type a brand's website or name once. Get back every ad it runs in the **Google Ads Transparency Center**, the **Meta Ad Library** (Facebook, Instagram, Messenger, Audience Network) and the **TikTok Ad Library**, in one clean table with the same columns for every source.

Built for agencies, DTC brands and competitive intelligence teams who are tired of searching three ad libraries by hand and pasting the results into a spreadsheet.

### What it does

- Takes a list of advertiser **domains** (`nike.com`) or **names** (`Spotify`).
- Finds the matching advertiser in each library.
- Returns each ad as one row: library, advertiser, ad ID, first and last shown dates, format, headline, ad text, media links, landing page, regions, platforms and a direct link to the ad in the public library.
- Optional filters: one country and a date window.
- Writes a `SUMMARY` record to the key value store that shows, for each advertiser, how many ads each library returned and whether a match was found.

### Data sources, and how they are used

This actor only reads **public transparency libraries**, the pages that Google, Meta and TikTok publish so that anyone can see who is advertising. It never logs in, never uses cookies from an account, and never collects personal data about people. Requests are spaced out politely and retried with backoff when a library is busy.

| Library | Coverage | How it is read |
|---|---|---|
| Google Ads Transparency Center | Search, Display, YouTube and Shopping ads, worldwide | The public JSON endpoints behind adstransparency.google.com, no browser needed |
| Meta Ad Library | Facebook, Instagram, Messenger and Audience Network ads, worldwide | The public logged out Ad Library page, opened in a normal browser |
| TikTok Ad Library | Ads shown in the EU, EEA, UK, Switzerland and Turkey only (TikTok does not publish other regions) | The public logged out library.tiktok.com page, opened in a normal browser |
| LinkedIn Ad Library | **Not included.** | See the FAQ |

### Input

| Field | What it means |
|---|---|
| `advertisers` | Required. Domains or names, one per line. A Google advertiser ID (`AR` plus digits) or a Meta page ID (digits only) also works. |
| `sources` | Any of `google`, `meta`, `tiktok`. Empty means all three. |
| `country` | Optional two letter code such as `US`, `GB` or `DE`. Empty means all countries. |
| `dateFrom`, `dateTo` | Optional. Keeps ads whose shown period overlaps this window. |
| `maxAdsPerSource` | Cap per advertiser per library. Default 50, maximum 1000. |
| `strictMatch` | On by default. Keeps only ads whose advertiser name contains your term as a whole word, or, for a domain on Meta, whose link points to that domain. |
| `googleDetails` | Off by default. Adds every country a Google ad ran in, plus the YouTube link for video ads. One extra request per Google ad. |

Example input:

```json
{
  "advertisers": ["nike.com", "Spotify", "canva.com"],
  "sources": ["google", "meta", "tiktok"],
  "country": "DE",
  "dateFrom": "2026-08-01",
  "maxAdsPerSource": 20
}
```

### Output

One row per ad. The same fields for every library:

```json
{
  "source": "meta",
  "advertiserQuery": "shopify.com",
  "advertiserName": "Shopify",
  "advertiserId": "20409006880",
  "adId": "1238141341576372",
  "firstShown": "2026-01-13",
  "lastShown": "2026-08-09",
  "isActive": false,
  "formats": ["dco"],
  "title": "Get going and keep growing",
  "text": "When it's time to start your business, it's time for Shopify.",
  "mediaUrls": ["https://scontent.xx.fbcdn.net/..."],
  "landingUrl": "https://www.shopify.com/free-trial",
  "regions": ["US"],
  "platforms": ["facebook", "instagram", "messenger"],
  "libraryUrl": "https://www.facebook.com/ads/library/?id=1238141341576372",
  "extra": { "pageUrl": "https://www.facebook.com/shopify/", "ctaText": "Sign up", "caption": "shopify.com" },
  "scrapedAt": "2026-09-27T05:51:15.669Z"
}
```

A Google row:

```json
{
  "source": "google",
  "advertiserQuery": "nike.com",
  "advertiserName": "Nike Retail BV",
  "advertiserId": "AR18378488041124659201",
  "adId": "CR18038581305662242817",
  "firstShown": "2021-10-25",
  "lastShown": "2026-09-27",
  "formats": ["text"],
  "mediaUrls": ["https://tpc.googlesyndication.com/archive/simgad/6057781660182448484"],
  "regions": ["ES", "PT", "NL"],
  "platforms": ["google"],
  "libraryUrl": "https://adstransparency.google.com/advertiser/AR18378488041124659201/creative/CR18038581305662242817",
  "extra": { "advertiserDomain": "nike.com", "daysShown": 1758 }
}
```

What each library fills in:

| Field | Google | Meta | TikTok |
|---|---|---|---|
| First and last shown | yes | yes | yes |
| Format | text, image, video | image, video, carousel, dpa, dco | video, carousel, image |
| Headline and ad text | shown inside the image snapshot, not as text | yes | yes (caption) |
| Media URLs | image snapshot, YouTube link with `googleDetails` | images and videos | video and cover image |
| Landing URL | not published by Google | yes | not published in the list view |
| Regions | your country, or every country with `googleDetails` | countries when Meta lists them, else your country | your country |
| Active flag | no | yes | no |

### Pricing

Pay per event, no subscription:

- **$1.50 per 1,000 ads** returned ($0.0015 per ad).
- **$0.01 per advertiser resolved**, charged once per advertiser that is found in at least one library.

Example: 10 competitors with 50 ads from each of three libraries is 1,500 ads, so $2.25 plus $0.10, which is **$2.35**. You can cap spend with `maxAdsPerSource` and with the run's maximum charge setting; the actor stops cleanly when that limit is reached.

### Limits

- **TikTok covers Europe, the UK, Switzerland and Turkey only.** That is TikTok's own rule for its library. If you set another country, TikTok is skipped and the `SUMMARY` says so.
- **LinkedIn is not included.** Its ad library pages sit behind a bot wall that refuses visitors who are not logged in, and this actor does not log in or try to get around such walls.
- **Google does not publish ad text or landing pages** in its transparency data. Text ads come as an image snapshot of the ad.
- **Searching by domain on Google** returns every advertiser whose ads point at that domain, which can include resellers and agencies. Check `advertiserName`.
- **Searching by name on TikTok** matches legal entity names, so `nike` can match several entities. Use a fuller name, such as `NIKE Retail B.V.`, to narrow it.
- Media links from Meta and TikTok are signed by those platforms and expire after some hours or days. Download what you need soon after the run.
- Each run opens a browser for Meta and TikTok, so it needs 1 GB of memory. Google alone is light.

### FAQ

**Is this legal?** It reads public transparency libraries that the platforms publish so the public can see ads, while logged out, without an account and without personal data. Courts in the United States have treated logged out collection of public pages differently from collection behind a login (for example Meta v. Bright Data, 2024). This is not legal advice; check the rules that apply to your use.

**Why did an advertiser return zero ads in one library?** Either it does not advertise there, the country or dates exclude it, or strict matching filtered out ads from other advertisers. Try turning `strictMatch` off, or search by the exact name the library shows.

**Can I give it a Meta page ID or a Google advertiser ID?** Yes. A number is treated as a Meta page ID, and `AR` followed by digits as a Google advertiser ID. That is the most precise way to search.

**Do I need a Meta access token or a proxy?** No. The actor uses the public logged out pages. A proxy setting exists for special cases but is not needed normally.

**How fresh is the data?** Every run reads the libraries live.

**Something broke.** Open an issue on the Issues tab with the input you used. Issues are answered quickly.

This actor is independent and is not affiliated with, endorsed by or sponsored by Google, Meta, TikTok or LinkedIn. Names are used only to describe which public libraries are read.

# Actor input Schema

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

Advertiser domains or names, one per line. Domains (nike.com) give the cleanest matches. You can also paste a Google advertiser ID (AR followed by digits) or a Meta page ID (digits only).

## `sources` (type: `array`):

Which public ad libraries to search. Leave empty for all three.

## `country` (type: `string`):

Two letter country code (US, GB, DE). Leave empty for all countries. The TikTok library only covers Europe, the UK, Switzerland and Turkey, so TikTok is skipped for other countries.

## `dateFrom` (type: `string`):

Only ads shown on or after this date (YYYY-MM-DD).

## `dateTo` (type: `string`):

Only ads shown on or before this date (YYYY-MM-DD).

## `maxAdsPerSource` (type: `integer`):

Stops after this many ads for each advertiser in each library. You pay per ad, so this also caps cost.

## `strictMatch` (type: `boolean`):

On: keep only ads whose advertiser name contains your term, or (for domains on Meta) whose link points to your domain. Off: keep everything the library search returns.

## `googleDetails` (type: `boolean`):

Makes one extra request per Google ad to list every country it ran in, and to find the YouTube link for video ads. Slower.

## `proxyConfiguration` (type: `object`):

Optional. The libraries are public and usually work without a proxy.

## Actor input object example

```json
{
  "advertisers": [
    "nike.com",
    "Spotify",
    "hubspot.com"
  ],
  "sources": [
    "google",
    "meta",
    "tiktok"
  ],
  "maxAdsPerSource": 20,
  "strictMatch": true,
  "googleDetails": false
}
```

# Actor output Schema

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

All rows the run saved to the default dataset.

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

The SUMMARY record: counts and problems for the whole run.

# 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": [
        "nike.com"
    ],
    "maxAdsPerSource": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("pistachio_implementation/ad-transparency-multi-library").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": ["nike.com"],
    "maxAdsPerSource": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("pistachio_implementation/ad-transparency-multi-library").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": [
    "nike.com"
  ],
  "maxAdsPerSource": 20
}' |
apify call pistachio_implementation/ad-transparency-multi-library --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,pistachio_implementation/ad-transparency-multi-library"
        }
    }
}
```

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/1DyrmrMqhQWaAwu7W/builds/9e2lE9Pib0b6NU96Q/openapi.json
