- No ad disappears when our transcription service goes down mid-run. If the speech and text-reading service refuses the actor's access partway through a run, every ad still in the queue now comes back as its own row — status
asr_unavailable, retryable: true, never charged — saying the problem is on our side and asking you to re-run later. Before, those ads were only counted in the end-of-run summary, so a run (or an actor chained to its dataset) saw fewer rows than ads with no per-ad trace of why. The summary line is unchanged; the run still stops immediately without spending anything on calls that cannot succeed.
- Clearer wording on uncharged no-speech rows: an ad whose audio turns out to be music-only or silent now says exactly that in
statusReason, in plain language. The same ads are recognised as before, and they are still never charged.
This actor now reads image ads, not just video ads — and that changes what a run costs.
- Image ads get their on-image copy read and delivered as a new
imageText field (headline, body, CTA and the full verbatim rawText). About 4 in 5 LinkedIn ads are static image ads, and until now every one of them came back as an empty metadata row. Non-English copy is read as written and never translated. The advertiser name always comes from LinkedIn's own metadata, never from reading a logo in the picture.
- What this does to your bill: a keyword run now charges for roughly ten times as many rows. An image-ad extraction costs the same as a video transcript (same event, same price) and never adds a long-video surcharge. Use
maxItems and the run's max total charge to size a run — both stop it honestly with a "what's left" message. Prefer the old behaviour? Turn Read the text on image ads off and the run is video-only, exactly as before.
- Image ads cost no extra LinkedIn requests. The creative image link is already in the free search result, so nothing extra is loaded to find it.
- An image ad with no readable text is never charged — a plain stock photo comes back as a free
ocr_no_text_found row with its metadata.
- New optional switch: read the on-screen text of silent video ads. About half of LinkedIn's video ads are silent or music-only and carry their whole message as on-screen type. Turned on, those ads' own frames are read and delivered as
onScreenText, charged like a transcript; silent ads that are just b-roll stay free. It is off by default, so a silent ad is still never charged unless you ask for this.
- The run summary now says what the search saw and did not read. It names every creative format found — document, carousel, article, message — instead of dropping ~9 in 10 of them without a word.
ctaText is now a visible column. It was always in the data and missing from the results table.
- Chained rows: most creative image links never expire, but a small share are short-signed and can go stale in an older dataset — those come back as an uncharged
image_expired row telling you to re-run your scraper or search here instead. Ad video links are unaffected; they still do not expire.
maxItems now counts image ads as well as video ads, and its label says so.
A video ad we could not read the source from is no longer reported as a non-video creative.
- A video ad whose page arrives without a usable video source is now an uncharged, retryable miss that asks you to re-run it. It used to be reported as a non-video creative — both wrong and final, since LinkedIn had already identified the ad as video.
- Those pages are now retried once on a fresh connection before the miss is reported, so a one-off bad page usually resolves inside the same run.
- Image, text and document creatives are unchanged: they still pass through as free metadata rows.
- The end-of-run summary now says how many ad pages LinkedIn did not serve in a readable form, rather than naming a verification page for every one of them.
- A typo in an input field name now gets a helpful pointer instead of sample rows. If you send a field this actor does not have —
companies instead of accountOwners, say — the run now returns one free row that names the field it did not recognise, names the one you meant, and shows the shape to send. Before, that run looked exactly like a run with no input at all and answered with the demo row, which made a typo look like it had worked.
- The prefilled example row in "Dataset items" is now always treated as an example. Pressing Run without replacing it returns the demo row, clearly labelled as the demo, instead of reporting the sample HubSpot ad as if you had supplied it. Leaving it in among your own pasted rows drops it and processes the rest. Nothing about it was ever charged.
- Rate-limit retries now reuse the video already in hand. When the speech service asks the actor to wait, the retry transcribes the bytes it already downloaded instead of fetching the file again — retries are faster and cheaper, and a link that stopped working mid-run can no longer be misreported as permanently dead when the real cause was a brief wait.
- A speech-service access problem now stops the run honestly. If the speech service refuses this actor's access, the remaining ads are no longer processed one by one toward calls that cannot succeed: the run stops cleanly, the status line says how many ads were left and that the problem is on our side, and none of them are charged.
- Interrupted runs now resume without double-charging. If the platform moves a run to another server mid-batch (or you resurrect a finished run), the actor now recognises every ad it already delivered: nothing is fetched, delivered, or charged a second time, and any charge the interruption cut short is settled honestly. Before, a moved or resurrected run could deliver duplicate rows and charge again for ads you already had.
- The
maxItems limit now counts the whole run, so an interrupted run can no longer process more ads than the limit promises after it resumes.
- A run's time ceiling now counts from when the run started, not from the latest restart, so an interrupted run can no longer live (and cost) longer than the ceiling promises.
- Long-video surcharge budgeting now also reserves for ads still being processed by parallel workers, so a batch of long videos near your maximum cost stops honestly instead of being cut off by the platform.
- Chaining from a mistyped or unreadable Dataset ID now returns one free row naming the ID and what to fix, instead of finishing quietly with an empty result.
- An Ad Library detail link is now always treated as one. A correctly formed
linkedin.com/ad-library/detail/<id> URL whose id happened to be short was turned away with
"this is a LinkedIn page, not an Ad Library detail page" — which was simply wrong about your
input. The ad is now looked up, and if LinkedIn has no such ad you get the honest uncharged row
naming the id instead of a complaint about the link.
- Rows for an ad that does not exist now name the id in question, so a long input list is easy
to audit.
- The no-input demo row now says it is a demo. It previously came back looking like an
ordinary result for a real advertiser.
sourceIndex is now unique across a whole run that mixes input types. Rows coming from a chained dataset used to restart their numbering at 0 and collide with rows from pasted video URLs, so joining results back to your input could line up with the wrong ad. Runs that use a chained dataset on its own are unchanged.
- A video download that ends early is now caught and retried instead of being transcribed. You can no longer receive — or be charged for — a transcript of half an ad; if every retry comes up short, the ad ships as an uncharged row that says so.
- A run whose maximum total charge covers exactly one transcript now returns that transcript instead of stopping with nothing.
- The budget reserve follows the new prices, so a batch of long videos stops cleanly at your maximum total charge with a "what's left" message instead of being cut off mid-run.
- Every row's
charged flag and chargeEvents now match what was actually billed for that row.
- Price cut. A delivered transcript now costs $0.020 down to $0.008 depending on your Apify plan tier — the volume price was $0.015. The free-plan price and the $0.005 long-video surcharge are unchanged, and you are still charged only when a transcript lands in your dataset.
- The pricing block in this page now shows the new figures.
- Added a plain note that this is an independent actor — unofficial, and not affiliated with or endorsed by LinkedIn.
- The directory of other steadyfetch actors now covers every family (ad creatives, trends and keywords, YouTube, Instagram, jobs, Amazon, and general media) and names each one exactly as it appears on the Store, so a link always lands where the name says. It now sits at the end of the page, just above support.
- The README now opens with an Output section — a sample results table, a screenshot of a real run's output, and the full JSON row — so you can see exactly what you get back before spending anything.
- Added a copy-and-paste block for AI agents and LLM clients: actor id, a complete input example, every output field, and the exact event prices.
- Added a directory of the other steadyfetch ad-intelligence actors (Facebook & Instagram, Google Ads, TikTok, Instagram Reels, Google Trends) with their free n8n templates.
- The example dataset linked from the README is now permanent, so it will not expire.
- Added a ready-made n8n workflow and a live example dataset to the README.
- Billing accuracy: runs with many long videos now stay within
maxTotalChargeUsd and stop honestly; surcharge minutes on each row always match what was charged; the same ad supplied in different forms (video URL, detail URL, or id) is delivered and charged once; improved music-only detection (still never charged).
- Reliability: stricter download timeouts and size safeguards; a search stopped by the time limit says so instead of reporting "no video ads found"; malformed characters in advertiser text can no longer fail a run; sturdier transcription timeouts.
- Initial release: transcripts + first-3-seconds hooks for LinkedIn Ad Library video ads — search by advertiser name or keyword (the actor finds the video ads for you), pass ad detail URLs / ad IDs / video URLs, or chain any LinkedIn Ad Library scraper run (dataset ID or pasted rows).
- Charged only on delivery: image and text creatives, silent videos, music-only audio, removed ads, and pages LinkedIn won't serve arrive as uncharged rows with the reason stated. The first 3 minutes of each video are included; longer videos add a small per-started-minute surcharge.
- Every row carries advertiser, headline, ad text, paying entity, and — where LinkedIn shows them — the ad's run dates and estimated impressions with the per-country split.