# Changelog of LinkedIn Ads Scraper (`solidcode/linkedin-ads-scraper`) Actor

- **URL**: https://apify.com/solidcode/linkedin-ads-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/solidcode/linkedin-ads-scraper.md

## Changelog

### 1.0.17

- **Fixed: on detail runs, a few ads still named the wrong company.** 1.0.15 fixed this for search results but missed the ad's own page, so with **Fetch full ad details** switched on about 7% of rows still had `advertiserSlug` and `advertiserUrl` pointing at a company or person merely *mentioned inside* the ad. An ad paid for by "Ray Sanders" came back linked to `jet-propulsion-laboratory`, one by "Just Do Consulting" to `nexthealthmgmt`. Those rows now come back **empty rather than wrong**. Where LinkedIn does publish the advertiser's own link, it is returned exactly as before. **If you filter on `advertiserSlug`, note that a small number of detail rows that used to carry a value are now empty — every value that remains is the real advertiser.**
- Advertiser searches are unaffected: every row still carries the company id and URL the run pinned before collecting, as it has since 1.0.15. `advertiserName` is unchanged on every row.

### 1.0.16

- **Detail mode is not an EU-only feature, and the descriptions now say so.** The full ad copy, the destination link, the paying entity and the video file come back in **every** country. On a US-only test run, switching **Fetch full ad details** on lifted the longest ad body from 121 characters to 2,999 and filled the paying entity on 100% of rows. Only LinkedIn's transparency block — dates active, total impressions, impressions per country, targeting — is EU-served-ads-only, and only the ads carrying it are billed at the higher price: 72.5% of that US run stayed at the basic price. Nothing about the data or the pricing changed, only the descriptions of it.
- **The "Ad details" table is now called "Ad details (needs detail mode)".** On a run with detail mode off, most of its columns are empty by design, which read as a broken table rather than an unused option. The five columns LinkedIn only publishes for EU-served ads are now labelled `(EU only)` individually, and the ad copy column was added so the table shows something on every run.
- **Honest field coverage.** Not every ad carries a headline, body copy or image, and the field descriptions now state the measured rates instead of implying they are always present. `headline` lands on 40% to 91% of rows depending on which formats your search returns, because LinkedIn omits it for article, carousel, message and document ads and most video ads. Job and message (InMail) ads carry no headline, no copy and no image at all — 2.2% of rows across eight test searches. No data changed.
- The `follow` format is confirmed against LinkedIn's own card label, "Follow Company Ad".

### 1.0.15

- **`advertiserSlug` and `advertiserUrl` now fill in on every row of an Advertisers search, for free.** The run already works out exactly which LinkedIn company page each advertiser you list belongs to before it starts collecting, so every ad it returns for that advertiser now carries the company's LinkedIn id and URL. Previously these came back empty on 99% of rows and only appeared if you paid for **Fetch full ad details**.
- **Fixed: a handful of rows carried the wrong company.** On roughly 1 in 12 ads, `advertiserSlug` and `advertiserUrl` pointed at a company mentioned *inside* the ad rather than the advertiser who ran it — an ad by "Matt Freestone" came back linked to `itdobenord`, one by "Beeri Amiel" to `xfunnel-ai`. Those rows now return the correct advertiser on an Advertisers search, and empty rather than wrong on keyword searches.
- **New field `detailPageFetched`.** `true` when the ad's own page was read and folded into the row. This is the field to filter on if you want the enriched rows. **`detailsFetched` is unchanged** and still means "LinkedIn published its EU disclosure for this ad, so the higher price applied" — a US ad can be fully enriched and still read `detailsFetched: false`, which used to make enriched non-EU ads look like they had been skipped.
- **Runs that stop at your Max results now say so.** A multi-advertiser run that filled its result budget used to finish with a bare "Done! 312 ads from 3 queries", giving no hint there was more to collect. It now ends with "(max-results cap of 300 reached)".
- **A search LinkedIn never answered no longer counts as a search with no ads.** If every connection attempt for one of your keywords or advertisers is refused, the run now says so plainly and reports it separately, instead of quietly reporting it alongside searches that genuinely returned nothing.
- Pricing is unchanged. Every ad still costs exactly what it did before.

### 1.0.14

