Skip to content

Why Facebook Ad Library Scrapers Keep Breaking (and the Official API Doesn't)

The Ad Library UI is a private contract between Meta's frontend and its backend. The Graph API is a public one with a deprecation policy. That is the whole difference.

11 min read · 20 Aug 2026

Your Ad Library scraper worked in June and returns zero rows today. Nothing in your code changed. The URLs still load in a browser. The marketplace actor you were paying for has an issues tab with other people reporting the same thing, and a maintainer who has not replied in a while.

This happens repeatedly, to almost everyone who collects Meta ad data by scraping, and it is not bad luck or bad engineering. It is the predictable consequence of which interface you chose to depend on.

There are three ways to get this data. They fail differently, they cost differently, and — importantly — the most reliable one is not the best choice for everyone. Here is the honest version of that comparison, including the cases where scraping is simply correct and the official API cannot help you.

The three routes, and how each one fails

Scraping the Ad Library UI

facebook.com/ads/library is a client-side application. The page you see is assembled in the browser from JSON delivered by Meta's internal GraphQL endpoint — the same infrastructure that serves the rest of Facebook's frontend.

That endpoint is not a product. It is an implementation detail of a web app, and it has exactly one consumer that Meta cares about: Meta's own JavaScript, which is redeployed constantly and always ships in lockstep with whatever the backend just changed. There is no version number, no deprecation window, no changelog, and no obligation to anybody. A rename that takes Meta's frontend team ten minutes and breaks nothing internally will empty your dataset.

The failure is rarely a clean error, which is what makes it expensive. A renamed wrapper node means your extractor walks the response, finds nothing to extract, and returns an empty list with an HTTP 200. Your job succeeds. Your row count is zero. Your monitoring is green. This is the ordinary shape of what happens when a platform changes its JSON, and the Ad Library UI is one of the more actively redeployed surfaces on the internet.

Add the parts that have nothing to do with parsing: the UI is behind the same bot detection as the rest of Facebook, so you need residential IPs, you need to look like a browser at the TLS level, and you will still get served a consent interstitial or a checkpoint some fraction of the time. Every one of those is a recurring cost that does not appear in the estimate anyone wrote at the start.

Marketplace actors

The reasonable-sounding middle option: let someone else own the breakage. Apify hosts several Facebook Ad Library scrapers, and the market there is instructive. Checked on 20 August 2026:

Actor Rating Total users Price Maintainer
apify/facebook-ads-scraper 4.19 / 5 ~32,800 from $3.40 / 1,000 ads Apify
curious_coder/facebook-ads-library-scraper 4.75 / 5 ~38,000 $0.75 / 1,000 ads Community

Two honest observations. First, these are real, working, widely used tools — tens of thousands of users each is not a rounding error, and dismissing them would be silly. Second, the community-maintained actor is both cheaper and better rated than the platform's own, which tells you something about where the maintenance energy in this category actually sits.

The structural problem is not quality, it is coupling. An actor is a scraper with a billing wrapper; it depends on exactly the same unversioned internal interface, so it breaks on exactly the same days. What you have bought is not immunity — it is someone else's queue position. If the maintainer is responsive, you are down for hours. If they have moved on, you are down until you fork it. And you find out which kind of maintainer you have on the day it matters.

The one genuinely useful thing the marketplace gives you is a public signal: an actor's issues tab tells you whether a break is yours or everyone's, within minutes. That is worth more than it sounds when you are staring at zero rows at 9am.

The official Graph API

Meta publishes the Ad Library through ads_archive on the Graph API, and it is dull in the way infrastructure should be.

It does not break on frontend deploys because it is not attached to the frontend. It is versioned — you pin a version in the URL path, and Meta's platform versioning policy gives roughly two years of notice before a version is retired. The field list is documented. There is no bot detection to defeat, because you are an authorised caller with a token, so there are no proxies, no fingerprinting, and no consent interstitials. It runs from a plain server IP at effectively zero marginal cost.

It has exactly two failure modes, and both are boring: your token expired, and you got throttled. Long-lived user tokens run about 60 days, which makes the first one a scheduled event you can put in a calendar rather than a surprise. The second is error code 613 and the fix is backoff. Neither requires anyone to reverse-engineer anything.

The reason this holds is not that Meta is generous. It is that the archive exists because EU law requires them to publish it, through an API, and to keep publishing it. Article 39 of the Digital Services Act names programmatic access specifically. Withdrawing it is a compliance failure with a percentage-of-global-turnover price attached, not a product decision someone can make on a Tuesday.

The actual difference, in one sentence

The UI is a private contract between Meta's frontend and Meta's backend, optimised for change. The Graph API is a public contract with a deprecation policy, optimised for stability.

Everything else follows from that. The API is not more reliable because Meta engineers care more about it; it is more reliable because breaking it costs them something and breaking the internal one costs them nothing.

Any time you are choosing between two ways to reach the same data, that is the question worth asking: who else is relying on this interface, and what happens to the owner if it changes?

What each approach costs, honestly

Including the rows that go against the API.

UI scraping Marketplace actor Official Graph API
Time to first row Hours Minutes Days (identity confirmation)
Setup gate Proxies, browser stack An account Government ID, developer app, ads_read
Breaks on frontend deploys Constantly Constantly No
Proxy cost Residential, ongoing Included in the price None
Marginal cost per 1,000 ads Your proxy bill $0.75–$3.40 ~$0
Inactive non-EU commercial ads Whatever was archived Whatever was archived Not available
Creative image/video files Yes, if you render Often yes No — snapshot URL only
CTA button text Yes Sometimes No
Spend / impressions Political ads only Political ads only Political ads only
Rate limit Detection-driven, unpredictable Vendor's problem 200 calls/hour, documented
Multi-platform in one interface No Per-actor No — Meta only
Who fixes it when it breaks You Maintainer's queue Nothing to fix

Read the bold cells. Three of the six rows where the API loses are things a lot of products genuinely need.

Where scraping is simply the right answer

This is the part that gets left out of every version of this argument written by someone with an API to sell, so it goes in the middle rather than the footnotes.

Historical commercial ads. This is the decisive one. Meta keeps political and issue ads for seven years, but all other ads are visible while active and archived for one year after their last impression — and for commercial ads outside the EU, once a campaign stops, it leaves your view. The official API cannot reconstruct what a US brand ran in 2023. Anyone who was scraping and storing at the time can. That is precisely the product that commercial ad-intelligence services sell, and it is a real asset that no amount of API access replicates. If your question is "what has this advertiser tried over three years," an archive someone else has been building for three years beats a live API, and it is not close.

Creative files and the CTA button. The API gives you ad_snapshot_url, a page that renders the ad. It does not give you the image, the video, or the call-to-action button text. If your product shows creatives in a gallery or analyses hooks in ad video, you are rendering pages, and there is no sanctioned alternative.

Platforms with no usable API. LinkedIn publishes an ad library with no official API and no bulk export. TikTok's Commercial Content API is gated behind an application aimed at researchers with a non-commercial commitment. For those two, "use the official API" is not advice, it is a dead end. Scraping or an aggregator is the only route, and pretending otherwise is not being rigorous, it is being evasive.

Speed to a first answer. An actor gets you rows in five minutes. Identity confirmation for the Graph API takes days and can be refused. For a one-off analysis, a pitch deck, or finding out whether the data supports the idea at all, the marketplace option is straightforwardly better and the honest recommendation.

What the alternatives do better

A fair comparison names specifics rather than gesturing.

Aggregators cover ground the official APIs do not. adlibrary.com indexes across roughly eleven ad sources behind one key and one endpoint, with no per-platform app review, and maintains history for ads that have left the source archives. If your requirement is "one query across Meta, TikTok, LinkedIn, Google and YouTube," no combination of official APIs delivers that, and building it yourself means owning four integrations with four different access models — one of which does not exist.

ScrapeCreators has far more of this category built than we do. Per our own competitive research, dated 20 August 2026, they run 13 ad-intelligence endpoints across four ad libraries — Meta, Google Ads Transparency, TikTok Creative Center and LinkedIn — including an ad-transcript endpoint that pulls the spoken audio out of a video ad. We have four endpoints on one ad library and no transcript for ad creative. At $0.99 per 1,000 requests they are also the price leader, with the best-organised documentation in this category. If breadth across ad libraries is your requirement today, that is a straightforward answer and it is not us.

Ad-spy products are selling workflow, not data. AdSpy at $149/month and Foreplay from $49/month, as of August 2026, are frequently described as expensive wrappers on free public data. That framing is only half right. The archive is free; the searchable multi-year index, the saved boards, the creative tagging and the team workflow are the product, and they represent years of collection you cannot start today. If you have a creative strategist rather than an engineer, buying the tool is the correct call and building a pipeline is not.

The pattern that changes the arithmetic: watch, don't re-pull

Whichever route you take, the way most ad-monitoring pipelines waste money is architectural rather than technical.

The instinct is to re-pull an advertiser's full archive on a schedule and diff it locally. For a hundred advertisers on an hourly cron, that is 2,400 full history pulls a day, of which the overwhelming majority return exactly what they returned last time. On a metered API you are paying per call for the privilege of learning that nothing happened; on a scraper you are burning proxy bandwidth and detection budget for the same non-answer.

The shape that works: fetch the advertiser's active ads only, fingerprint the result, and act when the fingerprint changes. New ad IDs appearing and old ones disappearing is the entire signal for competitive monitoring, and it is a small fraction of the payload. Ad delivery moves in days, not seconds, so an hourly cadence is generous — this is a domain where polling is a tax you are choosing to pay.

Migrating off a broken scraper

If you have decided the official API is right for your case, the order that avoids wasted work:

  1. Start identity confirmation today. It is the long pole, it takes days, and everything else is quick. Do it before you write any code.
  2. Check your fields exist first. Before migrating anything, confirm that the fields your product depends on are in the API for your ads. Spend and impressions are political-only. Reach breakdowns and beneficiary/payer data are EU/UK-only. Creative files and the CTA button are not there at all. This is the step that kills migrations at week three, so do it at hour one — the field-by-field reference lists which population populates which field.
  3. Keep your historical data. Whatever your scraper collected of now-inactive commercial ads is not reproducible through the API. Export it before you decommission anything.
  4. Map Page IDs once. The API's advertiser endpoint keys on Page ID, and there is no advertiser-search edge. Derive the IDs by searching the archive and folding results to distinct pages, then store them — that mapping is stable and you only want to build it once.
  5. Handle the two failure modes explicitly. Token expiry (error 190) and throttling (error 613) need different responses, and neither should page someone as an outage. Put the token's ~60-day expiry on a calendar.
  6. Run both in parallel for a fortnight, and diff. You will find fields your scraper was silently inventing.

Where we sit

We took the official-API route for our own Meta ad endpoints: Graph API only, no proxies, marginal cost effectively zero, and four endpoints — archive search, all ads for one Page, a single ad with an archive-scan fallback, and a derived advertiser lookup that works around the missing search edge. They are built and currently blocked on an access token, and they return a clean not_configured error naming the missing variable rather than a generic failure.

That choice has costs we would rather state than have you discover: no historical archive of inactive commercial ads, no creative files, one ad library rather than four, and a days-long identity gate before anything works at all. If any of those is your requirement, one of the options above is a better fit than we are.

The general point is smaller than any of the products in it. When two interfaces expose the same data, prefer the one whose owner pays a price for breaking it. On the Meta Ad Library, a regulator set that price, which is why the boring option keeps working.

Everything described here runs on the same API. You are never charged for a failed request, an empty result, or a cache hit.