# Meta Ad Spend Scraper: Advertiser Spend by Country (`automation_craft/meta-ad-spend-scraper`) Actor

Scrape Meta's Ad Library Report, no login or API key: every advertiser of ads about social issues, elections or politics in 205 countries, ranked by spend. Get page name, page ID, disclaimer, amount spent, number of ads and spend by region. JSON, CSV or API; pay per row, monitors bill only changes.

- **URL**: https://apify.com/automation_craft/meta-ad-spend-scraper.md
- **Developed by:** [Automation Craft](https://apify.com/automation_craft) (community)
- **Categories:** News, Social media, Marketing
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.12 / 1,000 advertiser spend rows

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

### Meta Ad Spend Scraper: Advertiser Spend by Country

**Meta ad spend scraper for the Ad Library Report**: every advertiser that ran ads about social issues, elections or politics in a country, ranked by the amount spent, as clean rows, with no login and no API key.

Meta publishes the Ad Library Report every day for 205 countries. For each advertiser it lists the page name, the page ID, the funding disclaimer, the amount spent and the number of ads, for yesterday, the last 7, 30 or 90 days or lifelong, plus the spend by state, province or nation. This Actor returns that report as a dataset you can export as JSON, CSV or Excel, read over the API or schedule. The US report holds about 8,000 advertisers a day, 31,000 over 90 days and 524,000 lifelong.

The report covers ads about social issues, elections or politics only. It is not a report of commercial advertising: it holds no spend for ordinary brand ads.

### Quick start

1. Open the Actor and keep the prefilled input: the United States, the period `yesterday`, 20 advertiser rows.
2. Change **Countries** to the two letter codes or English names you need (for example `GB`, `India`, `CA`) and pick a **Period**.
3. Set **Maximum advertiser rows** to the number of advertisers you want, highest spend first.
4. Click **Start**. The top 20 of the US report takes a few seconds on the platform.
5. Open the **Advertisers** view of the dataset and export it as JSON, CSV or Excel, or call the Actor from the API (examples below).

To track changes, give the same **Monitor name** to a scheduled run: each run then delivers only advertisers that are new or whose figures changed.

### What you get

Every run writes paid rows (advertiser rows, region rows) and free rows (one coverage row per subject, status rows when something needs saying, and one summary). The `type` field says which.

#### Advertiser rows (`type: advertiser`, billed as Advertiser spend row)

Fill rates were measured on the UK ranked list read on the platform (yesterday, report of 2026-10-06, 510 rows) and on Meta's US report file for the same date (8,231 rows).

| Field | What it holds | Filled (UK list / US file) |
|---|---|---|
| `type` | `advertiser` | 100% / 100% |
| `country`, `countryName` | the report country: two letter code and English name | 100% / 100% |
| `timePreset` | `yesterday`, `last_7_days`, `last_30_days`, `last_90_days` or `lifelong` | 100% / 100% |
| `reportDate` | the date of the report the row came from (YYYY-MM-DD) | 100% / 100% |
| `rank` | the position in the list as Meta sorts it (1 = highest) | 100% / 100% |
| `pageId` | the Facebook Page ID as a string; Meta writes `0` for Instagram only advertisers | 100% / 100% |
| `pageName` | the advertiser's page name | 100% / 100% |
| `disclaimer` | the "paid for by" disclaimer; `null` when the ads ran without one | 84.5% / 96.3% |
| `hasDisclaimer` | `true` when a disclaimer is present | 100% / 100% |
| `amountSpent` | the amount spent in the period, a number in the report's currency | 100% / 100% |
| `amountSpentIsUpperBound` | `true` when Meta reported the spend as 100 or less (its lowest bucket; `amountSpent` is then 100) | true on 81.2% / 65.3% |
| `amountSpentText` | the amount as Meta wrote it, for example `179834` or `≤100` | 100% / 100% |
| `currency` | the report's currency code (USD, GBP, INR), the one Meta keeps the country's report in; the breakdown by billing currency is in `detailedSpends` | 100% / 100% |
| `numberOfAds` | the advertiser's number of ads in the Library for the period | 100% / 100% |
| `pageUrl` | the advertiser's Facebook page; `null` for page ID `0` | 100% / 99.8% |
| `adLibraryUrl` | the advertiser's political ads in Meta's Ad Library for the country; `null` for page ID `0` | 100% / 99.8% |
| `reportUrl` | Meta's report page for the country | 100% / 100% |
| `source` | `graphql` (the ranked list) or `file` (the daily report file) | 100% / 100% |
| `scrapedAt` | when the row was read (ISO 8601, UTC) | 100% / 100% |
| `detailedSpends` | the spend broken down by the advertiser's billing currency, as Meta gives it (ranked list only) | 100% / not in the file |
| `spendInOtherCurrency` | `true` when Meta shows the breakdown in another currency than the report's (ranked list only) | 100% / not in the file |
| `pageIconUrl` | the page's icon image (ranked list only) | 100% / not in the file |
| `pageDeleted` | `true` when Meta marks the page deleted (ranked list only) | 100% / not in the file |
| `reportRowId` | Meta's id of the row in the ranked list (ranked list only) | 100% / not in the file |
| `searchTerm`, `nameMatch` | the search term that found the row and `contains` or `exact` (search runs only) | on every row of a search |
| `changeType` | `new` or `changed` (monitor runs only) | on every row of a monitor run |

The 15.5% of UK rows without a disclaimer and the 34.7% of US rows above the bucket are what Meta published for that day, not gaps in the reading. Meta answers a few small bucket rows of the ranked list without data (7 of 517 in the UK sample); they are skipped, counted as `rowsWithoutData` in the coverage row and free, and they are complete in the report file (mode `report`).

#### Region rows (billed as Region spend row)

`type: regionTotal` is the spend of one state, province or nation: `country`, `countryName`, `timePreset`, `reportDate`, `rank`, `region`, `amountSpent`, `amountSpentIsUpperBound`, `amountSpentText`, `currency`, `numberOfAds`, `reportUrl`, `source`, `scrapedAt`. The US report has 57 regions. `numberOfAds` is `null` on these rows, because Meta's region table carries no ad count; `currency` is the report's currency, and in mode `regions` `detailedSpends` carries the breakdown by billing currency where Meta gives one.

`type: regionAdvertiser` is one advertiser's spend inside one region (mode `report` with `includeRegionAdvertisers`): `country`, `countryName`, `timePreset`, `reportDate`, `rank`, `region`, `pageId`, `pageName`, `disclaimer`, `hasDisclaimer`, `amountSpent`, `amountSpentIsUpperBound`, `amountSpentText`, `currency`, `pageUrl`, `adLibraryUrl`, `reportUrl`, `source`, `scrapedAt`. Meta's per region tables carry no ad count, so these rows have no `numberOfAds`. The US file for the 2026-10-06 report held 128,659 such rows over 57 regions, 96.0% with a disclaimer and 96.0% in the bucket of 100 or less.

#### The coverage row (`type: coverage`, free)

One per country and period, and per search term when you give terms. It says what happened to that subject:

| Field | What it holds |
|---|---|
| `country`, `countryName`, `timePreset`, `period`, `reportDate`, `searchTerm` | the subject and the report date read |
| `status` | `complete`, `no_rows`, `partial`, `failed`, `not_read` or `refused` |
| `complete`, `endOfListReached` | whether the subject was read to its end |
| `engine` | `graphql` (the ranked list) or `file` (the report file) |
| `rowsInReport`, `rowsRead`, `rowsDelivered`, `regionRowsDelivered` | rows Meta reports, rows read, rows delivered |
| `rowsDeliveredBefore`, `rowsNew`, `rowsChanged` | the monitor's count: known (free), new, changed |
| `rowsBelowMinSpend`, `rowsNotMatchingName`, `rowsAlreadyInThisRun` | rows left out free, by reason |
| `rowsNotDelivered`, `regionRowsNotDelivered` | rows read but not delivered because a cap or a stop was reached |
| `rowsWithoutData`, `rowsUnreadable` | rows Meta answered without data, lines that could not be read |
| `pagesRead`, `callsMade`, `bytesRead`, `seconds` | the work done |
| `regionTotalsInReport`, `regionFilesInReport`, `regionFilesRead` | the region tables of the report file |
| `stoppedBy`, `message`, `notes` | why it stopped, in plain words |

#### Status rows and the summary (free)

A `status` row (`scope`, `key`, `status`, `message`) appears when the input has a problem (one row that lists the problems, and Meta is not asked anything) or when a cap, the charge limit or a stop ended the run early. The last row of every run is the `summary`: rows delivered per kind, the report date used per country, requests made, the monitor's state and the billing per event.

#### Example output row

```json
{
  "type": "advertiser",
  "country": "US",
  "countryName": "United States",
  "timePreset": "yesterday",
  "reportDate": "2026-10-06",
  "rank": 1,
  "pageId": "318975057964832",
  "pageName": "America PAC",
  "disclaimer": "America PAC",
  "hasDisclaimer": true,
  "amountSpent": 179834,
  "amountSpentIsUpperBound": false,
  "amountSpentText": "179834",
  "currency": "USD",
  "numberOfAds": 229,
  "pageUrl": "https://www.facebook.com/318975057964832",
  "adLibraryUrl": "https://www.facebook.com/ads/library/?active_status=all&ad_type=political_and_issue_ads&country=US&view_all_page_id=318975057964832&media_type=all",
  "reportUrl": "https://www.facebook.com/ads/library/report/?country=US",
  "source": "graphql",
  "scrapedAt": "2026-10-08T11:19:29.302Z",
  "detailedSpends": [{ "amount": 179834, "currency": "USD" }],
  "pageIconUrl": "https://scontent-atl3-1.xx.fbcdn.net/v/t39.30808-1/461740820_122135556350332751_4469909543841105104_n.jpg",
  "pageDeleted": false,
  "reportRowId": "1641491187437702"
}
```

### The three modes and the monitor

- **`advertisers`** (the default): Meta's ranked list, read 120 rows a call, highest first, sorted by amount spent, number of ads, page name or disclaimer. Add **search terms** to get the rows whose page name or disclaimer contains the text, in any case, as Meta's own search does; set **name match** to `exact` to keep only rows whose page name or disclaimer is exactly the term (the others are read, counted and free). The `lifelong` period is read from Meta's report file, which is sorted by spend.
- **`report`**: the whole daily report file as rows: every advertiser, then the region totals (`includeRegionTotals`) and every advertiser per region (`includeRegionAdvertisers`) when you switch them on. When the file cannot be read, the ranked list is read instead and the coverage row's `engine` says so.
- **`regions`**: the region totals in one call, one row per state, province or nation.

A **minimum spend** leaves out advertiser rows under that amount, free; it leaves out the per region advertiser rows under it too, and never the region totals. When the list is sorted by spend, the read ends at the first advertiser under the minimum.

**The monitor.** Give **monitorName** (any name up to 100 characters) and the run remembers, under that name, every advertiser row it delivered. The next run with the same name delivers only rows that are new (an advertiser not delivered before under that name) or changed (its amount spent or number of ads differs), and marks each in `changeType` as `new` or `changed`. Unchanged rows are read, counted in the coverage row as `rowsDeliveredBefore` and not charged. Rows that share page id, page name and disclaimer inside one report, compared without regard to case and spacing (Meta publishes a few such pairs: about 2 in 1,000 rows of the US 90 day report, 1 in 8,000 of the daily one) have no identity of their own under a monitor: once a run has met such a pair, every row of it is delivered free and marked `ambiguous` whenever its figures are not the ones delivered before, and never charged. The memory compares reports across dates, so schedule the same countries and period: on `last_90_days` or `lifelong` it delivers the advertisers whose totals moved since the last run; on `yesterday` most figures change every day.

Monitor limits: one monitor remembers one entry per advertiser (its latest figures), up to 60,000 advertisers of one report, so a larger report (the US lifelong report has about 524,000) is refused before any row, with a free row; monitor a shorter period or a search term instead. Two runs on one monitor name at the same time are refused. A monitor works in modes `advertisers` and `report`, not on region rows.

A report date you give must be one Meta still serves (about the last seven): a date without a report ends as a free `refused` coverage row, never as an empty report. After a platform restart of a long run, a subject that was cut is read again with its delivered rows skipped, and gets a second coverage row with its final outcome. A monitor run the platform restarted delivers nothing more: the rows its first attempt delivered stand (charged once), and the next run on that monitor name goes on from the memory.

### How much does it cost to scrape the Meta Ad Library Report?

You pay per row delivered, plus a small start fee per run. Prices per 1,000 rows by Apify plan:

| Event | FREE | BRONZE | SILVER | GOLD |
|---|---|---|---|---|
| Advertiser spend row | $0.20 | $0.20 | $0.15 | $0.12 |
| Region spend row | $0.05 | $0.05 | $0.045 | $0.04 |

The Actor start event costs $0.008 per run on every plan. Platinum and Diamond plans pay the Gold price. The Store pricing card shows the same prices per 1,000 rows: "$0.20 / 1,000" on the Advertiser spend row means 1,000 advertiser rows cost 20 cents on the Free plan, so one row costs $0.0002.

Worked example: the top 100 advertisers of the US report cost 100 x $0.0002 + $0.008 = $0.028 on the Free plan.

What is free:

- coverage rows, status rows and the summary;
- advertiser rows under your minimum spend and rows that do not match an exact name;
- rows a monitor delivered before with the same figures;
- a second copy of a row found twice in one run (two search terms can find one advertiser);
- misses: a search term nobody matches, a country without rows, a report date without a report;
- failures: anything Meta did not answer, and an input with a problem (Meta is not asked).

Each row is charged once per run. A run never charges past the maximum charge you set on it: rows that do not fit are not delivered, and a free status row says so.

### Input

| Field | Also accepted as | What it does |
|---|---|---|
| `mode` | | `advertisers` (default), `report` or `regions` (see above) |
| `countries` | `country`, `countryCode`, `countryCodes` | two letter codes in any case or English names, up to 50 per run; empty means the United States |
| `timePreset` | `period`, `timeRange`, `preset`, `dateRange` | `yesterday` (default, the day before the report date), `last_7_days`, `last_30_days`, `last_90_days` or `lifelong` |
| `reportDate` | `reportDS`, `date` | the report to read, YYYY-MM-DD; empty means the newest report |
| `maxRows` | `maxItems`, `maxResults`, `limit`, `resultsLimit`, `maxAdvertisers` | the most advertiser rows the run delivers and charges, over all countries and terms (1 to 1,000,000; 100 when left out; one run delivers at most 150,000 rows in all, advertiser and region rows together, and a `lifelong` report at most 150,000 advertiser rows, the highest spenders first: the run says so in a status row) |
| `sortBy` | | `spend` (default), `ads`, `page_name` or `disclaimer`, highest first; mode `advertisers` only, and only `spend` for `lifelong` |
| `searchTerms` | `search`, `query`, `queryString`, `advertisers`, `advertiserNames`, `pageNames`, `keyword`, `keywords` | advertiser names or disclaimer text, one per line, up to 200; mode `advertisers` only |
| `nameMatch` | | `contains` (default, what Meta returns) or `exact`; with search terms only |
| `minSpend` | | only advertiser rows (and per region advertiser rows) that spent at least this whole amount in the report's currency; modes `advertisers` and `report`; region totals are not filtered |
| `includeRegionTotals` | | mode `report`: add the region totals table as Region spend rows; read even when `maxRows` cuts the advertiser table |
| `includeRegionAdvertisers` | | mode `report`: add every advertiser per region as Region spend rows (about 130,000 rows a day for the US: set a cap or a maximum charge); read even when `maxRows` cuts the advertiser table |
| `maxRegionRows` | `maxRegions` | the most region rows the run delivers, 0 or empty for no cap; mode `regions`, or `report` with region rows switched on |
| `monitorName` | `memoryName`, `watchName` | a name for the monitor memory, up to 100 characters; modes `advertisers` and `report` |
| `includeRaw` | | `true` adds Meta's own record of each row under `raw` (the list's node, or the file's fields by column name) |

Send each setting under one name only. An unknown field, a value that cannot be used or a setting given in a mode it does not apply to stops the run before any request, with one free status row that lists the problems. `proxyConfiguration`, `proxy` and `debug` are ignored with a warning: the Actor chooses its own route.

Example input:

```json
{
  "countries": ["US", "GB"],
  "timePreset": "last_30_days",
  "searchTerms": ["Planned Parenthood"],
  "maxRows": 200
}
```

### What this Actor does not do

- It does not return spend on commercial ads: Meta's report covers ads about social issues, elections or politics only.
- It does not return per ad data (creatives, ad texts, per ad spend ranges, impressions, audiences): its rows are advertiser totals. Per ad data is in the Ad Library listings linked below.
- It does not read Facebook pages, so it has no page transparency data (page creation date, name changes, admin countries).
- It has no e-commerce enrichment and no video transcripts: neither is in the report.
- It has no impressions per advertiser: the report does not carry them.
- It does not return recent spend in the EU: Meta stopped these ads in the EU in October 2025, so EU countries hold history only and a recent period returns a free `no_rows` coverage row.
- It does not sort the `lifelong` period by anything but spend, and it does not sort lowest first.
- It does not deliver more than 150,000 rows in one run (advertiser and region rows together; a `lifelong` report at most 150,000 advertiser rows, the highest spenders first): the run stops there with a status row and charges nothing for the rest. The US daily file with every region table (about 137,000 rows) fits. The US lifelong report (524,000 advertisers) does not: a run returns its top 150,000 by spend, and the rows below them are only in Meta's own CSV download (there is no "below this amount" filter). The US 90 day file's per region advertiser tables (about 671,000 rows) are beyond one run too and only in Meta's own CSV download; its region totals come from mode `regions`, and `minSpend` narrows the per region rows.
- It does not keep an archive of past daily reports: it reads the report dates Meta still serves.
- It does not read Meta's spend tracker (the email summaries) or the report page's lifetime totals.
- It needs no login, Facebook account or Ad Library API access, and it does not use any.

### API examples

Run the Actor and get the rows in one call (replace `$APIFY_TOKEN` with your Apify API token):

#### curl

```bash
curl -X POST "https://api.apify.com/v2/acts/automation_craft~meta-ad-spend-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"countries": ["US"], "timePreset": "last_30_days", "maxRows": 100}'
```

#### Node.js

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation_craft/meta-ad-spend-scraper').call({
    countries: ['US'],
    timePreset: 'last_30_days',
    maxRows: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((row) => row.type === 'advertiser'));
