LinkedIn Ads Scraper - Ad Library Search, No Login avatar

LinkedIn Ads Scraper - Ad Library Search, No Login

Pricing

from $0.24 / 1,000 ads

Go to Apify Store
LinkedIn Ads Scraper - Ad Library Search, No Login

LinkedIn Ads Scraper - Ad Library Search, No Login

Search the LinkedIn Ad Library by company, ad keyword, payer or country, with no login. One row per ad: advertiser, payer, copy, headline, call to action, image or video, landing URL, and for EU delivery the run dates, impressions and targeting. $0.25 per 1,000 ads.

Pricing

from $0.24 / 1,000 ads

Rating

0.0

(0)

Developer

Dami's Studio

Dami's Studio

Maintained by Community

Actor stats

0

Bookmarked

5

Total users

3

Monthly active users

2 days ago

Last modified

Share

Search the public LinkedIn Ad Library by company, keyword, payer or country: one row per ad, with the advertiser, the company that actually paid, the ad copy, the headline, the call to action, the creative image or video and the landing URL. No account needed.

Two things to know before you start. The library holds roughly the last twelve months, so anything older is simply not there. And the run dates, the impressions band and the targeting are only published for ads delivered into the EU, so on a US or UK search those fields come back null; that is LinkedIn's rule, not a gap in the row.

InputCompany names or URLs, keywords, payer names, country codes
OutputOne row per ad: advertiser, payer, copy, headline, call to action, image or video, landing URL, and for EU delivery the run dates, impressions band and targeting
Ceiling2,000 ads per run
Account neededNone
Price$0.25 per 1,000 ads, flat on every plan. The free plan's $5 a month covers about 20,000

πŸ” What LinkedIn Ads Scraper does

The Ad Library is open to anyone, but it is built for clicking through one advertiser at a time. This turns it into rows.

You can search four ways and mix them freely: by company, by words in the ad copy, by the payer, or by country on its own to sweep everything running into a market. Each term becomes its own search and the results are pooled into one dataset.

The advertiser and the payer are not always the same company, which is the part most people miss. A media agency often pays for a brand's ads, so searching the agency as a payer maps its whole client roster in one run. Both names are on every row.

By default the run also opens each ad's own detail page. That page is the only place LinkedIn publishes the untruncated copy, the landing URL, the country split and the EU disclosure fields. Turning it off makes a run faster, and the price per ad does not change.

πŸ“‹ What data you get from each LinkedIn ad

What you getField
Which of your searches found it, and howsearchTerm, searchType
The library's id for the ad, and its pageadId, adUrl
The advertiser, its company page and idadvertiserName, advertiserUrl, advertiserId
Who paid for itpayerName
The ad formatadType, creativeType
The copy, the headline and the buttonadText, headline, callToAction
Where it pointslandingUrl
The creativeimageUrl, videoUrl
When it ran (EU delivery only)firstShownDate, lastShownDate, runDates
Impressions band and country split (EU delivery only)totalImpressions, countries, impressionsByCountry
Targeting facets (EU delivery only)targeting
Whether LinkedIn withheld the creativeisRestricted, restrictionDetails

▢️ How to scrape the LinkedIn Ad Library

  1. Open LinkedIn Ads Scraper and click Try for free.
  2. Put a company name in Companies / advertisers, or words in Keywords in the ad copy.
  3. Add a country code in Countries if you want the EU disclosure fields.
  4. Set Maximum ads, then click Start.
  5. Download the dataset as JSON, CSV or Excel, or read it from the Apify API.

Start it with no company, keyword, payer or country and you get one labelled sample row, free.

πŸ’° How much does it cost to scrape LinkedIn ads?

$0.25 per 1,000 ads. Flat on every Apify plan, no volume tiers. On the free plan, the $5 Apify gives you each month covers about 20,000 ads.

One charge per ad row. An ad that two of your searches both find is written and charged once. Sample rows and diagnostic rows are never charged. Opening each ad's detail page does not change the price.

