# YouTube Ads Scraper - Video Ad Transparency & Competitor Intel (`mochiboo/youtube-ads-transparency-scraper`) Actor

Scrape competitor YouTube video ads from Google's Ads Transparency Center. Each ad resolves to a real YouTube video: video ID, watch URL, thumbnail, duration, aspect ratio, plus advertiser, flight dates and region. Video ad intelligence for creative research. Company-level only.

- **URL**: https://apify.com/mochiboo/youtube-ads-transparency-scraper.md
- **Developed by:** [mochi](https://apify.com/mochiboo) (community)
- **Categories:** AI, Automation, Agents
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## YouTube Ads Scraper — YouTube Ad Transparency & Competitor Video Ad Intelligence

Scrape **competitor YouTube video ads** from Google's public **Ads Transparency Center**, and get back the thing every other ad scraper leaves out: **the actual YouTube video**.

Every row resolves to a real video — **video ID, watch URL, thumbnail, duration, aspect ratio** — alongside the advertiser, the flight dates, and the region the ad ran in. Built for creative teams, performance marketers, and competitive-research agents doing **video ad intelligence**.

***

### Why this actor

Google's Ads Transparency Center tells you a creative *is* a video. It does not tell you **which** video — the list data contains no YouTube ID, no duration, no thumbnail. This actor closes that gap:

1. **Server-side video filter.** The transparency search is asked for video creatives *only*. This matters more than it sounds: in a normal mixed search, video is a small minority (for `nike.com`, **2 of 40** creatives). Filtering at the source returns roughly **20x more video ads per page fetched** than pulling everything and discarding non-video.
2. **Video resolution.** Each ad's creative preview is opened and mined for its YouTube video ID, duration, and aspect ratio — turning an opaque ad record into a video you can actually watch, embed, and analyse.

#### Relationship to our Google Ads Transparency Scraper — read this before you buy

This actor uses the **same public source** as our general [Google Ads Transparency Scraper](https://apify.com/mochiboo/google-ads-transparency-scraper), and shares its proven RPC client. It is a **specialisation, not a separate data source**, and we would rather say so plainly than have you find out after a run.

**Use the general actor** if you want *all* ad formats (text, image, video) and only need the ad record.
**Use this one** if you care about video: it adds the server-side video filter, the YouTube ID / URL / thumbnail / duration / aspect-ratio resolution, duration bucketing and duration filters — none of which the general actor does. If you only need the raw video ad list without the video details, set `enrichVideoData: false` and this actor is simply the general one with a video filter.

***

### What you get (one row per video ad)

| Field | Description |
|---|---|
| `advertiserName` | Advertiser (company/organisation) |
| `advertiserDomain` | Verified domain, e.g. `nike.com` (domain mode) |
| `advertiserId` | Google advertiser ID (`AR...`) |
| `creativeId` | Google creative ID (`CR...`) |
| `adFormat` | Always `video` for this actor |
| **`videoId`** | **YouTube video ID (11 chars)** |
| **`videoUrl`** | **`https://www.youtube.com/watch?v=...`** |
| **`videoThumbnailUrl`** | **Thumbnail image URL** |
| **`videoDurationSeconds`** | **Ad length in seconds (e.g. `15.082`)** |
| `videoDurationBucket` | `bumper (<=6s)` / `short (7-15s)` / `standard (16-30s)` / `long (31-60s)` / `extended (>60s)` |
| `videoAspectRatio` | `1.7778` = 16:9 landscape, `0.5625` = 9:16 vertical/Shorts |
| `videoLayout` | Render template / placement hint (e.g. `discover`, `youtube_home`) |
| `videoIdSource` | How the ID was found — provenance, not a guess |
| `firstShown` / `lastShown` | Flight dates (ISO 8601 UTC) |
| `firstShownTs` / `lastShownTs` | Same, as unix seconds (stable sort key) |
| `variantCount` | Relative breadth signal (see honesty note below) |
| `previewUrl` | Google's signed creative preview (short-lived) |
| `adLibraryUrl` | Deep link to the ad on Google's own site |
| `region`, `matchedQuery`, `searchMode`, `source`, `scrapedAt` | Query context |

***

### Input

Every field has a default — **running with empty input `{}` works** and returns a sample of Nike's video ads.

```json
{
  "searchMode": "domain",
  "queries": ["grammarly.com", "booking.com", "squarespace.com"],
  "region": "US",
  "maxResults": 24,
  "maxResultsPerQuery": 8
}
```

| Input | Default | Notes |
|---|---|---|
| `searchMode` | `domain` | `domain` | `keyword` | `advertiser` |
| `queries` | `["nike.com"]` | Domains, keywords, or `AR...` advertiser IDs |
| `region` | `anywhere` | `US`, `United Kingdom`, `DE`, … Unknown values fall back to global rather than guessing |
| `dateFrom` / `dateTo` | — | `YYYY-MM-DD`; matches ads whose flight overlaps the window |
| `minDurationSeconds` / `maxDurationSeconds` | `0` (off) | e.g. `maxDurationSeconds: 6` for bumper ads |
| `onlyWithVideoId` | `false` | Drop ads whose video ID could not be resolved |
| `enrichVideoData` | `true` | Turn off for a faster, cheaper advertiser-only run |
| `maxResults` | `20` | Global cap across all queries. Keep low for a quick sample; `0` = no limit |
| `maxResultsPerQuery` | `0` (off) | Cap each query separately. **Set this when comparing competitors** — queries run in order against the shared budget, so one prolific advertiser can otherwise consume the whole run |
| `maxAdvertisersPerKeyword` | `3` | Keyword mode only |

#### Search modes

- **`domain`** — best starting point. `["nike.com"]` returns Nike's video ads.
- **`keyword`** — `["running shoes"]` resolves the term to its top advertisers, then pulls each one's video ads. Rows are enriched with `advertiserCountry` and `advertiserAdCount`, so you get a ranked competitive landscape.
- **`advertiser`** — exact `AR...` IDs for exhaustive coverage of one advertiser.

***

### Use cases

- **Competitor video ad research** — pull every YouTube ad a rival is running, watch them, and track when creatives launch and retire.
- **Creative intelligence** — see which ad lengths and aspect ratios a category actually ships (bumper vs 30s; 16:9 vs 9:16 vertical).
- **Ad creative swipe files** — thumbnails and watch URLs, ready to embed in Notion/Airtable.
- **Campaign monitoring** — schedule runs and diff on `creativeId` to catch new video ads the week they launch.
- **AI agents** — flat, predictable, fully-typed JSON with no nesting; every field is null-safe.

***

### Honest limits

We would rather set expectations than have you discover these on run one.

- **About 4 in 5 video ads resolve to a YouTube video ID — but it varies a lot by advertiser.** Measured on a live sample of **120 video creatives across 8 advertisers: 95 resolved (79%)**. Per-advertiser it ranged from **100%** (grammarly.com, booking.com, hellofresh.com, expressvpn.com) down to **53%** (nike.com) and **0%** (coursera.org, whose ad previews contain no video reference at all). Unresolved ads are still returned with `null` video fields — never silently dropped. Set `onlyWithVideoId: true` to keep only resolved ones, and check `RUN_SUMMARY.videoIdResolutionRate` for the **real rate of your own run**.
- **Duration resolves about half the time (61/120 = 51% in the same sample).** It is recovered from the ad's media URL, which only some layouts inline. `videoDurationSeconds` is `null` when absent, and duration filters *keep* such ads rather than hiding them because of an enrichment miss.
- **The misses are mostly a real thing, not a parsing gap.** Typical unresolved cases are `youtube_home` masthead placements and regional creatives whose preview carries no video at all. Where a video *is* referenced, we resolve it from either the explicit video field or the thumbnail URL, and `videoIdSource` tells you which.
- **`variantCount` is a breadth proxy, not spend.** It is a per-creative integer Google publishes. It is **not impressions and not spend** — the public Transparency Center exposes neither, and no scraper can give you them. Treat it as a relative signal for which creatives an advertiser is pushing hardest.
- **`previewUrl` is short-lived.** Google signs it; it expires. Use `videoUrl` / `videoThumbnailUrl` for anything durable.
- **Coverage is whatever Google publishes.** The Ads Transparency Center is the source of truth; if an ad is not there, it is not here.
- **`RUN_SUMMARY`** (key-value store) reports `videoAdsReturned`, `resultCapReached`, `errors` and `complete`, so you can always tell a full run from one capped by `maxResults`.

### Data ethics & compliance

Public, unauthenticated data only, from Google's own transparency surface (no login, no cookies).

**Company-level only.** Output covers advertisers (organisations) and their creatives. This actor does **not** collect channel owners, uploaders, commenters, subscriber identities, or any personal data — by design, in line with GDPR/PDPA.

### Pricing

**Pay per result** — $0.003 per video ad returned, plus a $0.00005 actor-start event. No subscription.
The default run returns **20 ads (~$0.06)**, so you can check the output before scaling up.
Set `maxResults` to cap spend on any run.

### Use with AI agents (MCP)

Available to any MCP-compatible agent (Claude, ChatGPT, Cursor, LangChain) via the hosted
**[Apify MCP server](https://mcp.apify.com)** — connect once, then ask the agent to run
`mochiboo/youtube-ads-transparency-scraper`.

**Want only this actor as a tool, with no store search in the way?** Point the agent at
`https://mcp.apify.com/?actors=mochiboo/youtube-ads-transparency-scraper` and it loads as a single named tool —
the agent calls it directly instead of searching for it and possibly picking someone else.

Agent-friendly by design:

- **Every row resolves to a real YouTube video ID and watch URL**, so an agent can hand the creative straight to a video- or vision-capable model without another lookup step.
- **Small default run** (20 ads) for a cheap first probe.
- **Short, literal input field descriptions** — fillable with no extra documentation.
- **Flat output**, one level deep, no decode logic.

### Related ad-intelligence actors

- **[Google Ads Transparency Scraper](https://apify.com/mochiboo/google-ads-transparency-scraper)** — all Google ad formats (text, image, video) across Search, Shopping and Display; use it when you want everything, not just video.
- **[Competitor Ad Intel — All Platforms](https://apify.com/mochiboo/competitor-ad-intel-all-platforms)** — Google **and** Bing in one normalized dataset.
- **[Bing Ads Library Scraper](https://apify.com/mochiboo/bing-ads-library-scraper)** — the Microsoft/Bing Ads Library (EEA scope).
- **[Competitor Ad Monitor](https://apify.com/mochiboo/competitor-ad-monitor-google)** — scheduled change-feed: only new or changed creatives.
- **[Winning Ad Creatives](https://apify.com/mochiboo/winning-ad-creatives-scraper)** — ranks a competitor's ads by how long they have survived, so you get the proven creatives instead of the full list.

### FAQ

**Do I need a Google or YouTube account?**
No. It reads the public [Google Ads Transparency Center](https://adstransparency.google.com) — no login, no cookies.

**Can I get view counts or spend for a competitor's video ads?**
Not from this source — Google's public Transparency Center publishes neither. You get the video ID and
watch URL, so you can look up public YouTube metrics yourself from there.

**How is this different from just filtering the Google actor to video?**
The Google actor returns a video creative as an ad row. This one additionally resolves each ad to its
underlying YouTube video — video ID, watch URL, thumbnail, duration and aspect ratio — and lets you filter
by duration. See **Relationship to our Google Ads Transparency Scraper** above.

**Can I export to CSV or Excel?**
Yes — every Apify dataset exports to JSON, CSV, Excel, XML, or RSS from the UI or the API.

**Does this collect personal data?**
No. Output is advertiser/company-level only (PDPA / GDPR-friendly by design).

### Support & feedback

Found a bug or a missing field? Open an issue on the actor's **Issues** tab — this actor is actively maintained.
If it saved you time, an **honest review on the Apify Store** helps other people find it.

# Actor input Schema

## `searchMode` (type: `string`):

How to interpret your queries. 'domain' = brand/domain search (e.g. nike.com). 'keyword' = resolve a keyword to its top advertisers, then pull their video ads. 'advertiser' = exact advertiser IDs (AR...) for every video ad that advertiser runs.

## `queries` (type: `array`):

Domains, keywords, or advertiser IDs — must match your Search mode. Examples: domain mode -> \["nike.com", "grammarly.com"]; keyword mode -> \["running shoes"]; advertiser mode -> \["AR16832577870747402241"].

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

Restrict to ads shown in one country. Use a country name or code (e.g. "US", "United Kingdom", "DE") or "anywhere" for global. Unknown values fall back to anywhere rather than guessing.

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

Only ads whose active period overlaps on/after this date. Format YYYY-MM-DD. Leave blank for no lower bound.

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

Only ads whose active period overlaps on/before this date. Format YYYY-MM-DD. Leave blank for no upper bound.

## `minDurationSeconds` (type: `integer`):

Keep only video ads at least this long. Ads whose duration could not be resolved are kept. 0 = no minimum.

## `maxDurationSeconds` (type: `integer`):

Keep only video ads up to this long — e.g. 6 for bumper ads, 30 for standard. Ads whose duration could not be resolved are kept. 0 = no maximum.

## `onlyWithVideoId` (type: `boolean`):

Skip video ads whose YouTube video ID could not be resolved. About 8 in 10 resolve; the rest are placements (e.g. YouTube masthead) that do not map to a single video. Off = keep everything.

## `enrichVideoData` (type: `boolean`):

Open each ad's preview to recover the YouTube video ID, watch URL, thumbnail, duration and aspect ratio. Turn off for a faster, cheaper run that returns advertiser + dates only.

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

Stop after this many video ads (across all queries). Keep it low for a quick sample; 0 = no limit.

## `maxResultsPerQuery` (type: `integer`):

Cap each query separately so one prolific advertiser cannot use up the whole run. Recommended when comparing several competitors in one run. 0 = no per-query cap.

## `maxAdvertisersPerKeyword` (type: `integer`):

Keyword mode only: how many of the top resolved advertisers to expand into video ads, per keyword.

## Actor input object example

```json
{
  "searchMode": "domain",
  "queries": [
    "nike.com"
  ],
  "region": "anywhere",
  "dateFrom": "",
  "dateTo": "",
  "minDurationSeconds": 0,
  "maxDurationSeconds": 0,
  "onlyWithVideoId": false,
  "enrichVideoData": true,
  "maxResults": 20,
  "maxResultsPerQuery": 0,
  "maxAdvertisersPerKeyword": 3
}
```

# 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 = {
    "queries": [
        "nike.com"
    ],
    "region": "anywhere"
};

// Run the Actor and wait for it to finish
const run = await client.actor("mochiboo/youtube-ads-transparency-scraper").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 = {
    "queries": ["nike.com"],
    "region": "anywhere",
}

# Run the Actor and wait for it to finish
run = client.actor("mochiboo/youtube-ads-transparency-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "queries": [
    "nike.com"
  ],
  "region": "anywhere"
}' |
apify call mochiboo/youtube-ads-transparency-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=mochiboo/youtube-ads-transparency-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/HFDk9f3GdJTFPUdiP/builds/BBC8lfdCibV6kLFQh/openapi.json
