mcp-meta-ad-library-monitor
Search Meta's Ad Library through Apify for a company's Facebook and Instagram ads and return one flat row per matching ad.
Look up ads by company name or domain, with an advertiser identity gate to reject mismatched pages.
Filter by country audience, active/inactive status, ad type, media type, and maximum rows returned.
Retrieve ad creative text, headline, delivery dates, publisher platforms, and Meta snapshot URL.
Use caching controls and spending caps, and get coverage notes plus matched/rejected advertiser counts.
Perform read-only, point-in-time checks; schedule repeated calls to monitor changes over time.
Requires your own Meta access token and an Apify token; each run consumes Apify credits.
Political/issue ads may include banded impressions and spend; organic posts and follower counts are not covered.
Finds a company's active Facebook ads through the Meta Ad Library API, returning ad creative, delivery details, and snapshot URLs.
Finds a company's active Instagram ads through the Meta Ad Library API, returning ad creative, delivery details, and snapshot URLs.
Searches Meta's Ad Library for a company's active and historical ads, returning ad creative, delivery dates, publisher platforms, and permanent snapshot URLs.
Meta Ad Library Monitor MCP Server
An MCP server that finds a company's active Facebook and Instagram ads through the Meta Ad Library API. It wraps the Mamba Labs Meta Ad Library Monitor actor on Apify and returns Clay-ready flat JSON rows to any MCP client.
What's Inside
Related MCP server: mcp-people-finder
What it does
Give it a company name or domain and your own Meta access token, and it searches the Meta Ad Library and returns one flat row per ad: creative text, headline, delivery dates, the Meta surfaces the ad ran on, and Meta's permanent snapshot URL for the rendered ad.
Read the coverage first, because it decides whether this tool is any use to you. It reads Meta's Ad Library Graph API, which is the only route Meta sanctions, and that API publishes two things: every ad delivered to an audience in the EU, whatever the ad is about, and social issue, election and politics ads worldwide. So an EU heavy list gets good coverage of ordinary commercial advertising, while a US or UK list of ordinary product ads mostly comes back not_found. That is Meta's dataset rather than a fault in the lookup, and every row carries a coverage note saying what the search could have found. Impressions and spend exist for political ads only and arrive as bands, so a null there is not zero spend.
All of the searching runs on Apify. This package is a thin client that calls the actor and hands back the result unchanged.
Quick start
You need Node.js 18 or newer and an Apify account with an API token.
Add this to your Claude Desktop config:
{
"mcpServers": {
"mamba-meta-ad-library-monitor": {
"command": "npx",
"args": ["-y", "@mambalabsdev/mcp-meta-ad-library-monitor"],
"env": {
"APIFY_TOKEN": "your-apify-token"
}
}
}
}Get your token at https://console.apify.com/account/integrations, paste it in, and restart Claude Desktop. The find_meta_ads tool will be available.
You also need your own Meta app access token, free to create at developers.facebook.com. Set it as META_ACCESS_TOKEN in the same env block to keep it out of the chat transcript, or pass it per call as the metaAccessToken tool argument. With neither, the tool returns an error before any Apify run starts, so a missing token costs nothing.
Prerequisites
Node.js 18 or newer
An Apify account with an API token
Your own Meta app access token, free at developers.facebook.com. The Ad Library API is not open, so this is required.
A verified identity on your Meta account if you want political and issue ad data. That is Meta's requirement, not ours.
Example prompts
"Is gymshark.com running Facebook ads in the EU right now? Here is my Meta token."
"Show me the last 25 active ads for this company across EU audiences."
"Find video ads only for this advertiser, active and inactive."
"Search the Meta Ad Library for this brand in the UK and tell me what the coverage note says."
Inputs
company_domain(optional): bare company domain, for examplegymshark.com. Used to derive the advertiser search term when no company name is given, and used by the identity gate to check that a matched advertiser page really is this company.company_name(optional but strongly recommended): Meta advertiser search is a fuzzy text search over page names, so the company name is what the identity gate compares a matched page against. Without it the gate falls back to the domain stem, which is weaker.metaAccessToken(required unlessMETA_ACCESS_TOKENis set in the server environment): your own Meta app access token, free to create at developers.facebook.com. The Ad Library API is not open, so a call with neither returns an error and starts no run.ad_reached_countries(optional): which country audiences to search. One ofEU,GB,US,DE,FR,NL,ES,IT,IEorALL_EU_PLUS_UK. Meta requires this parameter and a request without it fails outright. The EU set is where the Ad Library covers all ads rather than only political ones, so it is the default.ad_active_status(optional):ACTIVE,ALLorINACTIVE.ACTIVEis the default because a currently running ad is the buying signal.ALLis what you want for a creative history or a competitive teardown.ad_type(optional):ALLreturns every ad the Ad Library holds for those countries.POLITICAL_AND_ISSUE_ADSnarrows to the political archive, which is the only archive carrying impressions and spend and which requires a verified identity on your Meta account.media_type(optional):ALL,IMAGE,VIDEO,MEMEorNONE. Useful for a creative teardown where you only care about video.maxAds(optional): how many ad rows to return per company. One of10,25,50or100. This is a cost dial, not a change of answer: the row always reports how many ads matched before the cap.skipCache(optional): when false (the default) a successful lookup is cached for seven days and reused. Set true to force a fresh fetch.max_charge_usd(optional): spending cap for this call, in USD. The actor stops before any charge that would take the run past this amount and keeps every row already charged.
Output
The tool returns the actor's flat JSON rows, one per ad, in snake_case with no nested objects. advertiser_match says how the advertiser page was matched and advertisers_rejected counts the ones the identity gate turned away. coverage_note states what the search could have found, so an empty result is readable. impressions and spend are populated for political and issue ads only. See the Apify Store page for the full output schema.
Example output
{
"degraded": false,
"degradation_reason": null,
"company_domain": "gymshark.com",
"company_name": "Gymshark",
"page_id": "102590181603009",
"page_name": "Gymshark Women",
"advertiser_match": "name_match",
"advertisers_rejected": 9,
"ad_id": "2824771397896004",
"ad_creative_body": "Hol dir die soften, leichten Gymsets fürs Training (und den chaotischen Alltag) ✨",
"ad_creative_link_title": "Everyday Seamless ab 30 € 💸",
"ad_creation_time": "2026-08-21",
"ad_delivery_start_time": "2026-08-21",
"ad_delivery_stop_time": null,
"ad_snapshot_url": "https://www.facebook.com/ads/library/?id=2824771397896004",
"publisher_platforms": "facebook, instagram, audience_network, messenger, threads",
"languages": "de",
"impressions": null,
"spend": null,
"currency": null,
"ads_matched": 10,
"coverage_note": "Searched EU audiences, where the Ad Library covers all ads, plus non EU audiences where it covers only political and issue ads. A commercial advertiser outside the EU is legitimately absent.",
"coverage": 1,
"fetch_status": "ok",
"run_date": "2026-08-23T05:50:09.867Z"
}Features
One flat row per ad, with creative text, headline and delivery dates
Meta's own permanent snapshot URL for each rendered ad
The Meta surfaces an ad ran on, in
publisher_platformsReads Meta's sanctioned Ad Library Graph API and no other route
A coverage note on every row, so an empty result is readable
Advertiser identity gate, with rejected candidates counted
Pricing
You pay per event on Apify, billed to your own Apify account. Prices from the live pricing record, read 2026-10-16:
Event | Price per event (USD) | Fires when |
| $0.00005 | Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). |
| $0.004 on the Free plan, down to $0.0028 on higher Apify plans | Once per company for which the Ad Library was searched and a non degraded result was produced, whether or not any ads were found. An advertiser with no ads fires this once and nothing else, because looking and finding nothing is a real answer and it is the work you asked for. A degraded row, where no search ran, fires nothing. |
| $0.002 on the Free plan, down to $0.0014 on higher Apify plans | Once per ad row actually returned, after the identity gate. Ads belonging to a page that failed the gate are not returned and are not charged: the work was done and the honest answer is that those ads are not this company. |
The actor's Apify page carries the current prices. Running this server consumes Apify credits.
Full actor documentation
This server is a thin client and holds no search logic. For the complete input and output reference, pricing, and run history, see the Apify Store page:
https://apify.com/mambalabs/meta-ad-library-monitor
Mamba Labs GTM Suite
This server is one of the Mamba Labs GTM Suite MCP servers. Every actor in the suite takes a domain or a company and returns one flat row, so they stack in the same Clay table without reshaping anything. The actor behind this server is the Meta Ad Library Monitor, immutable Apify actor ID J1GWlSXfSGU3u8Wng.
Built by Mamba Labs | npm | Apify Store
License
MIT
Built by Mamba Labs. https://apify.com/mambalabs
Available Tools
1 toolfind_meta_adsFind Meta AdsARead-onlyIdempotent
Search the Meta Ad Library for a company's ads through Facebook's sanctioned Graph API and return ONE FLAT ROW PER AD with creative text, headline, delivery dates, the Meta surfaces it ran on and Meta's permanent snapshot URL for the rendered ad. COVERAGE IS NOT UNIVERSAL: the Ad Library holds all ads only in the EU and only political and issue ads elsewhere, so a commercial advertiser outside the EU is legitimately absent and every row carries a coverage note saying what the search could have found. Requires the caller's own Meta app access token, as the metaAccessToken argument or the META_ACCESS_TOKEN environment variable. Use it to check whether a company advertises on Facebook and Instagram right now or to pull a creative history; each call is a point in time read, so monitoring means calling it on a schedule and comparing rows. Not for organic posts or follower counts, which the brand presence mappers cover. Impressions and spend exist for political ads only and arrive as bands, so a null there is not zero spend. Read only; requires an APIFY_TOKEN and consumes Apify credits per call.
| Name | Required | Description | Default |
|---|---|---|---|
| maxAds | No | How many ad rows to return per company. This is a cost dial, not a change of answer: the row always reports how many ads matched before the cap. | |
| ad_type | No | ALL returns every ad the Ad Library holds for those countries. POLITICAL_AND_ISSUE_ADS narrows to the political archive, which is the only archive that carries impressions and spend, and which requires a verified identity on your Meta account. | |
| skipCache | No | Default false: a successful lookup is cached for seven days and reused, which costs nothing on a repeated run. Set true to force a fresh fetch. | |
| media_type | No | Narrow to a creative format. Useful for a creative teardown where you only care about video, and irrelevant for a simple "are they advertising" check. | |
| company_name | No | Strongly recommended here. Meta advertiser search is a fuzzy text search over page names, so the company name is what the identity gate compares a matched page against. Without it the gate falls back to the domain stem, which is weaker. | |
| company_domain | No | Bare company domain, for example gymshark.com. Used to derive the advertiser search term when no company name is given, and used by the identity gate to check that a matched advertiser page really is this company. | |
| metaAccessToken | No | YOUR OWN Meta app access token, free to create at developers.facebook.com. Required unless the server was started with the META_ACCESS_TOKEN environment variable, which keeps the token out of the chat transcript; the Ad Library API is not open, so with neither the call returns an error before any Apify run starts. Political and issue ad data additionally requires a verified identity on your Meta account, which is a Meta requirement. | |
| ad_active_status | No | Whether to return currently running ads, stopped ads, or both. ACTIVE is the default because a currently running ad is the buying signal; ALL is what you want for a creative history or a competitive teardown. | |
| ad_reached_countries | No | Which country audiences to search. This parameter is REQUIRED by Meta and a request without it fails outright. The EU set is where the Ad Library covers ALL ads rather than only political ones, so it is the default. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only/idempotent/open-world, but the description adds substantial non-structural context: coverage is not universal (EU vs political-only elsewhere, with coverage notes on every row), the caller must supply their own Meta app token or META_ACCESS_TOKEN, political data needs a verified identity, Apify credits are consumed, null impressions/spend mean 'not reported' rather than zero, and each call is a point-in-time read. That is exactly the behavioral burden the annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It leads with purpose and return shape, then coverage caveats, then auth, then usage, then exclusions — a sensible priority order with essentially no filler sentences. It is dense and long, and a few clauses (e.g., restating the EU coverage rule) could be tightened, which keeps it from a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 9 parameters, no required fields, no output schema, and a complex external API, the description carries everything an agent needs: what a row contains, the coverage trap that produces false negatives, token/credit prerequisites, idempotency via caching, and the point-in-time nature. Nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with rich per-parameter descriptions, so the baseline is 3. The description still adds cross-cutting meaning over the schema: it explains that the row always reports total matches before the maxAds cap, that caching makes repeated runs free, and that ad_reached_countries is what determines whether coverage is universal or political-only.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence gives a specific verb (search), a specific resource (Meta Ad Library / Facebook Graph API), and even the return shape (one flat row per ad with named fields), so an agent knows exactly what it gets back. It has no siblings to disambiguate against, so nothing is left for inference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states the two legitimate uses ("check whether a company advertises... right now or to pull a creative history"), explains the monitoring pattern (call on a schedule and diff rows), and explicitly excludes organic posts and follower counts by naming the mappers that cover them. That is when-to-use, how-to-use repeatedly, and when-not-to-use in one place.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v1.1.1- Changed
find_meta_ads8 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / ad_active_status / descriptionPrevious value: -"Whether to return currently running ads, stopped ads, or both. ACTIVE is the default because a currently running ad is the buying signal; ALL is what you want for a creative history or a competitive teardown. Sent as a string for Clay compatibility."New value: +"Whether to return currently running ads, stopped ads, or both. ACTIVE is the default because a currently running ad is the buying signal; ALL is what you want for a creative history or a competitive teardown." - changed
Input schema / properties / ad_reached_countries / descriptionPrevious value: -"Which country audiences to search. This parameter is REQUIRED by Meta and a request without it fails outright. The EU set is where the Ad Library covers ALL ads rather than only political ones, so it is the default. Sent as a string for Clay compatibility."New value: +"Which country audiences to search. This parameter is REQUIRED by Meta and a request without it fails outright. The EU set is where the Ad Library covers ALL ads rather than only political ones, so it is the default." - changed
Input schema / properties / ad_type / descriptionPrevious value: -"ALL returns every ad the Ad Library holds for those countries. POLITICAL_AND_ISSUE_ADS narrows to the political archive, which is the only archive that carries impressions and spend, and which requires a verified identity on your Meta account. Sent as a string for Clay compatibility."New value: +"ALL returns every ad the Ad Library holds for those countries. POLITICAL_AND_ISSUE_ADS narrows to the political archive, which is the only archive that carries impressions and spend, and which requires a verified identity on your Meta account." - changed
Input schema / properties / maxAds / descriptionPrevious value: -"How many ad rows to return per company. This is a cost dial, not a change of answer: the row always reports how many ads matched before the cap. Sent as a string for Clay compatibility."New value: +"How many ad rows to return per company. This is a cost dial, not a change of answer: the row always reports how many ads matched before the cap." - changed
Input schema / properties / media_type / descriptionPrevious value: -"Narrow to a creative format. Useful for a creative teardown where you only care about video, and irrelevant for a simple \"are they advertising\" check. Sent as a string for Clay compatibility."New value: +"Narrow to a creative format. Useful for a creative teardown where you only care about video, and irrelevant for a simple \"are they advertising\" check." - changed
Input schema / properties / metaAccessToken / descriptionPrevious value: -"YOUR OWN Meta app access token, free to create at developers.facebook.com. REQUIRED: the Ad Library API is not open. Political and issue ad data additionally requires a verified identity on your Meta account, which is Meta requirement and not ours. Marked secret, so the value never renders on this page."New value: +"YOUR OWN Meta app access token, free to create at developers.facebook.com. Required unless the server was started with the META_ACCESS_TOKEN environment variable, which keeps the token out of the chat transcript; the Ad Library API is not open, so with neither the call returns an error before any Apify run starts. Political and issue ad data additionally requires a verified identity on your Meta account, which is a Meta requirement." - changed
Input schema / properties / skipCache / descriptionPrevious value: -"When \"false\" (default) a successful lookup is cached for seven days and reused, which costs you nothing on a repeated run. Set \"true\" to force a fresh fetch. Sent as a string for Clay compatibility."New value: +"Default false: a successful lookup is cached for seven days and reused, which costs nothing on a repeated run. Set true to force a fresh fetch."
1 tool update
v1.0.1- First observed
find_meta_ads
TDQS
Scored across 1 tool
With a single tool there is no possibility of misselection between tools. The description also explicitly bounds the tool's scope (paid Meta ads only, read-only, not organic posts or follower counts), so its boundary against adjacent capabilities is clear.
The lone name 'find_meta_ads' follows a clean verb_noun snake_case convention that matches the domain vocabulary. Nothing in the set deviates from that pattern.
A single tool is thin for a server explicitly framed as an ad 'monitor', which implies repeated reads, comparison, or advertiser discovery. It does one job well, but the surface feels minimal relative to the stated purpose.
Read-only search is the right shape for the public Ad Library, and the one tool covers the primary advertiser lookup. However, there is no way to fetch a specific ad by ID or snapshot, no advertiser/keyword discovery, and no pagination or multi-company batch, leaving notable gaps for monitoring workflows.
Maintenance
Related MCP Connectors
Hosted Meta Ads MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
Apify MCP — run web-scraping Actors and fetch their dataset results.
Hosted MCP server for DataLikers — Instagram & TikTok data API. 51 tools: Instagram user search by demographics (gender/age/race/country/city), profiles, bulk lookup, engagement, posts & reels, comments, hashtags, locations, stories, highlights, music, business accounts, top users; TikTok users, videos, comments, hashtags, playlists and top charts. Streamable HTTP, Bearer API key. Free tier: 100 requests on signup at https://datalikers.com/p/1by27bwg
17 data tools in one MCP server, run on Apify: Google Shopping, Flights, Hotels, News, Images, Videos, Ads Transparency, Jobs and Trends; YouTube transcripts; AI visibility checks; Google Maps leads; App Store and Google Play reviews. Pay per result. Sign in with Apify (OAuth) or an API token.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProduction MCP server for querying the official Meta Ad Library API to search and retrieve ads data without scraping.-
- AlicenseAqualityAmaintenanceMCP server for the Mamba Labs People Finder & Email Verifier actor on Apify. Give it a company domain, name or LinkedIn URL and it returns the people at that company who match your role, seniority and department filters, each as a structured contact record with an optional verified business email.165 npmMIT
- AlicenseAqualityAmaintenanceMCP server for the Mamba Labs Company Contact Details Extractor actor on Apify. Find a company contact page and extract role emails, a phone number and a postal address.164 npmMIT
- AlicenseAqualityAmaintenanceMCP server for the Mamba Labs GitHub Organization Signal Scanner actor on Apify. Resolve a company domain to its GitHub organization with repo, language and activity signals.186 npmMIT