```

#### Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("automation_craft/meta-ad-spend-scraper").call(
    run_input={"countries": ["US"], "timePreset": "last_30_days", "maxRows": 100}
)
rows = [r for r in client.dataset(run["defaultDatasetId"]).iterate_items() if r["type"] == "advertiser"]
print(rows[:3])
```

### FAQ

#### How do I download the Meta Ad Library Report?

Run this Actor with **mode** `report` and a country: it reads Meta's daily report file and returns every advertiser as a row, plus the region tables when you switch them on. Export the dataset as JSON, CSV or Excel, or read it over the API; no login or Facebook account is needed. One run delivers at most 150,000 rows: the US daily file with every region table fits; of the US lifelong report (524,000 advertisers) a run returns the top 150,000 by spend, or the rows a search term matches.

#### How can I see Facebook political ad spend by state?

Use **mode** `regions` for one row per state, province or nation with the amount spent in the period (57 rows for the United States). For every advertiser's spend inside each state, use **mode** `report` with `includeRegionAdvertisers` switched on.

#### Where can I get Meta political ads spending data?

Meta publishes it in the Ad Library Report: every advertiser that ran ads about social issues, elections or politics in a country, with the amount spent and the number of ads. This Actor returns that report as rows for yesterday, the last 7, 30 or 90 days or lifelong, ranked by spend, for 205 countries.

