Meta Ad Spend Scraper: Advertiser Spend by Country
Pricing
from $0.12 / 1,000 advertiser spend rows
Meta Ad Spend Scraper: Advertiser Spend by Country
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.
Pricing
from $0.12 / 1,000 advertiser spend rows
Rating
0.0
(0)
Developer
Automation Craft
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Categories
Share
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
- Open the Actor and keep the prefilled input: the United States, the period
yesterday, 20 advertiser rows. - Change Countries to the two letter codes or English names you need (for example
GB,India,CA) and pick a Period. - Set Maximum advertiser rows to the number of advertisers you want, highest spend first.
- Click Start. The top 20 of the US report takes a few seconds on the platform.
- 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
{"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 toexactto keep only rows whose page name or disclaimer is exactly the term (the others are read, counted and free). Thelifelongperiod 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'senginesays 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:
{"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_rowscoverage row. - It does not sort the
lifelongperiod 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
lifelongreport 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 moderegions, andminSpendnarrows 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
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
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
import osfrom apify_client import ApifyClientclient = 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.
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
- Facebook Ads Library Scraper - Ad Library & Spy
- Instagram Ads Library Scraper - Creatives, Video
- Snapchat Political Ads Scraper: Spend & Targeting
- Google Ads Transparency Scraper - Decoded Creatives
- LinkedIn Ad Library Scraper: Ads by Company
- TikTok Ads Library Scraper: EU Ads, No Login
Changelog
- 0.1 (2026-10-08): first release.