# Snapchat Ads Scraper With Competitor Monitoring (`scrapier/snapchat-ads-scraper`) Actor

- **URL**: https://apify.com/scrapier/snapchat-ads-scraper.md
- **Developed by:** [Scrapier](https://apify.com/scrapier) (community)
- **Categories:** Automation, Lead generation, Social media
- **Stats:** 2 total users, 1 monthly users, 100.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/platform/actors/running/actors-in-store#pay-per-usage

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

### Snapchat Ads Scraper — Ads, Advertiser Summaries and New-Ad Alerts

Snapchat Ads Scraper queries Snapchat's public Ads Library by advertiser or brand name and returns every matching ad as structured JSON, alongside a computed per-advertiser summary row — ad counts, impressions, ad-type and media-type breakdowns, and a date range — built strictly from the ads it actually scraped. Every response is typed JSON, ready to pass directly to an LLM, index into a vector store, or feed a monitoring pipeline. Enter one or more advertiser names, set how many ads you want per name, and rows stream into the dataset live as each one is found, with a flag on every ad marking whether it is new since your last run.

### What is Snapchat Ads Scraper With Competitor Monitoring?

Snapchat Ads Scraper is an Apify Actor that searches Snapchat's public Ads Library — the same transparency search that powers Snap's own [Ads Gallery](https://adsgallery.snap.com) web tool — by advertiser or brand name, and returns two kinds of records in one dataset: individual ad rows (`recordType: "ad"`) and, once per search keyword, a computed advertiser summary row (`recordType: "advertiser_summary"`). The summary row is what sets this Actor apart from a plain ad-library dump: it is not a static field on each ad, it is an aggregate — ad count, active/paused counts, total and average impressions, an ad-type breakdown, a media-type breakdown, the earliest and latest ad start date, and how many ads are new since the previous run — computed live from the real ads the Actor just scraped for that advertiser.

No Snapchat account, login, or API key is required. The endpoint the Actor calls (`adsapi.snapchat.com/v1/ads_library/ads/search`) is open and unauthenticated — it is the same public search that any anonymous visitor to the Ads Gallery website uses.

- 🔎 Search one or many advertiser or brand names in a single run — bulk input, each processed independently
- 👻 Return every matching ad with creative, status, and impression fields as published in the public library
- 🧮 Get a computed advertiser summary row per search keyword, when `emitSummary` is enabled
- 🆕 Flag every ad with `isNew`, and every summary with `newAdsThisRun`, based on the previous run's snapshot
- 🌍 Filter by a single EU country, ad status (active/paused), and a `start_date` range

### What data can you get with Snapchat Ads Scraper?

Snapchat Ads Scraper returns two result types in the same dataset — the raw ads, and the roll-up computed from them.

| Result Type | Extracted Fields | Primary Use Case |
| --- | --- | --- |
| Ad (`recordType: "ad"`) | `id`, `adName`, `adType`, `payingAdName`, `accountName`, `profileLogoUrl`, `profileName`, `brandName`, `headline`, `totalImpressions`, `adStatus`, `snapMediaDownloadLink`, `snapMediaType`, `startDate`, `searchQuery`, `isNew` | Per-ad creative and performance detail |
| Advertiser summary (`recordType: "advertiser_summary"`) | `searchQuery`, `adCount`, `activeCount`, `pausedCount`, `totalImpressions`, `avgImpressions`, `adTypeBreakdown`, `mediaTypeBreakdown`, `earliestStartDate`, `latestStartDate`, `newAdsThisRun` | One-glance competitive snapshot per advertiser, per run |

#### Advertiser summary rollups

This is the Actor's differentiator. Reviewed against the top Snapchat- and ad-library-adjacent Actors on the Apify Store (checked 26 July 2026), none document a computed per-advertiser aggregate row sitting in the same dataset as the raw ads — they return ad rows (optionally tagged "new") but leave counting, breakdowns, and date-range math to the user. This Actor does that math for you, per search keyword, per run:

```json
{
  "recordType": "advertiser_summary",
  "searchQuery": "Ikea",
  "adCount": 42,
  "activeCount": 31,
  "pausedCount": 11,
  "totalImpressions": 18540000,
  "avgImpressions": 441428.57,
  "adTypeBreakdown": { "SNAP_AD": 28, "COLLECTION_AD": 9, "STORY_AD": 5 },
  "mediaTypeBreakdown": { "VIDEO": 30, "IMAGE": 12 },
  "earliestStartDate": "2025-11-02",
  "latestStartDate": "2026-07-18",
  "newAdsThisRun": 6
}
```

`totalImpressions` and `avgImpressions` are computed only from ads that actually carried a numeric impression value — `avgImpressions` is `null` when none did. `newAdsThisRun` and each ad's `isNew` are `null`, not `false`, on the very first run for an advertiser, because there is no prior snapshot to diff against yet — the Actor never guesses a new/old signal it can't support.

#### Individual ad records

Each ad is mapped from Snapchat's raw `ad_preview` object into camelCase fields: `id` (Snapchat's ad ID), `adName`, `adType`, `payingAdName` and `accountName` (who is billed / whose account served it), `profileLogoUrl` and `profileName`, `brandName` (read from Snap's `brand_name` field when present, otherwise approximated from the first word of `accountName`), `headline`, `totalImpressions`, `adStatus`, `snapMediaDownloadLink`, `snapMediaType`, and `startDate`. Every field is exactly what Snapchat's Ads Library publishes for that ad — nothing is inferred beyond the `brandName` fallback noted above.

| Output field | Snapchat's raw field |
| --- | --- |
| `id` | `id` |
| `adName` | `name` |
| `adType` | `ad_type` |
| `payingAdName` | `paying_advertiser_name` |
| `accountName` | `ad_account_name` |
| `profileLogoUrl` | `profile_logo_url` |
| `profileName` | `profile_name` |
| `brandName` | `brand_name`, or the first word of `ad_account_name` when `brand_name` is absent |
| `headline` | `headline` |
| `totalImpressions` | `impressions_total` |
| `adStatus` | `status` |
| `snapMediaDownloadLink` | `top_snap_media_download_link` |
| `snapMediaType` | `top_snap_media_type` |
| `startDate` | `start_date` |

`brand_name` is only populated by Snapchat on certain creative types (for example AR Lens ads) — for the ads where it's missing, the fallback derives a brand string from the account name instead of leaving the field empty.

### How does Snapchat Ads Scraper work?

Snapchat Ads Scraper is a pure HTTP scraper — no browser, no page rendering. For each entry in `searchQueries` it builds a JSON search body (`countries`, `paying_advertiser_name`, and, when set, `status`, `start_date`, `end_date`) and sends it as a `POST` to `adsapi.snapchat.com/v1/ads_library/ads/search?limit=N`, where `N` is the smaller of 50 (the page size the Actor requests per call) and however many ads are still needed to reach `maxItems`.

Snapchat's response wraps each result inside an `ad_previews` array, and only entries whose `sub_request_status` is `"SUCCESS"` are kept — a partial or failed sub-result is skipped rather than pushed as a broken row. The response also carries `paging.next_link`; the Actor follows that cursor page by page until it reaches `maxItems`, the cursor runs out, or Snapchat returns zero ads on a page after the first (treated as end of feed for that advertiser, so the Actor moves on instead of retrying a query that has nothing left to give).

Each surviving ad is mapped to the output schema and pushed to the dataset the moment it's fetched — not batched until the end of the run — so a crash or timeout partway through still leaves every ad scraped so far sitting in your dataset. In parallel, an in-memory aggregator folds each ad into the running counts and breakdowns that become that advertiser's `advertiser_summary` row once its query finishes.

### Why not build this yourself?

Snapchat does not publish a documented developer API for third parties to search the Ads Library by keyword. The endpoint this Actor calls is the private-but-unauthenticated API that Snap's own web-based Ads Gallery uses internally — not a published, versioned product with a stability guarantee. Reconstructing it yourself means first reverse-engineering the request shape (which of `countries`, `paying_advertiser_name`, `status`, `start_date`, and `end_date` the body accepts, and how the `limit` query parameter and `paging.next_link` cursor behave), then keeping up with it. Three things make maintaining that a real burden:

- **No stability contract.** An undocumented endpoint can change its request shape, pagination cursor, or response fields without notice, and there is no changelog to watch — you find out it broke when your own script starts erroring.
- **Aggressive per-IP rate-limiting.** Snap returns `error_code: "E1009"` (or a 429/5xx) when a source IP is throttled. Getting a full result set back reliably means backing off, retrying, and — when that isn't enough — rotating onto a different IP, which in practice means running and paying for proxy infrastructure of your own.
- **Cross-run state for "what's new."** Flagging ads as new only works if something persists the previously-seen ad IDs per advertiser between runs and diffs against them safely, including on a partial or failed run. That's a small database problem hiding inside what looks like a simple search call.

### Snapchat Ads Library monitoring vs Ads Manager reporting: what's the difference?

Snapchat Ads Manager reporting and the public Ads Library answer different questions, and this Actor only touches one of them. Ads Manager is Snap's private, authenticated dashboard where an advertiser logs into their own ad account to see their own campaign metrics — spend, click-through rate, conversions — for campaigns they own. The Ads Library is Snap's public transparency tool: anyone can search any advertiser's ads by name without logging in, but only the fields Snap chooses to publish there are exposed — creative, status, impressions, and date range, not spend or click performance.

Snapchat Ads Scraper queries only the public Ads Library search endpoint — the same one behind adsgallery.snap.com — and never touches a private ad account, campaign dashboard, or Snapchat login. That means it can profile a competitor's advertising it has zero account access to, but it also means it returns exactly what the Ads Library publishes: `totalImpressions`, not spend or CTR, because Snap does not publish those figures for ads that aren't yours.

### How to scrape Snapchat ads with Snapchat Ads Scraper?

1. Open Snapchat Ads Scraper on the Apify Store and click **Try for free**
2. Enter one or more brand names into `searchQueries` — this is the only required input, and it accepts a list, so bulk advertiser tracking needs no extra configuration
3. Set the real query controls you need: `maxItems` per advertiser, `country` (EU only), `status`, and `startDate` / `endDate`
4. Click **Start** and watch ad rows — and, once each advertiser finishes, its summary row — stream into the dataset live
5. Download the dataset as JSON, CSV, Excel, XML, or RSS, or read it programmatically through the Apify API

Every step above runs entirely on Apify — there's no separate signup flow, no external dashboard, and no credential beyond the Apify account you're already using to open the Actor.

To track several advertisers in one job, put every brand name into the `searchQueries` array — `["Ikea", "Nike", "McDonald's"]` — each is searched independently, tagged with its own `searchQuery` value in the output, and gets its own summary row when `emitSummary` is on.

### ⬇️ Input

| Parameter | Required | Type | Description | Example Value |
| --- | --- | --- | --- | --- |
| `searchQueries` | Yes | array | One or more advertiser / brand names to search the Snapchat Ads Library for. Bulk input is fully supported — every keyword is processed independently and tagged with the search query in the output. Use an empty string `""` as a single entry to fetch all ads in the library (filtered only by country / date / status). Default `["Ikea"]`. | `["Ikea", "Nike"]` |
| `maxItems` | No | integer | Maximum number of ads to fetch per search keyword. Snapchat paginates internally; the Actor follows the cursor until this limit is reached or no more ads are available. Minimum `1`, maximum `10000`, default `10`. | `50` |
| `country` | No | string | Restrict results to ads served in a single EU country. One of `AT`, `BE`, `BG`, `HR`, `CY`, `CZ`, `DK`, `EE`, `FI`, `FR`, `DE`, `GR`, `HU`, `IE`, `IT`, `LV`, `LT`, `LU`, `MT`, `NL`, `PL`, `PT`, `RO`, `SK`, `SI`, `ES`, `SE`, or `""` for all countries. Default `""`. | `"DE"` |
| `status` | No | string | Filter by ad delivery status: `"ACTIVE"`, `"PAUSED"`, or `""` for both. Default `""`. | `"ACTIVE"` |
| `startDate` | No | string | Only return ads with a `start_date` on or after this date (`YYYY-MM-DD`). Leave empty for no lower bound. | `"2026-01-01"` |
| `endDate` | No | string | Only return ads with a `start_date` on or before this date (`YYYY-MM-DD`). Leave empty for no upper bound. | `"2026-07-01"` |
| `emitSummary` | No | boolean | When enabled, the Actor appends one `advertiser_summary` row per search query with the aggregates described above. Per-ad rows are always emitted regardless of this setting. Default `true`. | `true` |
| `proxyConfiguration` | No | object | Apify Proxy settings. By default the Actor runs without a proxy and only escalates to Apify's datacenter, then residential proxy, if Snapchat rate-limits it. Default `{"useApifyProxy": false}`. | `{"useApifyProxy": false}` |

None of this Actor's inputs are credentials or secrets — there is no API key, token, or login field, so nothing here is masked as sensitive in the input form. In the Apify Console, `proxyConfiguration` sits inside a collapsed **🌐 Proxy Configuration (Advanced)** section captioned "Optional — expand to configure proxy settings. The actor handles fallback automatically." — you don't need to open it for a normal run; the default-off setting plus the automatic escalation described below is enough for most searches.

#### Example input

```json
{
  "searchQueries": ["Ikea", "Nike"],
  "maxItems": 100,
  "country": "DE",
  "status": "ACTIVE",
  "startDate": "2026-01-01",
  "endDate": "2026-07-01",
  "emitSummary": true,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

**Common pitfall:** `country` only accepts the 27 EU codes listed above — anything else (a `US`, a lowercase code, a typo) is logged as a warning and silently ignored, so the run falls back to all countries rather than failing. The same applies to `startDate` / `endDate`: a value that isn't a valid `YYYY-MM-DD` string is dropped with a warning instead of erroring the run.

### ⬆️ Output

Every ad and every summary row is pushed to the dataset live, one `Actor.push_data` call per record, so a run that stops early still leaves a usable partial dataset rather than nothing. Both record types are billed under the same pay-per-event name, `row_result` — there is no separate, uncharged accounting row in this Actor's output. Export the dataset as JSON, CSV, Excel, XML, or RSS from the Apify Console's Output tab, or read it programmatically through the [Apify API](https://docs.apify.com/api/v2).

Because ad rows and summary rows carry different fields, a summary row will show blanks in the ad-specific columns (`adName`, `snapMediaDownloadLink`, and so on) if you're looking at the default table view — filter on `recordType` to separate the two, or read the full JSON to see every field on each row type.

The dataset's default table view ("🔥 Scraped Ads") renders `profileLogoUrl` as an inline image and `snapMediaDownloadLink` as a clickable "Download" link, so you can eyeball creative logos and pull a Snap's media file directly from the Apify Console without opening the raw JSON.

If a single row fails to push — a transient dataset error, for instance — the Actor logs it and keeps going rather than aborting the run, so one bad row never costs you the rest of the query's results.

#### Example output

```json
[
  {
    "recordType": "ad",
    "searchQuery": "Ikea",
    "id": "e3f1a9c2-88b4-4e77-9c1a-2f6d0a7b5c11",
    "adName": "Summer Collection Snap Ad",
    "adType": "SNAP_AD",
    "payingAdName": "IKEA Global",
    "accountName": "IKEA Global",
    "profileLogoUrl": "https://ads-media.snapchat.com/logos/ikea-global.png",
    "profileName": "IKEA",
    "brandName": "IKEA",
    "headline": "Refresh your space this summer",
    "totalImpressions": 452300,
    "adStatus": "ACTIVE",
    "snapMediaDownloadLink": "https://ads-media.snapchat.com/creatives/e3f1a9c2.mp4",
    "snapMediaType": "VIDEO",
    "startDate": "2026-06-01",
    "isNew": true
  },
  {
    "recordType": "ad",
    "searchQuery": "Ikea",
    "id": "7c4b2d18-1a9e-4f3c-b6d7-9e0f2a8c4d33",
    "adName": "Kitchen Storage Collection Ad",
    "adType": "COLLECTION_AD",
    "payingAdName": "IKEA Global",
    "accountName": "IKEA Global",
    "profileLogoUrl": "https://ads-media.snapchat.com/logos/ikea-global.png",
    "profileName": "IKEA",
    "brandName": "IKEA",
    "headline": "Smarter storage starts here",
    "totalImpressions": 218900,
    "adStatus": "PAUSED",
    "snapMediaDownloadLink": "https://ads-media.snapchat.com/creatives/7c4b2d18.mp4",
    "snapMediaType": "VIDEO",
    "startDate": "2026-03-14",
    "isNew": false
  },
  {
    "recordType": "ad",
    "searchQuery": "Ikea",
    "id": "0a9d3e57-6b2c-4d81-9f0a-1c8e7b4d2a99",
    "adName": "Back to School Snap Ad",
    "adType": "SNAP_AD",
    "payingAdName": "IKEA Global",
    "accountName": "IKEA Global",
    "profileLogoUrl": "https://ads-media.snapchat.com/logos/ikea-global.png",
    "profileName": "IKEA",
    "brandName": "IKEA",
    "headline": "Everything for the new term",
    "totalImpressions": 97650,
    "adStatus": "ACTIVE",
    "snapMediaDownloadLink": "https://ads-media.snapchat.com/creatives/0a9d3e57.jpg",
    "snapMediaType": "IMAGE",
    "startDate": "2026-07-05",
    "isNew": true
  },
  {
    "recordType": "advertiser_summary",
    "searchQuery": "Ikea",
    "adCount": 3,
    "activeCount": 2,
    "pausedCount": 1,
    "totalImpressions": 768850,
    "avgImpressions": 256283.33,
    "adTypeBreakdown": { "SNAP_AD": 2, "COLLECTION_AD": 1 },
    "mediaTypeBreakdown": { "VIDEO": 2, "IMAGE": 1 },
    "earliestStartDate": "2026-03-14",
    "latestStartDate": "2026-07-05",
    "newAdsThisRun": 2
  }
]
```

### How does Snapchat Ads Scraper handle rate limits and blocking?

Snapchat's Ads Library endpoint rate-limits aggressively per source IP, signaling it with `error_code: "E1009"` (or a plain 429 or 5xx). The Actor handles this on two levels. Inside a single request, it retries up to 3 times with exponential backoff (`2 × 2^attempt` seconds, capped at 30 seconds) before giving up on that proxy level, and each attempt times out after 30 seconds if Snapchat never responds. Across requests, once a level is exhausted it escalates the proxy: no proxy → Apify datacenter proxy → Apify residential proxy, with up to 3 further retries on residential before the query is abandoned for that page. Once residential is engaged, the Actor stays on residential for the rest of the run rather than stepping back down. Between successful pages the Actor also waits roughly 1.0–1.6 seconds (a fixed delay plus random jitter) before requesting the next page, and pages are fetched at 50 ads per request, following Snapchat's own pagination cursor.

Every request also sends a standard desktop Chrome `User-Agent` plus the `Origin` and `Referer` headers of Snap's own Ads Gallery web app (`adsgallery.snap.com`), matching what a browser sends when a person searches the library directly, rather than a bare HTTP client signature.

### How can I use the data from Snapchat Ads Scraper?

- **📊 Performance marketers and agencies:** pull `headline`, `adType`, `snapMediaType`, and `totalImpressions` for every ad a competitor is running to build a swipe file of live creative and spot which formats they're leaning on this quarter.
- **🤖 AI engineers and LLM developers:** an agent issues a query with `searchQueries`, receives typed JSON back, and passes ad rows or the `advertiser_summary` object directly into a model's context — no parsing step required.
- **📈 Market researchers:** run the same `searchQueries` set on a schedule and diff `adCount`, `adTypeBreakdown`, and `mediaTypeBreakdown` across runs to track a category's advertising volume and creative-format mix over time.
- **🎯 Growth and brand teams:** use `newAdsThisRun` and each ad's `isNew` flag to catch a competitor's campaign launch the same week it goes live, rather than discovering it by accident.
- **🎨 Creative and design teams:** filter on `snapMediaType` and pull `snapMediaDownloadLink` to build a reference library of live competitor creative by format, without manually browsing the Ads Gallery ad by ad.

### 🆕 How do you monitor new Snapchat ads over time?

New-ad monitoring is the second half of what this Actor does automatically. On every run, it loads a previously saved snapshot — the set of ad IDs seen for each advertiser — from a named, persistent Apify Key-Value store (`snapchat-competitor-monitor`), keyed by a normalized, lowercased version of each `searchQuery` so "Ikea" and "ikea" share the same baseline. Named key-value stores persist independently of any single run, so this snapshot survives between scheduled executions rather than being discarded when a run finishes.

Each ad scraped in the current run is compared against that snapshot to set `isNew`: `true` if the ad ID wasn't in the prior snapshot, `false` if it was, and `null` on an advertiser's very first run, when there's no baseline yet to compare against. The `advertiser_summary` row's `newAdsThisRun` field is the count of ads flagged `true` for that query. After each advertiser is processed, its snapshot is updated with the ad IDs actually seen — but only if the run produced at least one ad, so a failed or empty run never wipes a good baseline.

The practical workflow: put your tracked advertisers into `searchQueries`, run the Actor on a recurring [Apify Schedule](https://docs.apify.com/platform/schedules), and after each run filter the dataset on `isNew: true` (or read `newAdsThisRun` off the summary row) to see exactly what's changed since the previous check — without diffing anything yourself.

There is no separate "monitor ID" input to configure — the normalized `searchQuery` text itself is the tracking key inside the snapshot store, so every advertiser you search for is automatically tracked on its own, and adding a new advertiser to `searchQueries` starts a fresh baseline for that one name without touching the others.

### Integrate Snapchat Ads Scraper with Python and the Apify API

Snapchat Ads Scraper works with any language or tool that can send an HTTP request. Here it is called from Python with the official Apify client:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")

run = client.actor("<YOUR_USERNAME>/snapchat-ads-competitor-monitor").call(run_input={
    "searchQueries": ["Ikea", "Nike"],
    "maxItems": 50,
    "country": "DE",
    "status": "ACTIVE",
    "emitSummary": True,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    if item["recordType"] == "advertiser_summary":
        print(item["searchQuery"], "→", item["adCount"], "ads,", item["newAdsThisRun"], "new")
    else:
        print(item["searchQuery"], "→", item["headline"], item["totalImpressions"])
```

The same call works unchanged from Go, Ruby, Node.js, or a raw `curl` request against the Apify API — the input JSON and dataset shape don't change with the client:

```bash
curl -X POST "https://api.apify.com/v2/acts/<YOUR_USERNAME>~snapchat-ads-competitor-monitor/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
     -H "Content-Type: application/json" \
     -d '{
       "searchQueries": ["Ikea", "Nike"],
       "maxItems": 50,
       "country": "DE",
       "emitSummary": true
     }'
```

### Schedule Snapchat Ads Scraper for recurring monitoring

Scheduling and delivery run on Apify's own platform features, not on anything built into this Actor. Attach an [Apify Schedule](https://docs.apify.com/platform/schedules) to run it on a cron for hands-off competitor monitoring, and an [Apify webhook](https://docs.apify.com/platform/integrations/webhooks) to trigger a downstream action — a Slack alert, a sheet update — the moment a run finishes and new ads are sitting in the dataset.

### Is it legal to scrape Snapchat's Ads Library?

Scraping the Snapchat Ads Library is generally permissible because it collects only what is already publicly visible — the same ad transparency data any visitor to Snap's own Ads Gallery website can see without logging in. Snapchat Ads Scraper returns only what any visitor to that public search sees; it does not log in, does not access a private ad account, and does not bypass any authentication. Courts in the United States have treated scraping publicly accessible web data as generally permissible for the party doing the scraping — see *hiQ Labs v. LinkedIn*, 9th Cir., 2019.

The data this Actor returns — ad creative, advertiser names, impression counts, and campaign dates — is business and product data published for transparency purposes, not personal data about an individual, so the ToS and database-rights framing that governs commercial catalogue scraping applies here, not a personal-data regime like GDPR. That said, ad creative (a headline, a video, an image) can incidentally depict or name real people, so treat any personal data that surfaces inside a creative with the same care you would apply to any other publicly posted content. Scraping for internal competitive monitoring and scraping to train a commercial AI model carry different risk profiles. Consult your legal team for commercial use cases involving bulk data storage or resale.

Public ad-transparency search tools of this kind are now common practice among major ad platforms — a public, searchable repository of an advertiser's live and past ads, reachable without an account, is exactly the purpose Snap built the Ads Library to serve.

### ❓ Frequently asked questions

#### Does Snapchat Ads Scraper support country and date filtering?

Yes. `country` restricts results to a single EU country from the 27-code list in the Input schema (`""` for all countries), and `startDate` / `endDate` bound the range of `start_date` values Snapchat returns, in `YYYY-MM-DD` format.

#### What ad statuses can I filter by?

`status` accepts `"ACTIVE"`, `"PAUSED"`, or `""` (the default) to include both. This filters on the ad's current delivery status as reported by Snapchat.

#### How does Snapchat Ads Scraper handle Snapchat's anti-bot and rate-limit measures?

It retries each request up to 3 times with exponential backoff before escalating, then steps through a proxy fallback chain — no proxy, then Apify datacenter, then Apify residential proxy (with up to 3 further retries) — sticking at whichever level it last needed for the rest of the run. See "How does Snapchat Ads Scraper handle rate limits and blocking?" above for the full mechanics.

#### Does Snapchat Ads Scraper compute a per-advertiser summary automatically?

Yes — when `emitSummary` is `true` (the default), one `advertiser_summary` row is appended per search keyword after its ads are scraped, with `adCount`, `activeCount`, `pausedCount`, `totalImpressions`, `avgImpressions`, `adTypeBreakdown`, `mediaTypeBreakdown`, `earliestStartDate`, `latestStartDate`, and `newAdsThisRun`, all computed from the real ads returned in that run.

#### How many ads does Snapchat Ads Scraper return per query?

Up to `maxItems` per search keyword — the input schema allows `1` to `10000`, with a default of `10`. Snapchat is fetched in pages of 50 ads at a time, and the Actor follows Snapchat's own pagination cursor until it hits your `maxItems` limit or Snapchat has no more ads to return.

#### Does maxItems apply per advertiser or across my whole search list?

Per advertiser. `maxItems` is the cap for each entry in `searchQueries` individually, not a shared budget across the list — five advertisers with `maxItems: 50` can return up to 250 ads in total, 50 for each.

#### How do I use Snapchat Ads Scraper to monitor new ads over time?

Put your tracked advertisers in `searchQueries` and run the Actor on a recurring [Apify Schedule](https://docs.apify.com/platform/schedules). Each run compares the ads it finds against a named Key-Value store snapshot of previously-seen ad IDs, sets `isNew` on every ad and `newAdsThisRun` on the summary row, and updates the snapshot for next time.

#### Can I fetch every ad in the library instead of one advertiser?

Yes. Pass a single empty string as an entry in `searchQueries` (`[""]`) to fetch all ads in the library, filtered only by whichever `country`, `status`, and date filters you set.

#### What happens if I list the same advertiser twice, or with different casing?

Duplicates are removed before the run starts. Matching is case-insensitive and trimmed, so `["Ikea", "ikea ", "IKEA"]` is treated as a single query and scraped once. The same normalization is used for the new-ad snapshot, so switching casing between runs doesn't reset your baseline or duplicate an advertiser's tracked history.

#### Does Snapchat Ads Scraper work with Claude, ChatGPT, and AI agent frameworks?

It is callable as a standard HTTP endpoint through the Apify API, so any agent framework that can make a request — LangChain, CrewAI, a custom tool definition, or a no-code automation platform — can invoke it and receive typed JSON directly, without a dedicated MCP integration.

#### How does Snapchat Ads Scraper compare to other ad-library scrapers?

Checked on the Apify Store on 26 July 2026: `happitap/competitor-ads-monitor` covers Meta, Google, and TikTok with offer and CTA detection, but not Snapchat. `scrapesage/facebook-ad-library-scraper` covers only Meta's Ad Library, with a "monitoring mode" that returns new ads since the last run but no computed per-advertiser aggregate row. Neither documents Snapchat Ads Library coverage or a summary rollup computed alongside the raw ads in the same dataset — this Actor's differentiator against both. All three, including this one, price on Apify's Pay-Per-Event model, so you're billed per output record rather than per compute-minute regardless of which one you choose.

#### Can I use Snapchat Ads Scraper without managing proxies or Snapchat credentials?

Yes. No Snapchat account, login, or API key is required — the Actor queries Snapchat's open, unauthenticated Ads Library search endpoint. By default it runs with no proxy at all, and only reaches for Apify's datacenter and then residential proxy automatically if Snapchat starts rate-limiting it; you never have to configure or rotate one yourself unless you choose to preconfigure `proxyConfiguration`.

### 💬 Your feedback

Found a bug, or an advertiser whose ads aren't showing up as expected? Open an issue on the Actor's Issues tab on Apify and it will be looked at. Reports that include the exact `searchQueries` value and country/date filters you used are the fastest to act on.

# Actor input Schema

## `searchQueries` (type: `array`):

🏷️ Enter one or more **advertiser / brand names** to search the Snapchat Ads Library for (e.g. `Ikea`, `Nike`, `McDonald's`). Bulk input is fully supported — every keyword is processed independently and its results are tagged with the search query in the output.

💡 Use an empty string `""` as a single entry to fetch **all ads** in the library (filtered only by country / date / status).

## `maxItems` (type: `integer`):

🎯 Maximum number of ads to fetch **per search keyword**. Higher numbers = more data and longer runtime. Snapchat paginates internally; the actor follows the cursor until this limit is reached or no more ads are available.

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

🇪🇺 Restrict results to ads served in a single EU country. Leave empty to include **all countries**.

## `status` (type: `string`):

🟢 Filter by the current delivery status of the ad. Choose **Any** to include both active and paused ads.

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

📆 Only return ads with a `start_date` **on or after** this date (format: `YYYY-MM-DD`). Leave empty for no lower bound.

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

📆 Only return ads with a `start_date` **on or before** this date (format: `YYYY-MM-DD`). Leave empty for no upper bound.

## `emitSummary` (type: `boolean`):

📊 When enabled (default), the actor appends one **summary row** per search query (`recordType: "advertiser_summary"`) with aggregates computed from the real ads scraped: ad count, active/paused counts, total & average impressions, ad-type and media-type breakdowns, earliest/latest start date, and the number of ads that are new since the previous run. Per-ad rows (`recordType: "ad"`) are always emitted with an `isNew` flag.

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

🛡️ By default the actor runs **without a proxy**. If Snapchat rate-limits or rejects the request, the actor automatically falls back to a **datacenter proxy**, then to a **residential proxy** (with up to **3 retries** on residential). Once residential is engaged, it stays engaged for the rest of the run.

## Actor input object example

```json
{
  "searchQueries": [
    "Ikea"
  ],
  "maxItems": 10,
  "country": "",
  "status": "",
  "emitSummary": true,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# 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 = {
    "searchQueries": [
        "Ikea"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapier/snapchat-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 = {
    "searchQueries": ["Ikea"],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapier/snapchat-ads-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 '{
  "searchQueries": [
    "Ikea"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call scrapier/snapchat-ads-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

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