LinkedIn Ad Library Scraper avatar

LinkedIn Ad Library Scraper

Pricing

Pay per event

Go to Apify Store
LinkedIn Ad Library Scraper

LinkedIn Ad Library Scraper

Export ad-creative records from LinkedIn's public Ad Library by advertiser name — creative type, ad copy, image URLs, ad-detail link, timestamps. Real multi-page depth via LinkedIn's own pagination, not just page one. Batch advertisers in one run, fault-isolated. JSON/CSV export.

Pricing

Pay per event

Rating

0.0

(0)

Developer

DevilScrapes

DevilScrapes

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

13 hours ago

Last modified

Share


🎯 What this scrapes

Point this Actor at one or more LinkedIn advertiser/company names and it hits the public Ad Library search (linkedin.com/ad-library/search?accountOwner=<name>) for each one, then keeps following LinkedIn's own pagination — page after page — until it reaches the end of that advertiser's ad list or a safety cap you set. Every ad-preview creative block is parsed into a typed row — advertiser name, creative type, ad copy, creative image URLs, and a link back to LinkedIn's own ad-detail page. Multiple advertisers run in the same batch, and one advertiser's block or empty result never sinks the others.

🔥 What we handle for you

  • 🛡️ Browser fingerprint impersonationcurl-cffi replays a real browser's TLS handshake, tuned specifically to clear this target's defenses when routed through a proxy, not just on direct traffic.
  • 🌐 Apify Proxy exit rotation, tuned to what actually clears — every attempt rides a fresh proxy session, and we default to the exit tier measured to clear this target most reliably rather than the "usual" pick. A block retries automatically on a different exit instead of failing the whole request.
  • 🔁 Retries with exponential backoff on 408 / 429 / 503 and network errors — up to 5 attempts, Retry-After honoured.
  • 🧱 Per-advertiser fault isolation — a blocked or empty advertiser is logged and skipped; every other advertiser in the batch still runs.
  • 🧊 Clean, typed dataset rows — Pydantic-validated, ISO-8601 timestamps, JSON / CSV / Excel export straight from the Apify Console.
  • 💰 Pay-Per-Event pricing — you only pay for ad rows that land in your dataset. No data, no charge.

💡 Use cases

  • Competitor ad monitoring — see which creatives a rival is currently running on LinkedIn.
  • Ad-transparency research — build a dataset of B2B advertiser messaging and creative formats across an industry.
  • Lead gen for ad agencies — find companies actively spending on LinkedIn ads as warm outreach targets.
  • Creative benchmarking — compare ad copy and creative types across multiple advertisers in one batch run.

⚙️ How to use it

  1. Click Try for free at the top of the page.
  2. Add one or more advertiser/company names to advertiserNames — most other fields have sensible defaults.
  3. Click Start. Rows stream into the run's dataset as each advertiser is searched.
  4. Export from Storage → Dataset as JSON, CSV, or Excel — or fetch via the API.

📥 Input

