- A field name this actor does not have is now reported as your field name, not as ours. When a run arrived carrying only a name this actor neither has on its form nor reads as an alternative spelling, the uncharged row explaining it was filed internally against "Search keywords or advertisers" — a box you had never typed in. It is now filed against the name you actually sent, the run page names that name beside the two this actor reads, and the row itself is unchanged except that it is clearer. A keyword or an ad link this actor genuinely could not use still reports against the field you put it in, because that one really is about that field. Nothing about pricing, the form, the output columns or what gets charged changed, and no run behaves differently.
- Keywords and ad links sent under a slightly different field name are now read instead of ignored. If your call put them under a name this actor does not have on its form —
adUrl, adLink, url, urls, startUrl, adLibraryUrl for the links, or keyword, keywords, query, queries, searchQuery, searchTerm, advertiser, pageName for the search — the run had nothing to look up and answered with its built-in sample search, which reads as if your call had worked. Those names are now read as the field this actor does use, your input is searched exactly as if you had typed it into the right box, and one uncharged row tells you the name to use next time. An ad sent under two names is still one ad and one result fee. If a value cannot be used at all, the row now names the field you put it in as well as the one this actor reads. Nothing about pricing, the form itself, or the output columns changed, and a field belonging to our transcript actor still earns the same hand-off row it always did.
- The store card now says what a run costs, and the page shows you a row before you spend anything. The listing's description carried no price at all — it now says From $2.00 per 1,000 ads (the Business-plan floor, the same figure the page and the pricing tab have always carried) and that transcripts are an opt-in add-on. A new What a row looks like section shows one real delivered row from a live
fitness app search, field by field. No price, no input, no output column and no charged event changed.
- The form now tells an AI agent what a run costs before it calls this actor. Apify's MCP server hands an agent the input form and never this page, so the description at the top of the form was the one screen that had to carry the whole story and did not. It now opens with the call that works, names what one ad row costs on the Apify free plan and on a paid one with the arithmetic for a thousand ads, names the separate transcript charge that Add the ad's transcript turns on and the long-video surcharge that rides with it, lists what is never charged, names the run option that caps the bill, and says where the one-pass Ad Library transcript actor belongs instead.
- Search keywords now leads with the value shape and says in its second sentence that a keyword matching nothing is never charged; everything it said before is still there, in a different order, with the "leave it empty and press Start" instruction at the end.
Your inputs, your columns, your events and your prices are unchanged, and nothing you have already collected needs re-running.
- An aborted or migrated run now leaves its receipt from the first moment of the run, instead of only after start-up finishes. The record that says how a run ended was only put in place once the run had finished starting up — reading your input, opening its stores, working out what a previous attempt had already delivered and charged. A run stopped inside that window ended with nothing written about it at all, which mattered most on a re-started run, where the thing not written about was the earlier attempt's work. It is now in place from the run's first moment. Nothing else moved: no input field, output column, event or price changed, and a run that reaches its work behaves exactly as before.
- The two caps have limits — 500 ads per keyword, 10,000 per run — and asking for a bigger number never stops the run. The run goes ahead at the limit and the dataset carries one uncharged row saying what you asked for and what the run used.
- A search that ends on one of the run's OWN limits says so and names the lever: pages that stopped carrying ads new to the run (usually ads another of your keywords had already listed) and the per-search page bound each get their own uncharged note row — never the sentence about the ad format you asked for, which is now reserved for a search that really did return only other formats. A search cut short this way after listing some ads is no longer silent.
- A search your run's own backstop stopped now says so in the run summary too, not just on the row. Last build the uncharged row learned to say that stopping on pages of ads this run had already listed is a limit on the run, not a verdict about the advertiser — but the summary still filed it under "the search matched nothing", so the row and the summary said opposite things about the same keyword. The summary now names it separately, as a stop rather than a miss: nothing ran out, nothing failed, and nothing was charged. "No results" from now on means only what it says — the Ad Library ran the search and had nothing for it.
- The output tab's charging contract names that stop, so every status a row can carry is still listed there.
Your inputs, your columns, your events and your prices are unchanged, and nothing you have already collected needs re-running.
First public build.
- Meta Ad Library search by keyword, advertiser page name or pasted Ad Library link, scoped by country, ad format and running status.
- One structured row per ad: advertiser and page ID, flight dates and live status, publisher platforms and countries, creative format and media URL, ad body text, headline, caption, link description and landing page, call-to-action, Meta's own classification (categories, gated type, sensitive-content and AI-media flags, disclaimer label), the collation a repeated creative belongs to, and the EU spend, impressions and reach bands.
startedAfter / startedBefore date filters, applied to what the search returns and never charged for the ads they drop.
maxAds also answers to maxItems, resultsLimit, limit and count — the names other Ad Library scrapers use. The smallest limit present binds, and one uncharged note row says which name was read and what it was read as.
- Opt-in
includeTranscript: video ads are transcribed onto the same row (transcript, hook3s, language, durationSeconds, segments), charged only when a transcript is delivered.
- Never charged: a search that matched nothing, a walled or rate-limited fetch, a link that would not resolve, an ad whose row could not be read, ads dropped by your own filters or cap, and — on the transcript leg — silent ads, image ads, expired video links and failed transcriptions.
- A cost cap or a time limit ends the collecting, never the delivering: rows already in hand ship in full, uncharged if they could not be billed, and say so.
- Store copy says what a run can reach and what it cannot: the per-keyword and per-run caps, Meta's own depth limit on a broad search, why
spend, impressionsText and reachEstimate are null outside EU and political ads, that the column names are ours and do not move with Meta's, that a single ad's own link is a first-class input, and that there is no sort control.