πŸ“₯ What you give it

{
"companies": ["HubSpot"],
"countries": ["DE"],
"dateRange": "last-30-days",
"maxItems": 100
}
FieldDefaultWhat it is
companiesnoneUp to 20. A company name, or a LinkedIn company URL. A URL with a numeric id matches exactly; a plain name matches on advertiser name, which can pull in more than one page with that name. The form opens with HubSpot filled in.
keywordsnoneUp to 20. Words searched inside the ad text. Several words in one entry are treated as AND.
payersnoneUp to 20. The entity billed for the ad, often an agency.
countriesnoneUp to 20 two-letter codes: DE, FR, US. Applied to every search above, and usable on its own to sweep a market. Put an EU code here to switch on the run dates, impressions and targeting.
dateRangenoneall, last-30-days, current-month, current-year or last-year. The form opens on all.
dateFrom, dateTononeYYYY-MM-DD. Fill both to use an exact window instead of the preset. LinkedIn only accepts dates inside the last twelve months.
maxItems201 to 2,000. Rows across the whole run.
includeAdDetailstrueOpens each ad's detail page. Leave it on unless you only want advertiser and creative.
proxyUrlsnoneOptional. Your own servers as http://user:pass@host:port; leave it empty for a normal run. Anything unusable in the list is reported as a free PROXY_INPUT_ADJUSTED row.

Two values are dropped without a warning. A country that is not exactly two letters, like Germany or DEU, is ignored, and if it was your only input you get the sample row. A dateFrom without a valid dateTo (or the other way round) is ignored too, and the preset applies.

The row budget is split evenly between your searches. Four searches and maxItems: 200 gives you fifty of each, not two hundred of the first. Set maxItems below the number of searches and each one returns a single row.

πŸ“€ What you get back

A real row from a real run, with the media links cut short:

{
"ok": true,
"charged": true,
"recordType": "ad",
"searchTerm": "HubSpot",
"searchType": "company",
"adId": "1552531503",
"adUrl": "https://www.linkedin.com/ad-library/detail/1552531503",
"advertiserName": "HubSpot",
"advertiserUrl": "https://www.linkedin.com/company/68529",
"advertiserId": "68529",
"payerName": "HubSpot, Inc.",
"adType": "Video Ad",
"creativeType": "SPONSORED_VIDEO",
"adText": "HubSpot vereint Kundendaten, historische Daten und Teams. So wirken Kampagnen schneller, Teams arbeiten besser zusammen und nichts bleibt liegen.",
"headline": "Ergebnisse fΓΌr den 9-Uhr-Termin um 8:56",
"callToAction": "Learn more",
"landingUrl": null,
"imageUrl": "https://media.licdn.com/dms/image/v2/D4D10AQH8c-Ni0tRqCQ/videocover-high/...",
"videoUrl": "https://dms.licdn.com/playlist/vid/v2/D4D10AQH8c-Ni0tRqCQ/progressive-servable-video/...",
"firstShownDate": null,
"lastShownDate": null,
"runDates": null,
"totalImpressions": null,
"countries": [],
"impressionsByCountry": [],
"targeting": [],
"isRestricted": false,
"restrictionDetails": null,
"scrapedAt": "2026-09-21T01:33:25.034Z"
}

That row is a German-language ad found by company search, and the EU fields are empty because the search was not scoped to an EU country. Add "countries": ["DE"] and they fill in.

FieldHow to read it
adIdYour dedupe key.
payerNameOften an agency, sometimes a legal entity name that differs from the brand.
adText, headlineFull text when the detail page was opened, about 150 characters when it was not.
landingUrlClick-tracking is stripped, campaign parameters are kept. null when details are switched off or the ad has no link.
videoUrlThe highest-quality version of the video, for video ads.
totalImpressionsA band, not an exact number, because that is how it is published.
isRestrictedtrue when LinkedIn has withheld the creative. The advertiser and card details still come through.

🧾 Reading the output

Three kinds of row, and only ads cost anything.