FieldTypeRequiredDefaultNotes
advertiserNamesarrayyes["nike", "salesforce", "hubspot"]Advertiser/company names to search — one Ad Library search per item.
maxAdsPerAdvertiserintegerno200Cap on ad rows collected for a single advertiser before its pagination walk stops early. Set above 24 to go past the first page.
maxPagesPerAdvertiserintegerno20Safety cap on how many pages to follow per advertiser, independent of the empty-results stop condition.
maxTotalResultsintegerno500Cap on total ad rows emitted across the whole run.
maxRunSecondsintegerno600Wall-clock budget across all advertisers; the run ships whatever it collected so far. Capped at 3 480s, below the platform's own hard limit.
proxyConfigurationobjectno{"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}Apify Proxy config — defaults to residential, the tier proven to complete a multi-page walk from the Apify cloud.

Example input

{
"advertiserNames": ["nike", "salesforce", "hubspot"],
"maxAdsPerAdvertiser": 200,
"maxTotalResults": 500,
"maxRunSeconds": 600,
"proxyConfiguration": {
"useApifyProxy": true,
"apifyProxyGroups": ["RESIDENTIAL"]
}
}

📤 Output

Every row is one parsed ad creative.

FieldTypeNotes
advertiser_namestringThe input advertiser name searched (echoed, not re-parsed).
ad_idstring | nullNumeric ad id parsed from the ad's /ad-library/detail/<id> link.
creative_typestring | nullLinkedIn's own creative-type label (e.g. SPONSORED_STATUS_UPDATE, FOLLOW_COMPANY_V2, SPONSORED_VIDEO) — free-form, not a closed list.
ad_copystring | nullAd copy/body text, or the headline text when no body copy is present.
image_urlsarrayCreative image URL(s) hosted on media.licdn.com. Empty list when none found — never null.
linkedin_detail_urlstring | nullLinkedIn's own ad-detail page for this creative.
page_numberinteger1-based page within this advertiser's pagination walk (1 = the first page, 2+ = later pages).
scraped_atstringISO-8601 UTC timestamp at parse time.

Example output

{
"advertiser_name": "salesforce",
"ad_id": "1546052924",
"creative_type": "SPONSORED_STATUS_UPDATE",
"ad_copy": "Looking forward to this one tomorrow, we have some brilliant trailblazer speakers to share their #datamigration challenges…",
"image_urls": [
"https://media.licdn.com/dms/image/v2/D4E03AQFiUMm9kqlKMQ/profile-displayphoto-scale_100_100/B4EZqDUk73KoAc-/0/1763139804985"
],
"linkedin_detail_url": "https://www.linkedin.com/ad-library/detail/1546052924",
"page_number": 1,
"scraped_at": "2026-09-10T07:48:06.525134Z"
}

💰 Pricing

Pay-Per-Event — you pay only when these events fire:

EventUSDWhat it is
actor-start$0.20Base fee, once per run (warm-up, proxy resolution)
ad-result$0.003Per ad-creative row written to the dataset

Example: 1 000 ad rows in one run ≈ $3.20 ($0.20 + 1 000 × $0.003). No subscription, no minimum — Apify gives every new account free trial credit.

🚧 Limitations

  • Depth is real but bounded. Every run follows LinkedIn's own pagination until it reaches the end of an advertiser's ad list, or one of maxAdsPerAdvertiser / maxPagesPerAdvertiser / maxTotalResults / maxRunSeconds is hit — whichever comes first. When a walk stops early, the run's status message is prefixed [TRUNCATED] instead of [COMPLETE], so you always know whether you got everything or hit a cap. Raise the caps for a deeper pull.
  • No external landing/destination URL. LinkedIn's search and pagination markup — the only pages this Actor fetches — never exposes the advertiser's external landing page, only its own ad-detail page (linkedin_detail_url). We looked (including at the separate per-ad detail page) rather than assume, and dropped the field entirely instead of shipping a column that would always read null — see the Actor's changelog for details.
  • Video creative extraction is out of scope; image creative URLs are captured, video asset URLs are not.
  • creative_type values are passed through as free-form text (we've observed FOLLOW_COMPANY_V2, SPONSORED_STATUS_UPDATE, and SPONSORED_VIDEO so far), not mapped to an exhaustive enum.
  • No login or session persistence — every request is anonymous, reading only what LinkedIn's Ad Library already serves to a public visitor.

❓ FAQ

Is this legal?

We only fetch what LinkedIn's public Ad Library already serves to anonymous visitors — no login, no session cookies, no credential harvesting. Respect LinkedIn's terms of service before using output commercially.

What if an advertiser has no ads?

The run still succeeds. That advertiser's rows are simply zero, and the status message says so — a real zero-match result is never treated as a failure.

Why does my run say [TRUNCATED] instead of [COMPLETE]?

[TRUNCATED] means at least one advertiser's pagination walk stopped before reaching the end of its ad list — a safety cap (maxAdsPerAdvertiser, maxPagesPerAdvertiser, maxTotalResults, or maxRunSeconds) was hit first. This Actor bills per row, so we never let a partial run's status message read the same as a finished one. Raise the relevant cap and re-run for the rest.

Why are some fields null?

LinkedIn's Ad Library markup doesn't guarantee every field on every creative — some creative types (e.g. SPONSORED_INMAILS) don't carry body copy in the same place a status-update ad does. We never fabricate a value — unconfirmed fields come back null rather than a guess.

Can I track ads over time?

Each run is a single snapshot. Schedule the Actor daily/weekly in Apify Console and diff successive dataset exports to track changes.

💬 Your feedback

Spotted a bug, hit a weird edge case, or need a new field? Open an issue on the Actor's Issues tab on Apify Console — we ship fixes weekly and we read every report.