---
name: ad-library-recon
description: Read a company's live advertising out of the public ad libraries — LinkedIn Ad Library, Meta Ad Library, and Google Ads Transparency Center — using a real browser, because these are JavaScript applications that block scrapers outright. Use this whenever the task needs to know who a company TARGETS rather than who it has already won: building or sharpening an ICP, finding an anti-ICP, checking whether a competitor is moving upmarket, reading a rival's positioning and offer, sizing how seriously someone is spending on a channel, or verifying that a company's stated ICP matches where its money actually goes. Use it when a website read has left the ICP thin, when someone asks "who are they going after", "what ads are they running", "are they targeting enterprise", or "what's their angle" — and specifically when a Firecrawl or Exa attempt on an ad library has already failed, which it will. Prefer this over any scraping approach for ad libraries; they are browser-only.
---

# Ad library recon — declared targeting, read through a browser

## Onboarding — start here

**What this does.** Pulls a company's live and historical ads out of the three
public ad libraries and turns them into ICP evidence: who they target, what
offer they lead with, which segment they name, and how much they are spending
relative to peers.

**Why it exists as its own skill.** Every ad library is a JavaScript app behind
a search form, and LinkedIn's blocks automated fetching completely — a Firecrawl
attempt against `linkedin.com/ad-library/search` failed on all six engines
including stealth proxy. Google's returns a list but serves ad creatives inside
`tpc.googlesyndication.com` iframes that a scraper cannot read. The only route
that works is a browser that renders and where the user is already signed in.

**What it does not do, and where to go instead.**

- It does not build the whole ICP. It supplies the *targeting* half. Pair it
  with `icp-research`, which covers the website, pricing and client roster.
- It does not give ad spend in currency. No library publishes that outside
  political advertising. You get ad counts and date ranges — volume, not budget.
- It does not work at corpus scale. Budget 3–6 minutes of browser interaction
  per company. For 40 companies use `icp-research` and reserve this for the ones
  still thin afterwards.
- It is not a competitive-intelligence archive. For historical creative sets at
  scale, the Google Ads Transparency BigQuery public dataset is the right tool.

**Setup.** Needs a browser surface: the in-app browser
(`mcp__Claude_Browser__*`) or Claude in Chrome (`mcp__claude-in-chrome__*`).
Prefer Chrome when the user is already logged into LinkedIn — the Ad Library is
public but degrades heavily when signed out. Verify with one navigation to
`https://adstransparency.google.com/?region=NL` — if the page renders, you are
ready.

**Cost.** Zero vendor spend. The cost is wall-clock and attention.

**How to invoke.** "What ads is X running", "check the ad library for X", "are
they targeting enterprise", "who does X actually go after".

**Boundaries that are not negotiable.** These libraries are public records; read
them and nothing else. Never sign in on the user's behalf, never enter
credentials, never click an advertiser's ad — a click costs a real company real
money and pollutes their data. Never accept cookie banners beyond declining
non-essential. If a library demands a login the user does not already have, stop
and report that rather than creating an account.

**Rest of the skill.** Per-library mechanics below, then what to extract, then
the interpretation rules that stop this producing confident nonsense.

---

## Why targeting data is worth the extra effort

A client roster is *revealed* preference — who a company won, filtered by
survivorship and by what marketing chose to display. Ad targeting is *stated*
preference — who they are spending money to reach right now, declared by them,
with budget behind it.

The gap between the two is the finding. An agency whose logo wall is all
20-person startups but whose ads target `Director+ at 501-1000 employees` is
trying to move upmarket and has not landed it. That is invisible from the
website, and it changes what "their ICP" means: their aspiration and their
reality are different segments, and a study measuring buyer-fit needs to say
which one it is scoring against.

---

## LinkedIn Ad Library — the highest value, the most effort

This is the only library that publishes B2B targeting parameters, which is
exactly what an ICP needs. It cannot be scraped; drive it in a browser.

**Route.** `https://www.linkedin.com/ad-library/home` → search the company name
in the advertiser field. Direct URLs of the form
`/ad-library/search?companyIds=<id>` work when you have the numeric company id
from the company page URL, which is more reliable than name search for
companies with common names.

**Mechanics that matter.**

- Search by advertiser, not keyword. Keyword search returns anyone mentioning
  the term.
- Results are paginated by infinite scroll. Scroll to load; do not assume the
  first screen is the full set.
- Set the date filter deliberately. The default window hides older creative, and
  the *change over time* in who they target is more informative than a snapshot.
- Open an individual ad to reach the detail view. **The targeting disclosure
  lives there, not in the grid**, and only for ads served in the EU — the DSA
  requires it. A company advertising only in North America will show ads with no
  targeting panel at all, which is a limitation to report, not a null result.