RowHow to spot itBilled
An adrecordType: "ad"yes
The sample rowrecordType: "sample", _sample: trueno
A diagnosticrecordType: "diagnostic", ok: falseno

Filter on recordType == "ad". The charged field is a row marker, not a receipt: it is stamped as the row is built. Your Apify run detail is the authority on what you were actually billed.

CodeWhat it means
NO_RESULTSThe search ran and the library holds nothing for it. More than five empty searches collapse into one row so your dataset is not flooded.
RATE_LIMITEDToo many requests too close together. Ask for fewer rows, or space the runs out.
BLOCKEDThe library answered with a check page instead of results.
SERVER_ERROR, NETWORKLinkedIn errored, or a page could not be read. Detail-page failures all report as NETWORK, whatever the cause.
TIME_BUDGETThe run hit its time limit with searches left. Everything collected before that is in your dataset.
PROXY_INPUT_ADJUSTEDSomething in your proxyUrls list could not be used and was dropped.
CHARGE_ERROR, UNEXPECTED_ERRORSomething went wrong that the run could not classify. Worth sending in.

πŸ’‘ What people use it for

  • Reading a competitor's current campaigns: the copy, the hooks, the offers and where they point.
  • Mapping an agency's client list by searching the agency as the payer.
  • Checking which markets a company is actually buying in, and roughly how heavily, in the EU.
  • Building a swipe file of headlines and calls to action for a category before writing new ads.

Mapping an agency's clients and who runs them, in three steps:

  1. Run this actor with payers set to the agency's name and an EU code in countries.
  2. Collect the distinct advertiserName values: that is the agency's client list.
  3. Put them into LinkedIn Company Employees Scraper as companies, with jobTitles set to marketing roles, to see who runs those campaigns.

🚧 What it does not do

  • No spend, no budget, no CPM. The library does not publish them, and neither does this.
  • Impressions are bands, and EU only. So are run dates and targeting. Outside the EU those fields are null on every row.
  • About twelve months of history. Older campaigns are gone from the library itself.
  • No audience data about who saw an ad, beyond the targeting facets LinkedIn discloses.
  • A name search is a name match. Two companies sharing a name both come back. Use the company URL with the numeric id when you need exactly one advertiser.
  • Restricted ads arrive without their creative. You get the card and the flag, not the image.
  • No ranking by performance. The order is the library's, and it is not by impact.

🧭 Which LinkedIn scraper do you need?

If you wantUse
The ads a company runs, from LinkedIn's Ad LibraryThis one
Facebook and Instagram ads from Meta's Ad LibraryMeta Ad Library Scraper
The ads a brand runs on GoogleGoogle Ads Transparency Scraper
Size, followers, headquarters and website for company page URLsLinkedIn Companies Scraper
Recent posts from a company pageLinkedIn Company Posts Scraper
The people who work at one companyLinkedIn Company Employees Scraper

❓ Questions people ask

Do I need a LinkedIn account to search the Ad Library?

No, and there is no cookie field. The Ad Library is public.

Why are the dates and impressions empty?

Because the ad was not delivered into the EU, or your search was not scoped to an EU country. That disclosure only exists for EU delivery.

Can I get ads older than a year?

No. The library holds about twelve months and there is no archive behind it.

Why did I get fewer rows than maxItems?

Either the searches found fewer ads, or your budget was split across several searches. Check searchTerm on the rows to see which.

Can I call it from code or connect it to an AI assistant?

Yes. The API tab has ready-made code for Python, JavaScript and the command line. For Claude, ChatGPT or another MCP client, connect https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/linkedin-ads-scraper. Either way the run happens on your Apify account at the same price.

It is a public transparency database LinkedIn publishes on purpose. Apify's write-up on the legality of web scraping is a reasonable starting point, and we are not lawyers.

πŸ†˜ If something breaks

Open the Issues tab on the actor page. Send the run ID and the exact search you used. The errorCode on the diagnostic row is usually enough to explain it.