# Facebook & Meta Ad Library Scraper: by website, with EU reach (`reachlens/meta-ad-library-scraper`) Actor

Type a website, Facebook page or brand and get its running Facebook & Instagram ads: days running, landing page, copies of each creative, Meta's ad count, EU reach by age and gender, lasting image links, new and stopped ads, and a summary per advertiser.

- **URL**: https://apify.com/reachlens/meta-ad-library-scraper.md
- **Developed by:** [Reachlens Tomi](https://apify.com/reachlens) (community)
- **Categories:** Marketing, Lead generation, Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 ads

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

## Facebook & Meta Ad Library Scraper: by website, with EU reach

![Type a website, see every Meta ad it's running](https://api.apify.com/v2/key-value-stores/BP3X8AWW1qET6sR0h/records/hero-v1?signature=etijlFIpHgrv54Z5hWiR)

**Type a website. Get every Facebook and Instagram ad that brand is running right now.**

No page IDs or Ad Library links needed: give it `gymshark.com` and it finds Gymshark's own Facebook pages for you, leaving out look-alike pages with the same name.

👀 **See it on real brands first:** the free [European Ad Watch](https://api.apify.com/v2/key-value-stores/U4yOehVsIM3TPcJxA/records/index?signature=1I5OAEbynn6hyQYUgIK1A) shows what 29 European brands are advertising this week, made with this tool and updated every Monday.

### What you get

**For every ad**

- ⏱️ **How long it has run**: start date and days running
- 📑 **How many copies of it run**: brands copy the ads they put money behind
- 🔗 **The ad itself**: text, headline, button, landing page, image and video
- 🇪🇺 **Who saw it in the EU** (optional): people reached by country, age and gender, plus the targeting and who paid

**For every brand, one summary row**

- 📊 How many ads Meta shows for them, and how many different creatives that is
- 🆕 How many of the ads read started this week and this month
- 🏆 The 5 ads they back hardest
- 🔄 What's new and what stopped since your last run, if you run it on a schedule

### How to use it

1. Add **websites** (or Facebook pages, page IDs or brand names), one per line.
2. Choose **Every running ad**, or **One row per advertiser** to check many companies cheaply.
3. Click **Start**. Download the result as Excel, CSV or JSON, or send it to Google Sheets, Make, n8n, Zapier or your AI agent.

**Tip:** schedule it weekly, and each run tells you which of your competitors' ads are new.

### Pricing

You pay only for results:

| What | Price |
|---|---|
| Each brand that is advertising | $0.02 |
| Each ad | $0.0015 ($1.50 per 1,000 ads) |
| EU reach for an ad (optional) | $0.003 |
| Saved copy of an ad's image (optional) | $0.001 |

- Brands that aren't advertising, and websites that couldn't be read, cost nothing.
- A run never goes over the spending limit you set.

**Examples:** 10 competitors with 50 ads each costs **$0.95**. Checking whether 1,000 companies advertise costs **at most $20**, and nothing for the ones that don't.

### Example: one ad

```json
{
  "pageName": "HelloFresh",
  "headline": "Spare bis zu 120 €",
  "startDate": "2026-09-17",
  "daysRunning": 22,
  "copiesRunning": 3,
  "platforms": ["facebook", "instagram", "threads"],
  "format": "video",
  "cta": "Order now",
  "landingDomain": "hellofresh.de",
  "isNewSinceLastRun": false,
  "euAudience": {
    "reach": 2270985,
    "countries": [{ "country": "DE", "reach": 2297479 }],
    "genderSplit": { "female": 0.71, "male": 0.25, "unknown": 0.03 },
    "topAgeGroup": "25-34",
    "payer": "HelloFresh SE"
  },
  "adLibraryUrl": "https://www.facebook.com/ads/library/?id=1201251448800306"
}
```

### Example: one brand

```json
{
  "input": "elixia.fi",
  "status": "advertising",
  "matchedBy": "Linked from elixia.fi",
  "activeAds": 49,
  "libraryTotal": 49,
  "distinctCreatives": 12,
  "startedLast7Days": 11,
  "longestRunningDays": 49,
  "mostBackedAds": [{ "copiesRunning": 12, "daysRunning": 49, "headline": "Aloita tästä 💙" }],
  "newSinceLastRun": 0,
  "stoppedSinceLastRun": 4
}
```

In **Every running ad** mode, these brand rows are saved in the run's storage under `OVERVIEW`.

### Good to know

- **Running ads only.** That's what Meta's library lists. With a schedule, stopped ads are counted from your second run.
- **No spend or clicks.** No ad library publishes them, and this Actor doesn't guess them. Reach is published only for ads shown in the EU.
- **"Copies running" is a signal, not proof** that an ad is profitable. It shows where a brand puts its weight.
- **Up to 500 ads per brand, in the order Meta lists them**, which is not by date (set **Max ads per advertiser**; 100 when left empty). Read them all for exact counts of new ads. The summary shows how many Meta lists next to how many were read, so nothing is silently missing.
- **EU reach by country can add up to a bit more than the total**: Meta counts a person once in the total, but in every country they were reached in.
- **Saved images are what Meta publishes.** For video ads that's the preview frame, sometimes a small one.

### For AI agents and automations

- **AI agents** (Claude, ChatGPT, Cursor) can run it through Apify's MCP server. Ask for **One row per advertiser** first: one short row per brand fits an agent's context.
- **Clay, n8n, Make, Zapier:** run it per company with the website as input. Field names stay stable; new fields are only added.
- It keeps three small stores in your account so later runs are faster and can say what changed (`reachlens-meta-lookups`, `-history`, `-images`). Delete them to start fresh.

Also by Reachlens: [Google Ads Transparency Scraper](https://apify.com/reachlens/google-ads-transparency-scraper), the same idea for Google Search, YouTube and Display ads, including the words inside image ads.

# Actor input Schema

## `searches` (type: `array`):

One per line. A website (gymshark.com) finds the brand's own Facebook pages for you: pages linked from the site and pages whose ads land on it. You can also give a Facebook page link, a page ID, an Ad Library link, or a brand name.

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

Ads shown in this country, as Meta's Ad Library filters them.

## `maxAdsPerAdvertiser` (type: `integer`):

Running ads to read for each input, in the order Meta lists them (not by date), up to 500. When empty: 100 (30 in one-row-per-advertiser mode, where Meta's own total gives the count). The summary says how many Meta shows.

## `output` (type: `string`):

Every ad, or one row per advertiser (is it advertising, how many ads and creatives, formats, landing pages, its most-copied creatives). The per-advertiser row is the cheapest way to check many companies.

## `euAudience` (type: `boolean`):

For ads shown in the EU, Meta publishes how many people each ad reached, by country, age and gender, and its targeting. Charged only for ads where Meta publishes it.

## `euAudienceMaxAds` (type: `integer`):

Reads EU reach for this many of each advertiser's ads (the first ones read).

## `trackChanges` (type: `boolean`):

Remembers what each input showed last time (in your own storage), so a scheduled run flags new ads and counts stopped ones.

## `saveImages` (type: `boolean`):

Meta's image links stop working after a few days. This saves each ad's picture (a video's preview frame) in your Apify storage and adds a lasting link (savedImageUrl). Charged per picture saved; pictures saved by earlier runs are reused for free.

## `proxy` (type: `object`):

Apify's datacenter proxies read Meta's library well and keep runs fast and cheap; when Meta slows a read, the retry goes through residential proxies automatically, unless you pick proxy groups yourself.

## Actor input object example

```json
{
  "searches": [
    "gymshark.com"
  ],
  "country": "ALL",
  "maxAdsPerAdvertiser": 20,
  "output": "ads",
  "euAudience": false,
  "euAudienceMaxAds": 50,
  "trackChanges": true,
  "saveImages": false,
  "proxy": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One row per running ad (days running, copies running, text, landing page, media, EU reach when asked), or one row per advertiser in 'One row per advertiser' mode.

## `overview` (type: `string`):

One row per website, page or brand searched: running ads and Meta's own count, distinct creatives, new ads in 7 and 30 days, most-backed ads, new and stopped since the last run, and notes on anything the run couldn't read.

# 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 = {
    "searches": [
        "gymshark.com"
    ],
    "maxAdsPerAdvertiser": 20,
    "proxy": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("reachlens/meta-ad-library-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 = {
    "searches": ["gymshark.com"],
    "maxAdsPerAdvertiser": 20,
    "proxy": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("reachlens/meta-ad-library-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 '{
  "searches": [
    "gymshark.com"
  ],
  "maxAdsPerAdvertiser": 20,
  "proxy": {
    "useApifyProxy": true
  }
}' |
apify call reachlens/meta-ad-library-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,reachlens/meta-ad-library-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/SVDejOCKsUfHgysK6/builds/3BWPMJrGgnufNFVxa/openapi.json