**What the targeting panel gives you**, and it maps almost directly onto the ICP
schema: job function, seniority, company size, industry, location, and sometimes
member-interest or list-based audiences. Record it verbatim before interpreting.

## Google Ads Transparency Center — fast, shallow, scriptable

The one library where a URL alone gets you something useful.

**Route.** `https://adstransparency.google.com/?region=<CC>&domain=<domain>` —
for example `?region=NL&domain=coldiq.com`. This renders enough that even a
plain fetch returns the advertiser's verified legal name, the ad count, and
per-creative links. Confirmed working.

**Its ceiling.** Creatives render inside `tpc.googlesyndication.com` iframes that
a scraper sees as blocked. To read the actual ad copy you need the browser.
There is no targeting disclosure here for commercial ads — only political.

**Use it as a cheap first pass** across many companies to answer: do they
advertise at all, under what legal entity, at what volume, since when. That
alone separates companies with a real paid motion from those without, and tells
you which ones deserve the expensive LinkedIn pass.

**Note the region parameter is load-bearing.** Ads shown in the EU carry extra
disclosure by law. Query the region the company actually sells into, and if in
doubt query an EU region as well as the home one.

## Meta Ad Library — broad, weak on B2B

**Route.** `https://www.facebook.com/ads/library/` → set country and category
`All ads`, then search the page name. Direct: `?q=<name>&country=<CC>`.

Coverage is deep and history is long, but targeting disclosure is limited
outside political and issue advertising, and B2B service businesses often do not
advertise here at all. Treat an empty result as information — it usually means
their buyers are not on Meta, which is itself an ICP signal.

---

## What to extract, per company

Record these, and keep the ad copy verbatim — paraphrasing ad copy destroys the
segment language, which is the most useful part.

```
advertiser_legal_name      # Google gives the registered entity; often differs from the brand
is_advertising             # true / false / not-in-this-region
ad_count, date_range       # volume and recency, not spend
platforms                  # which libraries returned results
targeting_declared         # LinkedIn EU ads only: function, seniority, company size, industry, geo
offer_in_ads               # what they lead with - a demo, a lead magnet, a webinar, a hire
segment_language           # verbatim phrases naming the buyer, e.g. "for RevOps leaders at 200+"
landing_pages              # where ads point; frequently a page the nav does not link
```

That last field is quietly valuable. Ad landing pages are built for a specific
segment and are often unlinked from the main navigation — which means they carry
a sharper ICP statement than the homepage, and `icp-research` can then read them
directly.

---

## Interpretation rules

**Absence of ads is not absence of a motion.** Plenty of strong B2B service
businesses run entirely on founder-led content and referral. Record
`is_advertising: false` as a finding about their channel mix, and do not let it
lower your ICP confidence — it is evidence about *how* they sell, not *to whom*.

**Targeting is aspiration; the client roster is outcome.** When they disagree,
report both rather than reconciling them. The disagreement is more informative
than either number, and picking one silently hides the interesting part.

**Ad copy segment language beats targeting parameters for wording.** The
parameters give you machine-readable bands; the copy gives you the words the
company uses for its buyer, which is what you actually want when matching
against a commenter's self-written headline.

**One creative is not a strategy.** A company with three ads is testing. A
company with twenty running for eight months has a committed segment. Weight
your confidence by volume and duration, and say which you saw.

**Region gaps are limitations, not nulls.** If a company serves North America
only, no targeting panel exists anywhere. Report "no EU-served ads, targeting
undisclosed" rather than "no targeting" — those read identically in a table and
mean completely different things.

---

## Verified behaviour (tested 2026-08-12)

**LinkedIn Ad Library renders in a browser without a login.** `/ad-library/home`
returned full page text with the search form present and no auth wall — the same
URL family that failed on every Firecrawl engine including stealth. The
browser-only claim holds, and signed-out access is sufficient to reach the form.

**`?companyName=<name>` is NOT a valid search parameter.** Navigating to
`/ad-library/search?companyName=Frontal%20AI` returned "Failed to load". Do not
guess query parameters. Either drive the form directly, or get the numeric
company id from the LinkedIn company page URL and use `?companyIds=<id>`.

**The pane needs a real viewport.** In one session the in-app browser reported
`Viewport: 0x0`; `get_page_text` still worked but `read_page` returned an empty
accessibility tree, so no element refs existed and the form could not be driven.
`resize_window` did not clear it. When you see a 0x0 viewport, switch to Claude
in Chrome rather than retrying — a real Chrome window has a real viewport, and
it also carries the user's existing LinkedIn session, which improves results.

**Practical order, therefore:** try Google Ads Transparency first by URL (cheap,
needs no browser at all), and go to Chrome — not the in-app pane — for anything
on LinkedIn.
