Everything you can know about one ad
One ad id gives you its run time, EU reach over time, stage and the rules behind it, versions, hook, offers, format, on-image text, landing URL, targeting and payer. Three calls, real Samsung examples.
The AdLib team · · 7 min read
You saw a competitor's ad and want to know more than the picture tells you. When did it start? Is it still running? Did they spend on it or was it a test? What exactly is the offer, and where does the click go? Who paid?
The ad libraries hold part of the answer, spread over a detail page, a reach popup and a creative you read yourself. AdLib puts it behind one id. Below are the three calls, with real Samsung ads we captured on 28 Oct 2026.
What you can do with it
- Decide whether an ad matters. A four-day ad with no signal is a test. A 231-day ad with three signals is something the advertiser keeps paying for.
- Brief a creative team with evidence. Hook, prices, discounts, format and on-image text come out as fields with the exact text quoted, not as a summary someone wrote.
- See who is behind it. On EU ads the library names a payer and a beneficiary. That is where an agency shows up.
- Track a launch. For running Meta ads of watched advertisers, EU reach is stored as a series, so you see whether an ad is still being pushed.
- Keep it after it is gone. The archive keeps the ad when the library stops showing it, with
removed_from_library_atset.
Step 1: the ad
curl "https://api.adlibapi.com/v1/ads/meta:2021287835092375" \
-H "X-API-Key: $ADLIB_API_KEY"This is a Samsung Italia ad for the 2026 TV range. Trimmed to the fields that matter:
{
"id": "meta:2021287835092375",
"status": "inactive",
"first_shown": "2026-04-29T09:00:00+02:00",
"last_shown": "2026-05-02T09:00:00+02:00",
"first_seen_by_us": "2026-10-28T08:13:22+01:00",
"countries": ["IT"],
"eu_data": {
"reach_total": 120531,
"targeting": { "ages": ["18-65+"], "genders": ["all"], "locations": ["Italy"] },
"payer": "Samsung Italia",
"beneficiary": "Samsung Italia"
},
"derived": {
"days_running": 4,
"variant_count": 2,
"signals": ["wide_reach"],
"stage": "scaling"
}
}Two kinds of dates
first_shown and last_shown are what the platform publishes. first_seen_by_us and last_seen_by_us are when our crawlers saw the ad. Here they are six months apart: the ad ran from 29 April to 2 May 2026, and we found it in the library on 28 October. The run time comes from the platform dates, so days_running is 4 even though we only saw it once.
The gap tells you how much of the history is ours. For a watched advertiser the two stay close, because we check on a schedule.
Stage and the rules that fired
derived.signals and derived.stage come from fixed rules on public facts, with no model and no estimate:
| Signal | Rule |
|---|---|
long_running |
Ran more than 30 days |
still_running_90d |
Still active after more than 90 days |
scaled |
Three or more ads of the advertiser share the text |
wide_reach |
EU reach of 100,000 people or more |
multi_country |
Shown in five or more countries |
stage is testing with no signal, scaling with one and proven with two or more.
The TV ad reached 120,531 people in four days, so wide_reach fired and the stage is scaling. Its text appears on 2 ads, one short of scaled. A Black Friday ad from the same page (meta:768581402879056, "Il Black Friday è iniziato.") shows the threshold from the other side: 98,179 reached, so no wide_reach, but three ads share its text, so scaled fired instead.
A Samsung Electronics Benelux ad on Snapchat (snapchat:b622506f-5fca-4cc8-8fd8-5ee8839d65f3) has been running since 11 March 2026. At 231 days it carries long_running, still_running_90d and scaled (16 ads share its text), and the stage is proven. The reasoning behind run length as a signal is in ad run length as a performance signal.
Targeting and payer
For ads shown in the EU, libraries publish targeting and who paid. The TV ad targeted all genders aged 18 to 65+ in Italy, paid for by Samsung Italia on behalf of Samsung Italia. The Snapchat ad lists age 18 and French as the language, paid for by Samsung Electronics Benelux.
The payer is where agencies appear. An Amazon ad of the account Samsung_DE_EUR (amazon:27ef9b66db8d133ae52a7bb5f3257203b8d33afe) lists Starcom Worldwide Ltd as payer, location and search terms as targeting methods, and a reach range of 0 to 1,000. Fields a library does not publish are null; the ad object lists them all.
Step 2: versions, active periods and reach over time
curl "https://api.adlibapi.com/v1/ads/meta:2021287835092375/history" \
-H "X-API-Key: $ADLIB_API_KEY"versions: each change of the creative (text, media, CTA, landing page) withvalid_fromandvalid_to.status_periods: when the ad was active, as start and stop intervals. An ad that was paused and restarted has more than one.events:discovered,started,stopped,changedandremoved.reach: EU reach per measurement day, oldest first, for Meta ads shown in the EU.
For the TV ad the history is short, and honestly so: one version, one active period from 29 April to 2 May, and one reach point dated 28 October, the day we found it. Every ad in our Samsung capture has a single version.
The reach curve is where watching pays off. Reach is cumulative, unique EU accounts since the ad started, so the growth between two points is what the ad gained in that window. Reach that keeps climbing means the advertiser keeps funding the ad. Reach that flattens while the ad is still active means the budget moved. For Meta ads of advertisers on a watchlist, we measure reach daily while the ad is younger than 14 days, because the first weeks show whether it gets scaled, and weekly after that while it runs and has EU reach. Every GET /v1/ads/{id} call also records a point for that day. More in EU reach over time and Meta EU reach as a performance number.
Step 3: the creative, taken apart
curl "https://api.adlibapi.com/v1/ads/meta:2021287835092375/features" \
-H "X-API-Key: $ADLIB_API_KEY"{
"method": "rules+measurement+ocr",
"format": "carousel",
"text": {
"hook": "Acquista un TV o uno Speaker in promo della gamma 2026 e ricevi fino a 1000€ di rimborso.",
"hook_is_question": false,
"prices": ["1000€"],
"discounts": [],
"urgency": []
},
"headline": "Nuova Gamma TV 2026",
"cta": "Learn More",
"landing": { "domain": "samsung.com", "path": "/it/tvs/all-tvs/", "utm": {} },
"media": [
{ "kind": "image", "aspect": "9:16", "orientation": "vertical", "ocr": { "confidence": 0.93 } },
{ "kind": "image", "aspect": "1.91:1", "orientation": "horizontal" },
{ "kind": "image", "aspect": "1:1", "orientation": "square" }
]
}No AI model is involved. The hook is the first sentence of the primary text. Prices, discounts and numbers come from patterns, and phrase tags like urgency or social proof quote the exact text they matched. Media is measured: the TV ad is a carousel with the same image in three aspect ratios, 9:16, 1.91:1 and 1:1. On-image text is read with OCR; here it picked up the promotion dates on the image, "Dal 27 Aprile 17 Maggio 2026", which are not in the ad text at all.
For the Black Friday ad, discounts holds "40% di Sconto" and "-40%". For the Snapchat video, the measurements are 6.1 seconds, audio on, one scene cut, 9:16, and an empty OCR result. OCR keeps only words read with at least 75% confidence, so you get no text rather than wrong text.
landing.utm lists UTM parameters of the landing URL. Samsung tags its links with its own cid parameter instead, so utm is empty, but the full URL is there to read: cid=it_pd_social_meta_tv_ecommerce_e-store_image_tv-gamma-2026_conversion names the channel, the product line and a conversion objective in plain text. How the rules work is in creative features without AI and the features reference.
What it costs
| Call | Credits |
|---|---|
GET /v1/ads/{id} |
1 on Meta, TikTok, Snapchat, Amazon and the other 1-credit platforms, 2 on Google, 3 on LinkedIn; double for ads last shown more than 12 months ago; free if cached |
GET /v1/ads/{id}/history |
1 per version or active period returned |
GET /v1/ads/{id}/features |
2, plus the ad if it has to be fetched live |
The TV ad, with one version and one active period, comes to about 5 credits for all three calls. Features are stored per ad version, so a repeat call for the same creative answers from storage, and calls where nothing could be analysed are not billed. Every response carries an X-Billing-Credits header with the exact cost. The full table is on credits and billing.
Honest limits
- We only know what we saw. History starts when we first see an ad. An ad that ended before anyone looked it up has platform dates but no versions or reach curve from its run.
- Reach is EU only, and Meta for the curve. Ads shown only outside the EU have no reach, and reach counts people, not impressions.
- The reach curve needs a watchlist. Without one you get a point on each day someone fetches the ad, not a regular series.
- Fields depend on the library. Targeting, payer and reach exist where the platform publishes them, and are
nullelsewhere. - OCR is conservative. Words under 75% confidence are dropped, so stylised text can come back empty, and what it does read can be fragments, as the Samsung image text shows.
Do this now
Take one competitor ad you have been wondering about. Copy its link from the library, turn it into an id with GET /v1/library-url (free), and run the three calls above with a free key (5,000 credits a month, no card). Then put the advertiser on a watchlist, so the next ad gets its reach measured daily from its first days:
curl -X POST "https://api.adlibapi.com/v1/watchlists" \
-H "X-API-Key: $ADLIB_API_KEY" -H "Content-Type: application/json" \
-d '{"name": "Competitors", "advertisers": ["meta:142116395934723"]}'Find the advertiser ids for a domain with one domain, every ad account, and get told when a new ad lands with Slack alerts for competitor ads.
Questions people ask
- What can I find out from one ad id?
- Run dates from the platform and from our own monitoring, EU reach and its history, a stage with the signals behind it, every version of the creative, hook, prices, discounts, format, video length and cuts, on-image text, landing domain and UTM parameters, targeting and the payer and beneficiary where the library publishes them.
- Which endpoints do I need?
- GET /v1/ads/{id} for the ad, GET /v1/ads/{id}/history for versions, active periods and reach points, and GET /v1/ads/{id}/features for the creative breakdown.
- How much does analysing one ad cost?
- The ad costs 1 credit on Meta, TikTok, Snapchat and Amazon, 2 on Google and 3 on LinkedIn. History costs 1 credit per version or active period returned, features 2 credits. A Meta ad with one version is about 5 credits in total.
- Is any of it AI-generated?
- No. Signals and stage follow fixed rules on public facts, text tags quote the exact text they matched, media is measured with ffprobe and ffmpeg, and on-image text is read with tesseract.
- How often is EU reach measured?
- For Meta ads of advertisers on a watchlist, daily while the ad is younger than 14 days, then weekly while it runs and has EU reach. Every GET /v1/ads/{id} call also records a point for that day.
- Why is first_seen_by_us later than first_shown?
- first_shown is the date the platform publishes. first_seen_by_us is when our crawlers first saw the ad. For an ad found in the archive months after it ran, the two can be far apart.