# YouTube Ads Scraper: Competitor Video Ads Library (`pulsedata/youtube-ads-scraper`) Actor

Scrape the YouTube ads any brand runs, from the Google Ads Transparency Center: YouTube video ID and watch URL, first and last shown dates, days active, countries and EU impressions. Search by brand, domain or advertiser ID. No login. $3 per 1,000 ads.

- **URL**: https://apify.com/pulsedata/youtube-ads-scraper.md
- **Developed by:** [PulseData](https://apify.com/pulsedata) (community)
- **Categories:** Marketing, Lead generation, Videos
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 ad scrapeds

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

## YouTube Ads Scraper: Competitor Video Ads Library

This actor exports the ads a brand runs on YouTube, taken from the public [Google Ads Transparency Center](https://adstransparency.google.com/) with the platform filter fixed to YouTube. You enter a brand name, a domain such as `nike.com`, an advertiser ID or a Transparency Center URL, and get one JSON item per ad with the YouTube video ID and watch URL, first and last shown dates, days shown, the countries it ran in and, for ads shown in the EU, impression ranges per country.

The actor does not visit youtube.com. Everything comes from Google's own ad library, which lists the ads of verified advertisers. No Google account, login or cookies are needed. PulseData is not affiliated with Google or YouTube.

Price: $3.00 per 1,000 ads ($0.003 per ad). There is no start fee, and details and video IDs are included in that price.

### What you can do with it

- **See every YouTube ad a competitor is running.** Enter their domain and get the video ads that point to it.
- **Get the YouTube video ID and link of each ad.** Open the ads, download them, or pass the IDs to a transcript or comments tool.
- **Find YouTube ads shown in one country.** Filter by any two-letter country code, such as `US`, `DE` or `GB`.
- **Get EU impression ranges for YouTube ads.** Google publishes an impression range per EU country, and the actor returns it.
- **Compare the YouTube ads of several brands** in one run, with the query stored on every row.
- **Track how long a brand keeps an ad live.** `firstShown`, `lastShown` and `daysShown` show which creatives run for months.
- **Find the text and image ads Google shows on YouTube**, mostly from Performance Max and Demand Gen campaigns, by switching the format to All.
- **Look up ads by Google advertiser ID** (`AR...`) when a brand name matches several accounts.

### Use cases

**Competitor research.** Marketing teams check which video ads a competitor has running now, which ones they keep for a long time and in which markets. Ads that stay live for months are usually the ones that perform.

**Creative swipe files.** Agencies collect the video IDs of a category's ads, watch them in bulk and tag hooks, lengths and calls to action. The [YouTube Transcript Scraper](https://apify.com/pulsedata/youtube-transcript-scraper) turns the same video IDs into text.

**Market entry checks.** Before launching in a country, filter a competitor's YouTube ads to that region and see how much they advertise there and since when.

**Monitoring.** Schedule a run per week with the same queries and compare `creativeId` values to spot new ads the day they appear in the library.

**Reseller and affiliate checks.** A domain query also returns ads from other advertisers that send viewers to that domain, for example sellers advertising their Amazon listings or agencies booking ads for a brand.

### Quick start

```json
{ "queries": ["nike.com"], "maxAdsPerQuery": 100 }
```

This returns up to 100 video ads pointing to nike.com that Google lists as shown on YouTube. Add more lines to `queries` to compare several competitors in one run.

### Input

| Field | What it does |
| --- | --- |
| `queries` | Advertiser names (`Nike`), domains (`nike.com`), advertiser IDs (`AR...`) or Transparency Center URLs, one per line. Required. |
| `region` | Only ads shown in this country (`US`, `DE`, `GB`, ...) or `anywhere` (default). |
| `format` | `VIDEO` (default) for YouTube video ads. `ALL` also returns the image and text ads Google lists as shown on YouTube. `TEXT` and `IMAGE` return only those. |
| `startDate`, `endDate` | Only ads shown in this date range (`YYYY-MM-DD`). |
| `maxAdsPerQuery` | Stop after this many ads per query. Default 100. 0 means no limit, and large advertisers can have thousands of ads. |
| `advertiserMatch` | For names: `best` takes the single most relevant advertiser, `all` takes every suggested advertiser that contains the name. |
| `includeDetails` | Per-country dates, EU impression ranges and targeting flags. On by default, one extra request per ad. |
| `enrichPreviews` | Extracts the YouTube video ID, watch URL and image URLs from the creative preview. On by default, one extra request per ad. |
| `proxyConfiguration` | Keep Apify residential proxies (default). Google blocks shared datacenter IPs quickly. |

Example with a country filter and several competitors:

```json
{
  "queries": ["nike.com", "adidas.com", "puma.com"],
  "region": "DE",
  "format": "VIDEO",
  "maxAdsPerQuery": 50
}
```

### Output

One item per ad. This is a shortened real item from a test run:

```json
{
  "query": "nike.com",
  "advertiserId": "AR08817325674072113153",
  "advertiserName": "Mediabrands Netherlands B.V.",
  "creativeId": "CR15582989562979287041",
  "format": "VIDEO",
  "firstShown": "2026-08-24T14:00:00.000Z",
  "lastShown": "2026-09-25T11:00:00.000Z",
  "daysShown": 33,
  "youtubeVideoId": "iC3pw6o5bN4",
  "youtubeUrl": "https://www.youtube.com/watch?v=iC3pw6o5bN4",
  "regionsShownIn": "FI",
  "regions": [
    { "regionCode": "FI", "regionName": "Finland", "firstShown": "2026-08-24", "lastShown": "2026-09-25", "impressionsLow": null, "impressionsHigh": null, "platforms": [] }
  ],
  "euTotals": { "impressionsLow": null, "impressionsHigh": null, "firstShown": "2026-08-24", "lastShown": "2026-09-25", "platforms": [] },
  "targeting": {
    "demographic": { "included": true, "excluded": true },
    "geographic": { "included": true, "excluded": false },
    "contextual": { "included": true, "excluded": false }
  },
  "variationsCount": 2,
  "url": "https://adstransparency.google.com/advertiser/AR08817325674072113153/creative/CR15582989562979287041?region=anywhere",
  "advertiserUrl": "https://adstransparency.google.com/advertiser/AR08817325674072113153?region=anywhere",
  "scrapedAt": "2026-09-25T12:49:03.309Z"
}
```

Other fields: `previewUrl`, `previewImageUrl`, `imageUrls`, `destinationUrl`, `appId`, `topicId` and `detailLastShown`. For ads shown in the EU, `impressionsLow` and `impressionsHigh` hold Google's published range, for example 15,000 to 20,000. The targeting block says whether demographic, geographic and contextual targeting was used, not the actual audience.

Export the dataset as JSON, CSV or Excel, or read it through the Apify API. The table view shows advertiser, format, dates, preview, video ID, regions and the ad link.

### Limits

- **The video ID is missing on some ads.** It is read from the ad preview, and some video ads have no public preview. In our tests 164 of 181 video ads had a `youtubeVideoId`. The other rows still have dates, countries and the Transparency Center link.
- **`ALL` is not only video.** With the format set to All, Google also lists text and image ads as shown on YouTube, mostly Performance Max and Demand Gen placements. Those rows have no video ID. Keep the default `VIDEO` if you only want video ads.
- Google shows ads in the Transparency Center only for verified advertisers. Ads that ran before an advertiser was verified may be missing.
- Impression ranges are published only for ads shown in the EU.
- A domain query returns every advertiser whose ads point to that domain, which can include agencies, regional companies and resellers. Use an advertiser ID to get one account only.
- Google rate-limits the Transparency Center. The actor paces requests and rotates residential proxy sessions, but a run can still end with a "Google is currently blocking the proxy exits" message. Nothing is charged for queries that returned no ads, and running it again later usually works.

### Price

$3.00 per 1,000 ads, charged as the `ad-scraped` event ($0.003 per ad). No start fee. Details and preview enrichment are included, so turning them off does not lower the price, only the run time. Apify platform usage is billed to us, not to you. Set a "Maximum cost per run" and the actor stops at that amount with a SUCCEEDED status and a message saying how to get the rest.

### FAQ

**Does it scrape YouTube itself?** No. It reads Google's public ad library and returns the ads Google lists as shown on YouTube.

**Why is the advertiser name not the brand I searched for?** A domain query returns every advertiser whose ads link to that domain. Big brands often buy ads through regional companies or media agencies, so a `nike.com` query can return "Nike Retail BV" or an agency name.

**Why did a brand name return no ads?** With `advertiserMatch: best`, the actor picks the largest advertiser whose name matches. That account may run no YouTube ads. Try the brand's domain, set `advertiserMatch` to `all`, or paste the advertiser ID from the Transparency Center URL.

**Can I get view counts or ad spend?** No. Google does not publish them. You get dates, days shown, countries and EU impression ranges.

**Can I download the video files?** The actor returns the YouTube video ID and watch URL. It does not download video files.

**I need ads from Search, Shopping or Maps too.** Use the [Google Ads Transparency Center Scraper](https://apify.com/pulsedata/google-ads-transparency-scraper), which covers every Google surface.

### Example pages

- [See every YouTube ad a competitor is running](https://apify.com/pulsedata/youtube-ads-scraper/examples/competitor-youtube-ads-by-domain)
- [See all YouTube ads Nike is running](https://apify.com/pulsedata/youtube-ads-scraper/examples/nike-youtube-ads)
- [Get the video IDs and links of a brand's YouTube ads](https://apify.com/pulsedata/youtube-ads-scraper/examples/youtube-ad-video-ids-and-links)
- [Compare the YouTube ads of several competitors](https://apify.com/pulsedata/youtube-ads-scraper/examples/compare-youtube-ads-of-competitors)

### More ad libraries by PulseData

- [Google Ads Transparency Center Scraper](https://apify.com/pulsedata/google-ads-transparency-scraper): all Google ad surfaces, including Search, Shopping, Maps and Play.
- [LinkedIn Ad Library Scraper](https://apify.com/pulsedata/linkedin-ad-library-scraper): ads companies run on LinkedIn.
- [TikTok Ad Library Scraper](https://apify.com/pulsedata/tiktok-ad-library-scraper): ads shown on TikTok in the EU.
- [YouTube Transcript Scraper](https://apify.com/pulsedata/youtube-transcript-scraper): turn the video IDs from this actor into text.

# Actor input Schema

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

One entry per line: advertiser names (`Nike`), domains (`nike.com`), advertiser IDs (`AR16735076323512287233`) or Ads Transparency Center URLs. Only ads shown on YouTube are returned.

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

Only ads shown in this country. Use `anywhere` for all countries or an ISO 3166-1 alpha-2 code (`US`, `DE`, `GB`, `FR`, …).

## `format` (type: `string`):

Filter by creative format. Video (default) returns YouTube video ads with their video ID. `All formats` also returns the image and text ads Google lists as shown on YouTube, mostly Performance Max and Demand Gen placements.

## `startDate` (type: `string`):

Only ads shown on/after this date, format `YYYY-MM-DD`.

## `endDate` (type: `string`):

Only ads shown on/before this date, format `YYYY-MM-DD`.

## `maxAdsPerQuery` (type: `integer`):

Stop after this many ads for each query. Set 0 for no limit (large advertisers can have tens of thousands of ads).

## `advertiserMatch` (type: `string`):

When a query is an advertiser *name*: `best` picks the single most relevant advertiser (largest matching one); `all` scrapes every suggested advertiser that contains the name.

## `includeDetails` (type: `boolean`):

Fetches the detail page of every ad: per-country first/last shown dates, EU impression ranges per country and platform, targeting flags and creative variations. One extra request per ad.

## `enrichPreviews` (type: `boolean`):

Fetches the creative preview of every image or video ad and extracts the YouTube video ID, watch URL, thumbnail and image asset URLs. One extra request per ad. Turn off only if you do not need the video IDs.

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

Google blocks shared datacenter IPs quickly – keep Apify residential proxies (default). Only the small JSON API calls go through the proxy; creative previews are fetched directly, so proxy traffic stays tiny (~3 KB per ad).

## Actor input object example

```json
{
  "queries": [
    "nike.com"
  ],
  "region": "anywhere",
  "format": "VIDEO",
  "maxAdsPerQuery": 100,
  "advertiserMatch": "best",
  "includeDetails": true,
  "enrichPreviews": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Results stored in the default dataset (JSON/CSV/Excel via the dataset API).

# 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",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("pulsedata/youtube-ads-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",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("pulsedata/youtube-ads-scraper").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 '{
  "queries": [
    "nike.com"
  ],
  "region": "anywhere",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call pulsedata/youtube-ads-scraper --silent --output-dataset

```

## MCP server setup

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

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/LvhggWXwXDmBzYmoS/builds/V70PdjCOEb6y4gwSd/openapi.json
