LinkedIn Ads Scraper: Full Advertiser Ad History
Under maintenancePricing
$19.99/month + usage
LinkedIn Ads Scraper: Full Advertiser Ad History
Under maintenanceLinkedIn Ads Scraper: Full Advertiser Ad History extracts data from LinkedIn ad campaigns, including ad titles, descriptions, impressions, engagement metrics, and company details. Ideal for marketers and analysts to track competitors and optimize campaigns.
Pricing
$19.99/month + usage
Rating
0.0
(0)
Developer
Scraper Engine
Maintained by CommunityActor stats
0
Bookmarked
10
Total users
1
Monthly active users
5 days ago
Last modified
Categories
Share
LinkedIn Ads Scraper — Ad Creatives, Run Dates and Coverage %
LinkedIn Ads Scraper extracts every ad it can find for a chosen advertiser on the public LinkedIn Ad Library — ad copy, call-to-action text, creative images, format, the paid-by line, and run start/end dates — by sweeping the advertiser's history across repeated time windows instead of the single results page the library shows for a plain search. Every row carries the library's own "ads match your search" total next to the count actually returned, so coverage is a measured number, not a guess. Paid-media analysts, competitive-intelligence teams, and agencies tracking a rival's LinkedIn ad activity over months — not just today's snapshot — are the natural users. Point it at a company name or LinkedIn URL and it does the rest.
What is LinkedIn Ads Scraper: Full Advertiser Ad History?
It is an Apify Actor that reads the public LinkedIn Ad Library (linkedin.com/ad-library) for one or more named advertisers and returns each distinct ad as a structured dataset row, plus one optional roll-up row per advertiser. No LinkedIn account, login, or API key is required — the Actor reads the same public pages a signed-out visitor sees, over plain HTTP requests.
Key capabilities:
- 🏢 Flexible targeting — accepts a company name, a
linkedin.com/company/…or/school/…URL, or a ready-made Ad Library search URL - 🗓️ Multi-window history sweep — walks up to 36 months back in configurable 7/14/30/90-day steps to get past the library's one-page-per-query limit
- 🌍🔎 Extra coverage passes — optional additional sweeps by country code or ad-text keyword, run after the time sweep, to surface ads the date walk alone misses
- 📝 Full ad-level fields — ad copy, CTA text, creative image URLs, paid-by entity, run start/end dates, and a currently-running flag
- 🧮 Honest coverage accounting — every row states how many ads the library lists for that search versus how many were actually returned
- ⬇️ Standard dataset export — results are a normal Apify dataset, downloadable as JSON, CSV, Excel, or any other format Apify supports
What data can I extract with LinkedIn Ads Scraper?
Each dataset row is either an ad record (type: "ad") or, if enabled, one advertiser coverage summary (type: "advertiserCoverage", isChild: true) — the table below covers every field the Actor writes and which row type carries it.
| Field | Example Value | Use Case |
|---|---|---|
adId | "3765412098" | Unique ad identifier (ad rows only; null on summary rows) |
type | "ad" | Row kind — "ad" or "advertiserCoverage" |
isChild | false | true on the advertiser summary row, false on ad rows |
advertiserTarget | "hubspot" | The input value that discovered this row |
resultRank | 3 | Position within its discovery search (ad rows only) |
discoveryFacet | "2025-04-01 to 2025-04-30" | Which sweep step or axis found this ad (ad rows only) |
adLibraryUrl | "https://www.linkedin.com/ad-library/detail/3765412098" | Direct link to the ad's public detail page (ad rows only) |
advertiserName | "HubSpot" | Advertiser display name |
advertiserUrl | "https://www.linkedin.com/company/1234" | Advertiser's LinkedIn company page (ad rows only) |
advertiserCompanyId | "1234" | LinkedIn's numeric company ID |
advertiserLogo | "https://media.licdn.com/…" | Advertiser logo image URL (ad rows only) |
format | "SINGLE_IMAGE" | Ad creative format (ad rows only) |
body | "Turn more leads into customers with…" | Ad copy text (ad rows only) |
ctas | ["Learn more"] | Call-to-action label(s) (ad rows only) |
paidBy | "HubSpot, Inc." | The entity named as paying for the ad |
imageUrls | ["https://media.licdn.com/…jpg"] | Creative image URLs (ad rows only) |
adRunStart | "2025-03-14" | Date the ad started running (ad rows only) |
adRunEnd | "2025-04-02" | Date the ad stopped, or last observed date (ad rows only) |
adDurationDays | 20 | Days between adRunStart and adRunEnd (ad rows only) |
isCurrentlyRunning | false | Whether adRunEnd is today or later (ad rows only) |
firstSeen | "2024-08-02" | Earliest adRunStart across all this advertiser's ads (summary row only) |
lastSeen | "2025-04-02" | Latest adRunEnd across all this advertiser's ads (summary row only) |
creativeTypeMix | "SINGLE_IMAGE: 14, VIDEO: 6" | Ad-format breakdown for the advertiser (summary row only) |
totalAdsMatchingSearch | 312 | The library's own "ads match your search" total |
adsReturnedBySurface | 20 | Distinct ads this run actually returned for the advertiser |
adRowsEmitted | 20 | Ad rows written for this advertiser (summary row only) |
windowsQueried | 14 | Number of sweep steps/facets queried for this advertiser |
windowsWithNewAds | 9 | Steps that surfaced at least one new ad (summary row only) |
coveragePct | 6.41 | adsReturnedBySurface as a percentage of totalAdsMatchingSearch, capped at 100 |
startUrl | "https://www.linkedin.com/ad-library/search?accountOwner=hubspot…" | The search URL that found this ad, or the anchor search for a summary row |
scrapedAt | "2026-08-15T09:41:02+00:00" | Collection timestamp, ISO 8601 UTC |
Ad performance and timing data
The fields that tell you what an ad says and when it ran sit on every ad row: body (the ad copy), ctas (button label), format, imageUrls, paidBy, and the run-date trio adRunStart / adRunEnd / adDurationDays, plus isCurrentlyRunning which is derived by comparing adRunEnd to today. A common use: pull every ad with isCurrentlyRunning: true to see exactly what a competitor is running right now, then cross-reference format and ctas to see which creative angle they're leaning on this quarter.
Coverage and discovery data
totalAdsMatchingSearch, adsReturnedBySurface, windowsQueried, and coveragePct tell you how thorough a given run was for that advertiser — useful before trusting a "they only run 12 ads" conclusion. discoveryFacet and resultRank record which sweep step and position found each ad, and startUrl gives the exact search that produced it, so any row can be traced back to a reproducible query.
Why not build this yourself?
LinkedIn does not publish a public Ad Library API — as of 15 August 2026, linkedin.com/ad-library is browser-only: searchable by advertiser, keyword, payer, country, and date range, but with no archive endpoint, no historical export, and no documented way to request results programmatically (source, source). Building a puller yourself means reverse-engineering three separate problems this Actor already solves: the library only ever returns one short page per query, so a real history requires running the same search across many date windows and merging by ad ID; the site occasionally serves a well-formed interstitial page instead of results, which a size-only check would silently accept as "no ads"; and a date window whose end is today comes back empty even when the same window ending yesterday is full — a trap that reads as "this advertiser stopped advertising" unless every window is explicitly capped one day short of today.
This Actor handles the window-walking, the interstitial detection (a response only counts as an answer when it carries a specific positive marker and a realistic page size — otherwise it's retried, never parsed), and the date-clamping automatically. Use the public Ad Library directly for a one-off manual look at a single advertiser; use this Actor when you need the same check repeated across many advertisers, on a schedule, landing in one structured dataset.
How to use data extracted from LinkedIn Ads?
Paid-media and competitive-intelligence analysts
Point advertiserTargets at a shortlist of competitors, set countries to "ALL" for the widest catalogue, and filter the resulting rows on isCurrentlyRunning to see what's live today versus what ran and stopped. body, ctas, and format show the messaging and creative format mix; adRunStart/adRunEnd show how long each concept stayed in rotation — enough to spot when a competitor's positioning shifts.
Agencies auditing client or prospect accounts
Run the same advertiser list on a schedule (Apify's built-in Schedules) and diff consecutive runs on adId to flag new or retired ads since the last check. coveragePct on each run is a built-in sanity check before reporting numbers to a client — a low percentage means the library's own total is higher than what this run reached, and the sweep should go deeper (historyMonthsBack, smaller windowSizeDays) before the report goes out.
Market research and creative-trend mapping
Run a batch of advertisers in one call and aggregate creativeTypeMix (from the coverage summary rows) and format (from ad rows) across the set to see which ad formats a sector leans on, or use expandKeywords to sweep for a shared topic like "webinar" or "demo" across the same companies and compare messaging.
AI agents and automated pipelines
Because output is a stable, typed JSON dataset, it drops directly into an agent's context or a RAG index for questions like "what is HubSpot currently advertising on LinkedIn?" — the agent reads body, ctas, and isCurrentlyRunning without any HTML parsing of its own.
⬇️ Input sample
| Parameter | Required | Type | Default / Prefill | Description |
|---|---|---|---|---|
advertiserTargets | No | array (string list) | prefill: ["hubspot"] | Company names, LinkedIn company URLs, or LinkedIn Ad Library search URLs — one per line. |
countries | No | string (enum, ~90 country codes plus "ALL") | prefill: "ALL" | Only keep ads shown in this country. "ALL" gives the widest history — a single country can cut an advertiser's visible catalogue by two thirds. |
maxAdsPerAdvertiser | No | integer (min 1, max 1000) | prefill: 100 | How many distinct ads to collect per advertiser before moving on. The sweep also stops on its own once the advertiser's history runs dry. |
historyMonthsBack | No | integer (min 1, max 36) | default: 12 | How many months of history to trace for each advertiser. |
windowSizeDays | No | string enum: "7", "14", "30", "90" | default: "30" | Size of each sweep step. Smaller windows surface more ads from busy advertisers; larger windows finish faster. |
stopAfterEmptyWindows | No | integer (min 1, max 20) | default: 4 | End an advertiser's time sweep early once this many steps in a row return no new ads. |
expandCountries | No | array (string list) | prefill: [] | Two-letter country codes to sweep as extra passes, e.g. JP, BR, DE. |
expandKeywords | No | array (string list) | prefill: [] | Words that appear in the ad text, e.g. webinar, pricing, demo. Each runs as an extra pass. |
includeCoverageSummary | No | boolean | default: true | Adds one extra row per advertiser (type: "advertiserCoverage") with format mix, first/last run dates, and coverage percentage. |
input | No | array (string list) | — | Legacy. Older name for advertiserTargets. Used only when that field is empty. |
dateOption | No | string enum: "", "last-7-days", "last-30-days", "last-90-days", "current-month", "this-month", "current-year", "this-year", "last-year" | prefill: "" | Legacy. Time range for the first look at each advertiser, before the history sweep starts. "" (Any time) gives the widest starting set. |
maxItems | No | integer (min 1, max 5000) | — | Legacy. Optional hard cap on the total number of ads across the whole run. Leave empty to let maxAdsPerAdvertiser decide per advertiser. |
proxyConfiguration | No | object (proxy editor) | prefill: {"useApifyProxy": true} | Apify Proxy is recommended — a history sweep makes many sequential reads and is far more reliable with it. |
None of the parameters are required — if advertiserTargets and input are both left empty, the run fails immediately with "No advertisers given."
{"advertiserTargets": ["hubspot", "https://www.linkedin.com/company/microsoft/"],"countries": "ALL","historyMonthsBack": 12,"windowSizeDays": "30","maxAdsPerAdvertiser": 200,"includeCoverageSummary": true}
Common pitfall: leaving countries set to a single market instead of "ALL" is the single biggest way to under-collect — the input description itself notes a single country can cut an advertiser's visible catalogue by two thirds. Start with "ALL", then narrow only once you've confirmed how much history exists.
⬆️ Output sample
Output is typed, normalized JSON — one row per ad, plus one optional coverage-summary row per advertiser. Export it as JSON, CSV, Excel, or any other format the Apify dataset supports. A full ad row:
{"adId": "3765412098","type": "ad","isChild": false,"advertiserTarget": "hubspot","resultRank": 3,"discoveryFacet": "2025-04-01 to 2025-04-30","adLibraryUrl": "https://www.linkedin.com/ad-library/detail/3765412098","advertiserName": "HubSpot","advertiserUrl": "https://www.linkedin.com/company/1234","advertiserCompanyId": "1234","advertiserLogo": "https://media.licdn.com/dms/image/advertiser-logo.png","format": "SINGLE_IMAGE","body": "Turn more leads into customers with HubSpot's free CRM.","ctas": ["Learn more"],"paidBy": "HubSpot, Inc.","imageUrls": ["https://media.licdn.com/dms/image/creative-1.jpg"],"adRunStart": "2025-03-14","adRunEnd": "2025-04-02","adDurationDays": 20,"isCurrentlyRunning": false,"totalAdsMatchingSearch": 312,"adsReturnedBySurface": 20,"windowsQueried": 14,"coveragePct": 6.41,"startUrl": "https://www.linkedin.com/ad-library/search?accountOwner=hubspot&dateOption=custom-date-range&startdate=2025-04-01&enddate=2025-04-30","scrapedAt": "2026-08-15T09:41:02+00:00"}
When includeCoverageSummary is on, one extra row per advertiser looks like this instead (note the different field set):
{"adId": null,"type": "advertiserCoverage","isChild": true,"advertiserTarget": "hubspot","advertiserName": "HubSpot","advertiserCompanyId": "1234","paidBy": "HubSpot, Inc.","firstSeen": "2024-08-02","lastSeen": "2025-04-02","creativeTypeMix": "SINGLE_IMAGE: 14, VIDEO: 6","totalAdsMatchingSearch": 312,"adsReturnedBySurface": 20,"adRowsEmitted": 20,"windowsQueried": 14,"windowsWithNewAds": 9,"coveragePct": 6.41,"startUrl": "https://www.linkedin.com/ad-library/search?accountOwner=hubspot","scrapedAt": "2026-08-15T09:41:02+00:00"}
Both row shapes are charged under the same pay-per-event, row_result — filter type == "ad" in your downstream code if you only want ad records and not the coverage roll-up, or turn includeCoverageSummary off to skip generating (and paying for) it in the first place.
How do you filter and target specific ads?
Four real controls decide what you get back:
- Company target vs. keyword sweep.
advertiserTargets(a company name, LinkedIn company/school URL, or a ready-made Ad Library search URL) anchors the sweep on one advertiser.expandKeywordsadds a separate pass filtered on ad-text keywords for that same advertiser — useful for isolating a topic ("webinar", "pricing") within a large advertiser's catalogue rather than reading everything. - Scope precision.
countriesnarrows to one market (or"ALL"for the widest set);expandCountriesadds extra full passes in other markets, since audiences by country only partly overlap.historyMonthsBacksets how far back to look;windowSizeDayssets the step size — smaller steps ("7") go deeper on busy advertisers, larger steps ("90") finish faster on quiet ones. - Stopping behavior as a quality signal.
stopAfterEmptyWindowsends the time sweep once that many consecutive steps add nothing new, and every row'scoveragePcttells you afterward how complete the result actually was against the library's own total — a low number is a real signal to lowerwindowSizeDaysor raisehistoryMonthsBack, not to trust the count as-is. - Volume controls.
maxAdsPerAdvertisercaps ads per advertiser (1–1000); the legacymaxItemscaps the whole run across every advertiser (1–5000) and, when set, splits its remaining budget across the targets still to run.
{ "advertiserTargets": ["stripe"], "countries": "US", "historyMonthsBack": 6, "windowSizeDays": "7", "maxAdsPerAdvertiser": 300 }
{ "advertiserTargets": ["salesforce"], "countries": "ALL", "historyMonthsBack": 36, "windowSizeDays": "30", "expandCountries": ["DE", "JP", "BR"] }
{ "advertiserTargets": ["hubspot", "zendesk"], "expandKeywords": ["webinar", "demo", "pricing"], "includeCoverageSummary": true }
▶️ Want to try other SimpleAPI scrapers?
| Scraper Name | What it extracts |
|---|---|
| Reddit Ads Scraper — Full Catalog Access | Ads from Reddit's public ad catalog, the closest equivalent ad-library sweep for another platform |
| Shopify Merchant Scraper: Niche & Keyword Store Search | Shopify stores discovered by niche or keyword — a comparable directory-search Actor |
| Amazon DE Sellers Leads Scraper — Product Price & Ratings | Amazon.de seller and listing leads with price and rating data — comparable business-intelligence records |
How to extract LinkedIn Ad Library data programmatically
This Actor runs as a standard Apify Actor: one API call starts the run, and results land in a dataset you read back as JSON.
Python example
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_API_TOKEN>")run = client.actor("<your-username>/linkedin-ads-scraper-full-advertiser-ad-history").call(run_input={"advertiserTargets": ["hubspot"],"countries": "US","historyMonthsBack": 12,})for item in client.dataset(run["defaultDatasetId"]).iterate_items():if item.get("type") == "ad":print(item["advertiserName"], item["adRunStart"], item["body"])
Export to spreadsheets or CRM
Every Apify dataset exports directly to CSV or Excel from the Console or the API — map advertiserName, body, ctas, adRunStart, adRunEnd, and isCurrentlyRunning straight into a tracking sheet or CRM import, one column per field.
⚖️ Is it legal to scrape LinkedIn Ad Library data?
Yes — this Actor reads pages LinkedIn already publishes without login at linkedin.com/ad-library, a transparency archive built specifically to be publicly searchable. The records it returns are business and marketing data — ad copy, formats, run dates, and the entity that paid for the ad — not personal data about private individuals, so GDPR's rules on personal-data processing do not attach here. What does apply is LinkedIn's own Terms of Service and standard database-rights principles governing systematic extraction and reuse of a platform's content. Consult legal counsel for commercial applications involving bulk storage or redistribution of this data.
❓ FAQ
How do I know if a LinkedIn ad is still running or has stopped?
isCurrentlyRunning is set directly from the ad's own end date (adRunEnd) compared to today — true if the ad's run end is today or later, false if it has already ended. adRunStart and adRunEnd give the exact dates either way.
Can I get an advertiser-level coverage summary along with the ad rows?
Yes — set includeCoverageSummary (on by default) and each advertiser gets one extra row, type: "advertiserCoverage", with creativeTypeMix, firstSeen/lastSeen, adRowsEmitted, windowsWithNewAds, and coveragePct. It's charged as a normal row under the same row_result event as ad rows.
How accurate is the ad copy, run-date, and paid-by data?
The Actor returns exactly what LinkedIn's own ad detail page shows at request time (scrapedAt records when). Accuracy after that depends on LinkedIn keeping the listing current — re-run the sweep before relying on run-date fields for a time-sensitive decision.
How many ads can I get per run?
maxAdsPerAdvertiser caps ads per advertiser at up to 1000; the legacy maxItems field caps the entire run at up to 5000 ads across every advertiser combined, and splits its remaining budget across whichever targets haven't run yet. There is no higher documented cap.
How do I sweep deeper history for one advertiser?
Raise historyMonthsBack (up to 36) and lower windowSizeDays (down to "7") — smaller steps surface more of a busy advertiser's catalogue per pass, at the cost of more requests. expandCountries and expandKeywords add further passes beyond the time sweep for advertisers whose catalogue still isn't fully reached.
⚠️ What happens if an ad's detail page can't be read?
That ad is left out of the output rather than guessed — the Actor logs how many detail pages it had to drop at the end of the run. This is a real, honest gap: adsReturnedBySurface and coveragePct reflect only ads whose detail page was successfully parsed, not every ad ID the search results surfaced.
Does this Actor work with Claude, ChatGPT, and AI agent frameworks?
There is no dedicated MCP server for this Actor. It is callable as a standard HTTP/API endpoint through the Apify API or apify_client from any agent framework capable of making a tool call.
Can I use this Actor without a LinkedIn account, login, or API key?
Yes — no LinkedIn credentials of any kind are used or required. You need only an Apify account to run the Actor and read the resulting dataset.
Can I target ads by keyword instead of by advertiser?
Not on its own — advertiserTargets (a company, URL, or advertiser-scoped search) is required to anchor a run. expandKeywords narrows within that advertiser's ads by ad-text keyword; it does not run an open, advertiser-agnostic keyword search across the whole library.
Conclusion
LinkedIn Ads Scraper: Full Advertiser Ad History turns the LinkedIn Ad Library's one-page-at-a-time public interface into a structured, multi-month dataset for one or many advertisers at once — ad copy, creative, run dates, and an honest coverage percentage on every row. It's built for analysts, agencies, and researchers who need a repeatable, filterable record of what a company is running on LinkedIn, not a single manual lookup. Start a run with a company name or LinkedIn URL in advertiserTargets and read the results back as JSON, CSV, or Excel from the Apify Console or API.