# Snapchat Ads Library (`s-r/snapchat-ads-library`) Actor

Search Snapchat's political ad library and get rows with exact spend, impressions and a computed CPM, the paying advertiser and the organisation, start and end dates, the creative URL, and the full targeting spec down to electoral districts. Any year from 2019.

- **URL**: https://apify.com/s-r/snapchat-ads-library.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** Social media, Marketing, Business
- **Stats:** 4 total users, 3 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

## Snapchat Ads Library

Search Snapchat's political ad library: who paid, **how much they actually spent**, how many impressions they bought, and exactly who they targeted, down to electoral districts.

### What you get

- **Exact spend per ad, not a range.** Meta's library gives you "$1.000 - $4.999". Snap publishes the number. That single difference is what makes this dataset usable for real spend analysis
- **Impressions per ad**, and **`cpm` computed from the two**, which is the comparison a media buyer or researcher actually wants and which the raw file leaves you to work out
- **The full targeting spec**: gender, age bracket, countries, included and excluded regions, metros, postal codes, interests, languages and **electoral districts**. This is the part that shows who a campaign was really speaking to
- **Both sides of the disclosure**: `organization` is who ran the ad, `paying_advertiser` is who paid, and they are frequently different entities
- **Any year from 2019**, merged into one result and sorted by spend
- **Creative URLs**, so the actual image or video is one fetch away

### Where the data comes from

Snap publishes this itself, as a yearly ZIP on Google Cloud Storage with no key and no login. This actor downloads it, unzips it, normalises twenty-odd inconsistently named CSV columns into stable field names, merges the years you asked for, filters, computes CPM and sorts by spend.

That is worth saying plainly: **you are not paying for access here, you are paying for the parsing.** The file is public. What it is not is convenient: the column names carry spaces and parentheses and have shifted between years, the dates are in a non-standard format, multi-value targeting is comma-packed into single cells, and nothing is sorted.

### Input

| Field | Type | Required | Default | What it does |
|---|---|---|---|---|
| `years` | array | no | `["2026"]` | Which yearly datasets to search. 2019 onward |
| `search` | string | no | – | Matches organization, paying advertiser, committee and ballot information |
| `country` | string | no | – | Country code or name; keeps only ads that targeted it |
| `min_spend` | integer | no | – | Keep only ads at or above this spend |
| `limit` | integer | no | `500` | Ads to return, highest spend first |

### Output

```json
{
  "position": 1,
  "ad_id": "71366643e9b37bcd2bc42e52ecce06ba8987836b2e5c7a110327ac9c67d7a5d6",
  "year": 2024,
  "paying_advertiser": "Harris for President",
  "organization": "Harris for President",
  "spend": 290000.0,
  "currency": "USD",
  "impressions": 7544365.0,
  "cpm": 38.44,
  "start_date": "2024-09-10",
  "end_date": "2024-09-24",
  "still_running": false,
  "target_countries": [
    "US"
  ],
  "target_age_bracket": "18+",
  "target_districts_included": [
    "PA-07",
    "PA-08"
  ],
  "creative_url": "https://www.snap.com/political-ads/asset/..."
}
```

### Use cases

**Campaign spend analysis that does not need estimating.** Filter to a year and an advertiser and you have the actual money, ad by ad, with impressions beside it. Most political ad research starts by guessing at spend from a range; here you do not have to.

**Finding who is really behind a campaign.** `organization` and `paying_advertiser` differ more often than you would expect, and `committee_id` ties an ad to a filed committee. That chain is the story in a lot of political ad reporting.

**Targeting analysis at district level.** `target_districts_included` shows which electoral districts a campaign bought. Comparing that against results, or against a rival's districts, is a question no other major ad library lets you ask.

**Efficiency benchmarking.** `cpm` across advertisers, geographies and years shows who bought attention cheaply and who overpaid. In testing, CPMs on the same platform ranged from about $5 to nearly $40.

**Compliance and monitoring.** Filter by `country` and `min_spend` on a schedule and you have a watch list for large political spend in a market.

### How it compares

| | this actor | reading the raw file yourself |
|---|---|---|
| Per 1.000 ads | **$1,00** | free |
| Column names stable across years | **yes** | no, they shift |
| Dates as ISO | **yes** | no, `2026/02/18 11:43:43Z` |
| Multi-value targeting split into arrays | **yes** | no, comma-packed cells |
| CPM computed | **yes** | no |
| Multiple years merged and sorted by spend | **yes** | no |

