LinkedIn Ad Library Scraper
Pricing
Pay per event
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
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
13 hours ago
Last modified
Categories
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 impersonation —
curl-cffireplays 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 / 503and network errors — up to 5 attempts,Retry-Afterhonoured. - 🧱 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
- Click Try for free at the top of the page.
- Add one or more advertiser/company names to
advertiserNames— most other fields have sensible defaults. - Click Start. Rows stream into the run's dataset as each advertiser is searched.
- Export from Storage → Dataset as JSON, CSV, or Excel — or fetch via the API.
📥 Input
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
advertiserNames | array | yes | ["nike", "salesforce", "hubspot"] | Advertiser/company names to search — one Ad Library search per item. |
maxAdsPerAdvertiser | integer | no | 200 | Cap on ad rows collected for a single advertiser before its pagination walk stops early. Set above 24 to go past the first page. |
maxPagesPerAdvertiser | integer | no | 20 | Safety cap on how many pages to follow per advertiser, independent of the empty-results stop condition. |
maxTotalResults | integer | no | 500 | Cap on total ad rows emitted across the whole run. |
maxRunSeconds | integer | no | 600 | Wall-clock budget across all advertisers; the run ships whatever it collected so far. Capped at 3 480s, below the platform's own hard limit. |
proxyConfiguration | object | no | {"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.
| Field | Type | Notes |
|---|---|---|
advertiser_name | string | The input advertiser name searched (echoed, not re-parsed). |
ad_id | string | null | Numeric ad id parsed from the ad's /ad-library/detail/<id> link. |
creative_type | string | null | LinkedIn's own creative-type label (e.g. SPONSORED_STATUS_UPDATE, FOLLOW_COMPANY_V2, SPONSORED_VIDEO) — free-form, not a closed list. |
ad_copy | string | null | Ad copy/body text, or the headline text when no body copy is present. |
image_urls | array | Creative image URL(s) hosted on media.licdn.com. Empty list when none found — never null. |
linkedin_detail_url | string | null | LinkedIn's own ad-detail page for this creative. |
page_number | integer | 1-based page within this advertiser's pagination walk (1 = the first page, 2+ = later pages). |
scraped_at | string | ISO-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:
| Event | USD | What it is |
|---|---|---|
actor-start | $0.20 | Base fee, once per run (warm-up, proxy resolution) |
ad-result | $0.003 | Per 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/maxRunSecondsis 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 readnull— 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_typevalues are passed through as free-form text (we've observedFOLLOW_COMPANY_V2,SPONSORED_STATUS_UPDATE, andSPONSORED_VIDEOso 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.