LinkedIn Ad Library Scraper: Ads by Company
Pricing
from $0.80 / 1,000 ads
LinkedIn Ad Library Scraper: Ads by Company
Scrape the public LinkedIn Ad Library by company, keyword, payer or country with no login and no cookies. Get ad copy, headline, CTA, format, image and video URLs, the paying entity, run dates, impression ranges and EU targeting. JSON, CSV, Excel or API, schedulable, billed once per new ad.
Pricing
from $0.80 / 1,000 ads
Rating
0.0
(0)
Developer
Automation Craft
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
9 days ago
Last modified
Categories
Share
LinkedIn Ad Library Scraper: Ads by Company
Scrape LinkedIn ads from the public LinkedIn Ad Library with no login, no cookies and no API key. Give it a company, a keyword, a payer or a pasted Ad Library link and it returns every matching ad with the full ad copy, the creative URLs, the paying entity and, for ads shown in the EU and the EEA, the run dates, the impression range, the split by country and the targeting the advertiser chose.
It was built next to our Facebook, Meta and Instagram Ad Library scrapers, so it follows the same rules: you pay once per new ad, duplicates are free, and the README tells you the measured fill rate of every field instead of promising all of them.
Quick start
- Paste a LinkedIn company page URL or its numeric id into Advertiser company pages or ids. The prefill
uses
1035, which is Microsoft, capped at 8 ads so the first run is quick and cheap. - Optionally add Keywords, Countries and a Date range. Pick European countries if you want run dates and impressions (see the table below).
- Set Maximum ads in total so a broad search cannot run away with your budget.
- Click Start. Results appear in the Ads view; switch to EU transparency for the impression and targeting columns.
- Export to JSON, CSV or Excel, or read the dataset from the API.
What you get
One row per ad, plus one run-summary row per run with the counters. Fill rates below were measured on 160
ad detail pages sampled across six creative types worldwide, and on 24 ads from a German search.
| Field | What it is | Worldwide | Ads shown in the EU and EEA |
|---|---|---|---|
adId, url | LinkedIn's ad id as a string, and the permanent ad page | 100% | 100% |
advertiserName, advertiserUrl, advertiserId | The LinkedIn page that ran the ad | 100%, 96%, 96% | 100% |
paidBy | The paying entity, often the media agency rather than the brand | 100% | 100% |
adFormat, creativeType | Single Image Ad, Video Ad, Carousel Ad, Document Ad, Message Ad, Job Ad, Event Ad, LinkedIn Article Ad | 100% | 100% |
bodyText | The full ad copy, not the truncated card teaser | 99% | 100% |
headline | Headline under the creative | 86% | - |
ctaLabel | Text on the ad's button, for example Learn more | 83% | - |
imageUrls, videoUrls, videoPosterUrls | Creative media, one image entry per carousel slide, MP4 renditions for video ads | 92% have at least one | - |
firstShownDate, lastShownDate | The dates the ad ran | 8% | 100% |
totalImpressions, totalImpressionsMin, totalImpressionsMax | LinkedIn's impression band, for example 200k-300k | 8% | 100% |
impressionsByCountry | Share of impressions per country | 8% | 100% |
adTargeting | Targeting parameters grouped by Language, Location, Audience, Company, Job and so on | 8% | 100% |
hasEuTransparency | Tells you in one boolean whether the four rows above are filled | 100% | 100% |
alreadyKnown | True when your dedup memory had already delivered this ad. Those rows are free | 100% | 100% |
The impression, run-date and targeting fields exist because of the EU Digital Services Act, so LinkedIn
publishes them for ads shown in the EU and the EEA and for almost nothing else. That is why the two columns
differ so much, and why every row carries hasEuTransparency.
How much does it cost to scrape LinkedIn ads?
Pay per result, no monthly fee.
| Event | Price | When it is charged |
|---|---|---|
| Ad | $0.001 each, so $1.00 per 1,000 ads | Once for every new, unique ad delivered, ad details included |
| Actor start | $0.0005 per run, per gigabyte of memory | Once when a run starts |
Store volume discounts apply to the Ad event: Silver 10 percent off ($0.90 per 1,000), Gold, Platinum and Diamond 20 percent off ($0.80 per 1,000). The Actor start event has no discount.
Nothing else is ever charged. Duplicates inside a run, ads your dedup memory already knows, ad ids that do not exist, requests LinkedIn refused, status rows and the run summary are all free. The Actor runs on 256 MB by default, so the start event is charged once.
Worked example: a weekly check on ten competitors that finds 300 ads the first week and 40 new ads a week after that costs $0.3005 in week one and $0.0405 a week from then on, because the dedup memory makes the other 260 free. A week where nobody launched anything new costs $0.0005.
Input
| Input | What it does |
|---|---|
companyUrlsOrIds | Company pages whose ads you want. A numeric URL or a bare id is an exact match; a vanity URL such as /company/microsoft has no id, so it is searched as an advertiser name and a warning says so |
searchKeywords | Words or phrases in the ad text, one search per entry |
advertiserNames | Advertiser names, when you do not have the numeric id |
payerNames | The paying entity, for tracking one media agency across its clients |
adUrlsOrIds | Look up specific ads directly |
searchUrls | Paste any Ad Library search URL and its filters are read out of the link |
countries | Two-letter country codes, empty for worldwide |
dateOption, startDate, endDate | Last 30 days, this month, this year, last year or a custom range |
maxAds, maxAdsPerQuery | Budget for the run and per search. The total is shared fairly between searches, then any leftover goes back to the searches that still have results |
includeAdDetails | On by default. Off returns a faster creative list from the search cards only. The price per ad is the same either way |
dedupMemoryName | Name a memory and later runs skip the ads it already delivered, free of charge |
emitKnownAds | Return known ads too, flagged alreadyKnown and free, instead of skipping them |
resetDedupMemory | Empty the memory first |
maxRequestsPerSecond, maxConcurrency | Pacing. The defaults are the tested ones |
proxyConfiguration | Leave the default residential setting |
Every search is independent, so five keywords and three companies run as eight searches with the same country and date filters.
FAQ
Do I need a LinkedIn account, cookies or an API key?
No. The LinkedIn Ad Library is a public, server-rendered page and this Actor reads it the way a signed-out visitor does. Nothing in the input asks for a credential.
How far back does the LinkedIn Ad Library go?
Twelve months. The date picker on LinkedIn's own page is limited to the last year, so current-year,
last-year and a custom range all stop there. Ads older than that are not published by LinkedIn at all.
Why do some ads have impressions and run dates and others do not?
Those fields come from the EU Digital Services Act, so LinkedIn publishes them for ads shown in the EU and
the EEA. Measured, 24 of 24 German ads carried them and 13 of 160 ads from a worldwide sample did. Filter by
a European country, or read hasEuTransparency on each row.
Can I get the landing page URL the ad clicks through to?
No. LinkedIn does not publish the click destination on the Ad Library, so no scraper can read it from this surface. The call to action label is there, the destination is not. LinkedIn also publishes no spend figures.
How do I stop paying twice for the same ad every week?
Put a name in dedupMemoryName and use the same name every run. The Actor keeps a private list of the ad
ids it has delivered under that name, skips them free of charge, and only charges for genuinely new ads.
Set emitKnownAds if you still want the known ads in the output, free.
Why does this Actor run with limited permissions?
Least privilege. It can only reach its own storages: the dataset it writes and the one named key-value store it creates for your dedup memory. It cannot read anything else in your Apify account.
How many ads can one search return?
As many as LinkedIn has. The Actor pages through the site's own infinite-scroll endpoint 24 ads at a time
until LinkedIn says there are no more. A test query whose header claimed 664 matching ads returned all 664
unique ads. Use maxAds to cap large searches on purpose rather than by accident.
What this Actor does NOT do
- No landing page URLs and no ad spend. LinkedIn does not publish either.
- No exact impression counts, only the band LinkedIn shows, such as
10k-20k. - No impressions filter and no targeting filter. Both exist on LinkedIn's own form and both are broken for signed-out visitors: the impressions filter returns a match count and zero rows, and the targeting filter silently widens the query instead of narrowing it. Shipping them would mean shipping wrong results.
- No logged-in LinkedIn data. No profiles, no connections, no Sales Navigator, no company employees.
- No ads older than 12 months, because the library does not hold them.
- Job ads carry no body copy, and their call to action can be an unresolved template such as
Careers at %COMPANYNAME%. That is what LinkedIn serves; it is passed through rather than cleaned up.
Using the API
Replace <TOKEN> with your Apify API token.
curl -X POST "https://api.apify.com/v2/acts/automation_craft~linkedin-ad-library-scraper/runs?token=<TOKEN>" \-H 'Content-Type: application/json' \-d '{"companyUrlsOrIds":["1035"],"dateOption":"last-30-days","maxAds":50,"dedupMemoryName":"microsoft-weekly"}'
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<TOKEN>' });const run = await client.actor('automation_craft/linkedin-ad-library-scraper').call({searchKeywords: ['cloud security'],countries: ['DE', 'FR'],maxAds: 200,});const { items } = await client.dataset(run.defaultDatasetId).listItems();
from apify_client import ApifyClientclient = ApifyClient("<TOKEN>")run = client.actor("automation_craft/linkedin-ad-library-scraper").call(run_input={"advertiserNames": ["Salesforce"],"dateOption": "current-year","maxAds": 500,})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item.get("headline"), item.get("totalImpressions"))
Changelog
0.1
First release: company, advertiser, keyword, payer, country and date search, direct ad lookup, full pagination, ad details with EU transparency fields, and cross-run dedup memory.