Being honest about it: the data is public and free. If you want one year and are happy in a spreadsheet, download the ZIP. This exists for when you want it as clean rows in a pipeline, across years, filtered and ranked.

### Pricing

Two events. `run_start` costs $0,0010 per run. `ad` costs $0,0010 per ad written to the dataset, which is $1,00 per 1.000.

### Limits and gotchas

- **Political ads only.** Snap publishes no commercial ad library, so there is nothing here about brand advertising. The run says so rather than returning an empty result that looks like a failure.
- **`totalSpend` sums across currencies.** A single result can carry USD, GBP, EUR, SEK, NOK and CAD at once, so that total is only meaningful when the summary's `currencies` shows one code. It is reported with that warning attached rather than presented as a figure.
- **Spend is what the advertiser had spent when the file was published**, not necessarily the final campaign total, and Snap regenerates the files over time.
- **Each year is a separate download of 1 to 5 MB.** Asking for eight years means eight downloads before any filtering, so a wide run takes a minute or two regardless of how few rows come back.
- **Snap's `CountryCode` column holds country names, not codes.** It contains `united states`, not `US`. This actor accepts either form and maps it to what the file uses, because filtering `US` against it directly matches nothing and looks like "no ads targeted the US" rather than a broken comparison.
- **`end_date` is empty on ads still running**, which is surfaced as `still_running` rather than left as a blank you have to interpret.
- **Targeting fields are only as complete as the advertiser's disclosure.** Many ads set none, and those come back without the field rather than with an empty one.

### FAQ

**Does this cover normal Snapchat ads?**
No. Snap only publishes political advertising, so a commercial ad library does not exist to scrape.

**Is the spend exact or a range?**
Exact, in the ad's own currency. This is the main advantage over Meta's library.

**How far back does it go?**
2019\. Every year through the current one is available.

**Why is total spend across mixed currencies?**
Because Snap reports each ad in the currency its account used. The summary lists which currencies are present so you can split before summing.

**Can I get the creative?**
`creative_url` links straight to the image or video Snap hosts.

### Related Actors

- [Meta Ads Library](https://apify.com/s-r/meta-ads-library) — Facebook and Instagram ads
- [TikTok Ads Library](https://apify.com/s-r/tiktok-ads-library) — TikTok ad research
- [Google Ads Transparency](https://apify.com/s-r/google-ads-transparency) — ads across Google, YouTube and Search
- [LinkedIn Ads Library](https://apify.com/s-r/linkedin-ads-library) — LinkedIn ad research

# Actor input Schema

## `years` (type: `array`):

Which years to search. Snap publishes one dataset per year from 2019 onward.

## `search` (type: `string`):

Match against organization, paying advertiser, committee and ballot information. Leave empty for everything.

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

Country code or full name. Keeps only ads that targeted it. Snap stores names, so both 'US' and 'united states' work.

## `min_spend` (type: `integer`):

Keep only ads at or above this spend, in the ad's own currency.

## `ad_status` (type: `string`):

Snap's file records an end date for ads it has finished. 'Still running' keeps the ones with no end date, 'Finished' keeps the rest.

## `only_total` (type: `boolean`):

Return one row with how many ads match, how many are still running and what they spent, instead of the ads themselves. No per-ad charge. Snap publishes no count endpoint, so the yearly archive is still downloaded.

## `limit` (type: `integer`):

How many ads to return, 1 to 20000, highest spend first.

## Actor input object example

```json
{
  "years": [
    "2026",
    "2024"
  ],
  "search": "harris",
  "country": "US",
  "ad_status": "all",
  "only_total": false,
  "limit": 500
}
```

# Actor output Schema

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

One row per political ad, highest spend first.

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

Ads returned, matches per year, total spend with its currency breakdown, and impression coverage.

## `errors` (type: `string`):

Per-year failures with a code and a redacted message.

# 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 = {
    "years": [
        "2026"
    ],
    "limit": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/snapchat-ads-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 = {
    "years": ["2026"],
    "limit": 500,
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/snapchat-ads-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 '{
  "years": [
    "2026"
  ],
  "limit": 500
}' |
apify call s-r/snapchat-ads-library --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/snapchat-ads-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/nBkc2hyvbwI1Uec6i/builds/XdICrj1WfUV8sAqZz/openapi.json