#### How often is the Ad Library Report updated?

Meta publishes a new report every day, and the newest one is about two days behind today. Every row carries the `reportDate` it came from, and **reportDate** in the input reads one of the recent reports Meta still serves.

#### Does the Ad Library Report include commercial ads?

No. The report covers ads about social issues, elections or politics only, so it holds no spend for ordinary commercial ads; brand names appear only for issue ads they ran. For the ads themselves, commercial ones included, see [Meta Ads Library Scraper - Ad Library, All Filters](https://apify.com/automation_craft/meta-ads-library-scraper).

#### Why does this Actor run with limited permissions?

It runs with Apify's limited permissions, the least privilege level: it reads its input and writes only its own run's storages. The one exception is the monitor: when you give **monitorName**, it opens a named key-value store it creates itself (`meta-ad-spend-monitor-v1-...`) to remember which advertiser rows it delivered. It touches nothing else in your account.

### More data tools by Automation Craft

- [Meta Ads Library Scraper - Ad Library, All Filters](https://apify.com/automation_craft/meta-ads-library-scraper)
- [Facebook Ads Library Scraper - Ad Library & Spy](https://apify.com/automation_craft/facebook-ads-library-scraper)
- [Instagram Ads Library Scraper - Creatives, Video](https://apify.com/automation_craft/instagram-ads-library-scraper)
- [Snapchat Political Ads Scraper: Spend & Targeting](https://apify.com/automation_craft/snapchat-political-ads-scraper)
- [Google Ads Transparency Scraper - Decoded Creatives](https://apify.com/automation_craft/google-ads-transparency-scraper)
- [LinkedIn Ad Library Scraper: Ads by Company](https://apify.com/automation_craft/linkedin-ad-library-scraper)
- [TikTok Ads Library Scraper: EU Ads, No Login](https://apify.com/automation_craft/tiktok-ads-library-scraper)

### Changelog

- 0.1 (2026-10-08): first release.

# Changelog

This Actor's version history is a separate document: https://apify.com/automation_craft/meta-ad-spend-scraper/changelog.md

# Actor input Schema

## `mode` (type: `string`):

advertisers: the ranked list of advertisers by spend (or by ads, page name or disclaimer), with an optional search by name. report: the whole daily report file as rows (every advertiser, and the region tables when switched on). regions: spend by region (state, province, nation) as rows.

## `countries` (type: `array`):

Two letter country codes in any case, or English names: US, GB, CA, AU, IN, BR, and 200 more. One report per country. Leave empty for the United States. The EU countries hold history only: Meta stopped these ads in the EU in October 2025.

## `timePreset` (type: `string`):

The period the spend covers, ending on the report date: yesterday (the day before the report date), the last 7, 30 or 90 days, or lifelong (everything since the report began, 2018 for the US). Leave empty for yesterday.

## `reportDate` (type: `string`):

The date of the report to read (YYYY-MM-DD). Meta publishes a report every day, about two days behind today, and serves the last seven report dates. Leave empty for the newest report; every row carries the report date it came from.

## `maxRows` (type: `integer`):

The most Advertiser spend rows this run may deliver (and charge), over all countries and search terms together. When the field is left out, 100 is used. The whole US report holds about 8,000 advertisers a day, 31,000 over 90 days and 524,000 lifelong; one run delivers at most 150,000 rows in all, and a lifelong report at most 150,000 advertiser rows.

## `sortBy` (type: `string`):

The column Meta sorts the list by, highest first: amount spent (default), number of ads, page name or disclaimer. Leave empty for amount spent.

## `searchTerms` (type: `array`):

One advertiser name or disclaimer text per line, for example Planned Parenthood. Meta returns every row whose page name or disclaimer contains the text (any case); each term gets its own free coverage row. A term nobody matches is free. Mode advertisers only.

## `nameMatch` (type: `string`):

Contains (what you get when the field is left empty): every row Meta returns for the term. Exact: only rows whose page name or disclaimer is exactly the term (case and extra spaces ignored); other rows are read, counted and not charged.

## `minSpend` (type: `integer`):

Only advertisers that spent at least this amount in the report's currency (whole number). Meta reports spends of 100 or less as one bucket, flagged on the row; a minimum above 100 leaves those rows out, free. Modes advertisers and report.

## `includeRegionTotals` (type: `boolean`):

Also deliver the file's region totals table (spend per state, province or nation) as Region spend rows, read even when maxRows cuts the advertiser table.

## `includeRegionAdvertisers` (type: `boolean`):

Also deliver the file's per region advertiser tables (every advertiser's spend inside each region) as Region spend rows, read even when maxRows cuts the advertiser table. The US file holds about 130,000 such rows a day: set a cap below or a maximum charge on the run.

## `maxRegionRows` (type: `integer`):

The most Region spend rows this run may deliver, over all countries together. 0 or left out means no cap (the run's maximum charge still applies). Mode regions, or mode report with region rows switched on.

## `monitorName` (type: `string`):

A name of your choice, up to 100 characters. The memory it opens belongs to this Actor and remembers up to 60,000 advertiser rows per report; a report or list larger than that is refused with a free row (a search term is not size limited). Modes advertisers and report.

## `includeRaw` (type: `boolean`):

Add Meta's own record of each row (the GraphQL node, or the file's fields) under raw.

## Actor input object example

```json
{
  "mode": "advertisers",
  "countries": [
    "US"
  ],
  "timePreset": "yesterday",
  "maxRows": 20,
  "includeRegionTotals": false,
  "includeRegionAdvertisers": false,
  "includeRaw": false
}
```

# Actor output Schema

## `items` (type: `string`):

No description

# 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 = {
    "countries": [
        "US"
    ],
    "timePreset": "yesterday",
    "maxRows": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation_craft/meta-ad-spend-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 = {
    "countries": ["US"],
    "timePreset": "yesterday",
    "maxRows": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation_craft/meta-ad-spend-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 '{
  "countries": [
    "US"
  ],
  "timePreset": "yesterday",
  "maxRows": 20
}' |
apify call automation_craft/meta-ad-spend-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation_craft/meta-ad-spend-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/h3TkLa8MQ6gg9VUAS/builds/6aMLjAwAxuLGSWsl7/openapi.json
