LinkedIn Scraper
Search Ads
Search the LinkedIn Ad Library by keyword, advertiser, country, or date.
Endpoint
Parameters
| Name | Type | Required | Note |
|---|---|---|---|
| keywordstring · required if keyword, searchUrl, accountOwner, countries, dateOption, startdate, enddate are all empty | string | required if keyword, searchUrl, accountOwner, countries, dateOption, startdate, enddate are all empty | Search by keyword. Each WORD is matched separately and combined with AND, across text that includes the ad copy, the advertiser and their pages — so "energy drink" finds ads containing both words somewhere, not ads about energy drinks. The Ad Library has no phrase search: quotes and AND/OR/NOT are ignored by LinkedIn itself. Use a single distinctive word where you can, or turn on Phrase match only. At least one search parameter is required on this step — this field, Search URL, Account Owner, Countries, or a date filter. Example: |
| searchUrlstring · optional | string | optional | Ad Library search URL to scrape directly Example: |
| accountOwnerstring · optional | string | optional | Search by company or advertiser name Example: |
| countriesstring · optional | string | optional | Comma-separated country codes or ALL Example: |
| dateOptionstring · optional | string | optional | Filter ads by date range One of: |
| startdatestring · optional | string | optional | Start date for custom range (YYYY-MM-DD) Used only when dateOption is custom-date-range. Example: |
| enddatestring · optional | string | optional | End date for custom range (YYYY-MM-DD) Used only when dateOption is custom-date-range. Example: |
| limitnumber · optional | number | optional | Max number of ads to return (1-1000). Default: 100. Each page returns up to 24 ads, so a smaller number here also means fewer pages scraped. Default: Example: |
| phraseMatchOnlyboolean · optional | boolean | optional | Keep only ads whose returned text contains your keyword as a whole phrase. Off by default. The pages are already paid for when this runs, so it returns FEWER results rather than fetching more — on a measured "energy drink" page it kept 1 of 24. `droppedByFilter` on the result says how many it removed. Raise Limit if you need more rows back. Default: |
Response schema
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"elements"
],
"properties": {
"hasMore": {
"type": "boolean",
"description": "True only when the provider still had reachable data and this execution stopped early. A managed Agent must treat this as an incomplete batch, never as completion."
},
"elements": {
"type": "array",
"items": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "string",
"description": "Unique ad identifier"
},
"about": {
"type": "object",
"properties": {
"ranTo": {
"type": "string",
"description": "End date of the campaign"
},
"format": {
"type": "string",
"description": "Ad format"
},
"paidBy": {
"type": "string",
"description": "Who paid for the ad"
},
"ranFrom": {
"type": "string",
"description": "Start date of the campaign"
},
"advertiserUrl": {
"type": "string",
"description": "Advertiser URL"
},
"advertiserName": {
"type": "string",
"description": "Advertiser name"
}
},
"description": "Ad campaign metadata",
"additionalProperties": true
},
"variants": {
"type": "array",
"items": {
"type": "object",
"properties": {
"content": {
"type": "object",
"properties": {
"slides": {
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"imageUrl": {
"type": "string"
},
"targetUrl": {
"type": "string"
}
},
"additionalProperties": true
},
"description": "Carousel slides"
},
"ctaLabel": {
"type": "string",
"description": "Call to action label"
},
"headline": {
"type": "string",
"description": "Ad headline"
},
"imageUrl": {
"type": "string",
"description": "Ad image URL"
},
"targetUrl": {
"type": "string",
"description": "Click-through URL"
},
"description": {
"type": "string",
"description": "Ad copy text"
},
"videoThumbnailUrl": {
"type": "string",
"description": "Video thumbnail URL"
}
},
"description": "Ad creative content",
"additionalProperties": true
},
"advertiser": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Advertiser company name"
},
"headline": {
"type": "string",
"description": "Advertiser headline"
},
"imageUrl": {
"type": "string",
"description": "Advertiser logo URL"
},
"linkedinUrl": {
"type": "string",
"description": "Advertiser LinkedIn URL"
}
},
"description": "Advertiser details",
"additionalProperties": true
},
"creativeType": {
"type": "string",
"description": "Type of ad creative"
}
},
"additionalProperties": true
},
"description": "Ad creative variants"
},
"targeting": {
"type": "object",
"properties": {
"segments": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"excludes": {
"type": "array",
"items": {
"type": "string"
}
},
"includes": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": true
},
"description": "Targeting segments"
},
"parameters": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"excluded": {
"type": "boolean"
},
"targeted": {
"type": "boolean"
}
},
"additionalProperties": true
},
"description": "Targeting parameters"
}
},
"description": "Targeting criteria",
"additionalProperties": true
},
"advertiser": {
"type": "object",
"properties": {
"name": {
"type": [
"string",
"null"
],
"description": "The advertiser's name — a company name, or null for an individual: the Ad Library search does not send a person's name, only their headline (which is returned on `headline`). To get an individual advertiser's real name, run Get Ad on this ad's id — its `about.advertiserName` has it."
},
"headline": {
"type": [
"string",
"null"
],
"description": "The advertiser's own headline, for individuals. Null for companies, which have none here."
},
"imageUrl": {
"type": "string",
"description": "Advertiser logo or profile photo URL"
},
"linkedinUrl": {
"type": "string",
"description": "Advertiser LinkedIn URL, when the endpoint sends one"
},
"advertiserType": {
"anyOf": [
{
"enum": [
"person",
"company"
],
"type": "string"
},
{
"type": "null"
}
],
"description": "Whether the advertiser is an individual or a company, read from their avatar. Null when there is no avatar to tell from."
}
},
"description": "Who ran the ad",
"additionalProperties": true
},
"impressions": {
"type": "object",
"properties": {
"total": {
"type": "string",
"description": "Total impressions"
},
"byCountry": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Country name"
},
"percentage": {
"type": "string",
"description": "Percentage of impressions"
}
},
"additionalProperties": true
},
"description": "Impressions by country"
}
},
"description": "Impression stats",
"additionalProperties": true
}
},
"additionalProperties": true
}
},
"nextPage": {
"type": "integer",
"exclusiveMinimum": 0
},
"returned": {
"type": "number",
"description": "How many records this run returned, after any `limit` was applied. ONE EXCEPTION: on a chat preview — where `truncated` is true — this is the count actually FETCHED while `elements` carries only a short sample of them, so the two deliberately disagree. Read `truncated` before comparing this against the array length; in a workflow it is never set and the two always match. Matches the other LinkedIn data tools, whose `meta.returned` is the fetched count on a truncated preview too."
},
"truncated": {
"type": "boolean"
},
"stopReason": {
"enum": [
"cancelled",
"provider-error",
"empty-page-stall",
"caller-limit",
"presentation-preview",
"cursor-stall",
"runtime-page-window",
"time-budget"
],
"type": "string"
},
"suggestion": {
"type": "string"
},
"totalCount": {
"type": "number",
"description": "How many records the search MATCHES, per the provider — the grand total, routinely in the millions while the endpoint will only serve about a thousand of them. Do NOT compare it with the row count to decide whether a run was complete, and do not paginate towards it: use `servableCount` for what is actually reachable. Absent when the provider sent no count."
},
"totalPages": {
"type": "number"
},
"pagesScraped": {
"type": "number"
},
"servableCount": {
"type": "number",
"description": "How many records this endpoint will serve across all its pages — the real ceiling on what any number of runs can reach, which the provider caps well below `totalCount` on most search endpoints. Absent when the provider sent no count."
},
"totalElements": {
"type": "number",
"description": "DEPRECATED — despite the name this is the count RETURNED by this run, not a grand total, so it equals your `limit` on a limited run. Kept at that value so existing flows do not change meaning. Use `returned` for this number, `totalCount` for how many records match, or `servableCount` for how many are reachable."
},
"nextPaginationToken": {
"type": "string"
}
},
"additionalProperties": true
}