- **`videoUrl` now actually fills in on video ads.** It was empty on every video ad ever returned. LinkedIn puts the player on the ad's own page and shows only a still frame in search results, so the field now fills whenever **Fetch full ad details** is switched on, and gives you the direct video file at the best quality LinkedIn offers. A basic run without detail mode still returns it empty, and the description now says so. Video ads are also easier to spot in the new **Video** column of the **Ad details** table.
- **Country names in `impressionsPerCountry` read correctly.** `Bosnia &amp; Herzegovina` and `Trinidad &amp; Tobago` now come back as `Bosnia & Herzegovina` and `Trinidad & Tobago`. **If you match on those country names, update your filters** — the old spelling is gone.
- **You can now add up the country shares.** LinkedIn groups every country under one percent into a single "less than 1%" bucket but still reports it as `1`, so an ad served in 174 countries looked like it totalled 230%. Each country now also carries `percentMin` and `percentMax`: add up `percentMin` for the smallest share those countries can really represent and `percentMax` for the largest. This also separates a true 1% market from a rounding-error one, which the number alone could never do. **`percent` itself is unchanged**, so existing filters and sorts keep working exactly as before.

### 1.0.13

- **Advertiser searches now return one company, not everyone with that name.** LinkedIn treats the **Advertisers** field as a company-*name* match, so a run for `hubspot` came back roughly half HubSpot and half partner agencies with "HubSpot" in their own company name — and you were billed for those extra ads. Each advertiser is now pinned to its actual LinkedIn company page first, so you get that company's ads only. **If you were relying on the wider set, switch on the new "Include partners and agencies with the advertiser's name" option to get the old behaviour back.**
- New option **Include partners and agencies with the advertiser's name** (`includeRelatedAdvertisers`, off by default). Only affects the Advertisers field; keyword searches and pasted search URLs are unchanged.
- When a brand can't be pinned to a single company page, the run log now says so and falls back to the old name match for that advertiser instead of failing.
- Pasting an `/ad-library/company/<slug>` URL into **Start URLs** gets the same one-company treatment.

### 1.0.12

- **Documentation accuracy.** Dates active, total impressions, impressions per country and targeting are now described everywhere as what they are: fields that need **Fetch full ad details** switched on, and that LinkedIn only publishes for **EU-served ads**. US and other non-EU ads return them empty no matter what. Nothing about the data changed, only the descriptions of it.
- **Dataset views split.** The default **Ads overview** table now shows only columns that carry data on every run (advertiser, format, headline, ad copy, image, ad URL, search). A second **Ad details** view holds the detail-page columns.
- **Max results.** Leaving the field empty still stops the run at 1,000 ads. The field description used to imply an empty box meant an unlimited run — it doesn't. Type `0` if you want no cap.
- Run summary now reads "1 query" instead of "1 queries".

### 1.0.11

- **`format` now has 13 values instead of 9.** Roughly one ad in five used to come back as `format: "unknown"`. Those rows now carry their real format: `article`, `job`, `event` or `follow`. **If you filter on `format == "unknown"` to catch article, job or event ads, that filter will now match nothing** — switch it to the specific format names. The four new values are:
  - `article` — Article Ad (about 6% of all ads)
  - `job` — Job Ad
  - `event` — Event Ad
  - `follow` — Follow Company Ad
- `advertiserName` no longer contains raw HTML codes. Names like `MAN Digital: HubSpot &amp; RevOps Agency` and `Joseph D&#39;Antonio, MBA` now read correctly.
- Job and Follow Company ads used to arrive with an empty `advertiserName`. They now carry the advertiser.

### 1.0.10

- `impressionsRange` now fills in on the ads that show a small figure. LinkedIn's most common bucket is `< 1k`, and it used to be dropped, leaving the field empty on about 80% of enriched EU ads. The field also gained a `label` key carrying LinkedIn's own wording.
- `impressionsPerCountry` now populates. It was empty on every row. It reports each country's **share** of the ad's impressions, which is what LinkedIn publishes: `{"Germany": {"percent": 62.0, "label": "62%"}}`.
- `body` now carries the complete ad copy on detail-enriched runs. Search results truncate it at about 120 characters, and enriched runs used to ship the same truncated preview.

### 1.0.9

- Runs with several keywords or advertisers now collect from all of them. The whole result budget used to go to the first search, so later searches returned nothing.
- An ad matching two of your searches is now saved and charged once, not twice.
