# LinkedIn Ads Transcript Scraper — Video Hooks & CTAs (`steadyfetch/linkedin-ads-transcript-scraper`) Actor

Charged only when a transcript is delivered — image, silent and blocked ads are free rows. No cookies, no login. LinkedIn Ad Library video ads → transcript, first-3s hook, advertiser metadata. Search by advertiser or keyword: it finds the video ads for you. No start fee.

- **URL**: https://apify.com/steadyfetch/linkedin-ads-transcript-scraper.md
- **Developed by:** [Steadyfetch Team](https://apify.com/steadyfetch) (community)
- **Categories:** AI, Social media, Videos
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.00 / 1,000 ad creative transcripts

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## LinkedIn Ad Library Transcript Scraper — video hooks, CTAs & ad copy

Turn [LinkedIn Ad Library](https://www.linkedin.com/ad-library/home) ads into **structured text** — video ads become full transcripts with the **first-3-seconds hook**, and image ads have their on-image copy read out — plus advertiser/creative metadata, in one JSON row per ad. Give it advertiser names or keywords (the actor searches the Ad Library for you), or chain it straight after any LinkedIn Ad Library scraper run. **You are charged only when text is delivered** — creatives with nothing readable, blocked pages and failures are never charged. No cookies, no LinkedIn login.

> **New: image ads are read too, and that changes your bill.** About 4 in 5 LinkedIn ads are static
> image ads, and each one whose copy is readable is now a charged result at the same price as a
> transcript. A keyword run that used to return a handful of video transcripts now returns roughly
> **ten times as many charged rows**. Use `maxItems` and the run's **max total charge** to set the
> size you want — or turn **Read the text on image ads** off to get the old video-only behaviour
> exactly as before.

| You give it | You get back |
|---|---|
| Advertiser names (e.g. `HubSpot`) | `transcript` — full speech-to-text, any length |
| …or keywords (e.g. `crm software`) | `hook3s` — what's said in the first 3 seconds |
| | `imageText` — the headline, body and CTA read off an image ad |
| …or ad URLs / video URLs | `advertiser`, `headline`, `adText`, `payingEntity`, `language`, `durationSeconds`, timestamped `segments` |
| …or an Ad Library scraper run's **dataset ID** | one JSON row per ad, misses clearly marked and never charged |

### Output

One JSON row per ad. Delivered rows carry the transcript (or the creative's text) and `charged: true`; anything that could not be delivered carries a `status` saying why, and `charged: false`. Real rows from the live example run below (long text trimmed with … for the page):

| status | charged | advertiser | headline | hook3s | transcript | language | durationSeconds |
|---|---|---|---|---|---|---|---|
| `transcribed` | `true` | Sparkon | HubSpot Elite Partner | Growth, AI, CRM Implementations, RevOps | We are Hubspot Elite Partner | If your revenue team is working harder than ever, but closing less, the problem isn't effort, it's the system. | If your revenue team is working harder than ever, but closing less, the problem isn't effort, it's the system. Too many manual tasks, too many disconnected tools… | English | 43.86 |
| `transcribed` | `true` | Sparkon | HubSpot Elite Partner | Growth, AI, CRM Implementations, RevOps | We are Hubspot Elite Partner | When your CRM becomes too complex, every team pays the price. | When your CRM becomes too complex, every team pays the price. We connect your financial systems, automate workflows, and give every team clear operational visibility… | English | 10.68 |
| `image_text_extracted` | `true` | HubSpot | *null* | *null* | *imageText:* "46% of marketers struggle with visual consistency. Get the free HubSpot & Canva Playbook" | *null* | *null* |
| `no_audio_stream` | `false` | HubSpot | *null* | *null* | *null* | *null* | *null* |

![LinkedIn ad transcripts output table — advertiser, headline, first-3s hook, transcript, language and the charged flag](https://raw.githubusercontent.com/steadyfetch/n8n-templates/master/assets/linkedin-ads-transcript-scraper-output-table.png)

Full row, as JSON:

```json
{
  "status": "transcribed",
  "charged": true,
  "advertiser": "Sparkon | HubSpot Elite Partner | Growth, AI, CRM Implementations, RevOps",
  "headline": "We are Hubspot Elite Partner",
  "adText": "Is your revenue team working harder, but closing less? ⚙️ …",
  "payingEntity": "Paid for by Triario LLC",
  "adId": "1508450294",
  "detailUrl": "https://www.linkedin.com/ad-library/detail/1508450294",
  "format": "SPONSORED_VIDEO",
  "availability": "Ran from Aug 17, 2026 to Aug 21, 2026",
  "impressions": "10k-20k",
  "impressionsByCountry": [{ "country": "Germany", "share": "70%" }, { "country": "Switzerland", "share": "22%" }],
  "hook3s": "If your revenue team is working harder than ever, but closing less,",
  "transcript": "If your revenue team is working harder than ever, but closing less, the problem isn't effort, it's the system...",
  "language": "English",
  "durationSeconds": 43.9,
  "segments": [{ "start": 0, "end": 7.7, "text": "If your revenue team is working harder than ever, but closing less, the problem isn't effort, it's the system." }],
  "chargeEvents": { "transcript": 1, "surchargeMinutes": 0 }
}
```

**[Browse the full live example dataset →](https://api.apify.com/v2/datasets/O0thSfah7LZve7qcM/items?clean=true\&format=json)** — real output from a verified run, including the free uncharged rows.

An image ad's row looks the same, with `imageText` in place of the transcript:

```json
{
  "status": "image_text_extracted",
  "charged": true,
  "advertiser": "HubSpot",
  "format": "SPONSORED_STATUS_UPDATE",
  "adId": "1478297483",
  "detailUrl": "https://www.linkedin.com/ad-library/detail/1478297483",
  "imageUrl": "https://media.licdn.com/dms/image/v2/…",
  "imageText": {
    "headline": null,
    "body": null,
    "cta": null,
    "displayUrl": null,
    "rawText": "46% of marketers struggle with visual consistency. Get the free HubSpot & Canva Playbook HubSpot | Canva"
  },
  "chargeEvents": { "transcript": 1, "surchargeMinutes": 0 }
}
```

`advertiser` always comes from LinkedIn's own metadata, never from reading a logo in the picture.

Every field is always present (explicit `null` over silent omission). Non-delivered rows carry `status` + `statusReason` instead — `ocr_no_text_found` (a genuinely text-free creative, e.g. a plain stock photo), `image_expired` (most creative image links never expire, but a small share — 2 of 76 measured — are short-signed and can go stale in a chained dataset; re-run your scraper for fresh URLs, or search here so the link and the picture are read in the same run), `image_skipped` (you turned image reading off), `non_video_skipped` (document, carousel, article, message and text-only creatives pass through with their metadata), `no_audio_stream` (a genuinely silent video), `no_speech` (music-only audio), `no_onscreen_text`, `not_found`, `blocked_by_challenge`, `unavailable_expired`, `no_videos_found`, `search_unavailable`, `asr_unavailable` (the speech and text-reading service refused this actor's access mid-run — every ad left in the queue comes back as its own uncharged, retryable row instead of disappearing; re-run later), `no_creative_found`, `input_error`, or `failed_*` (also listed in the run's `ERRORS` record). None of them are charged. `availability` and `impressions` are filled when LinkedIn shows them (EU-targeted ads) and `null` otherwise.

### For AI agents & LLMs — copy this block

```
Actor:   steadyfetch/linkedin-ads-transcript-scraper  (Apify Store)
Does:    LinkedIn Ad Library video ads -> full transcript + first-3-seconds hook +
         advertiser metadata. One JSON row per ad. No LinkedIn login or cookies.
Run:     POST https://api.apify.com/v2/acts/steadyfetch~linkedin-ads-transcript-scraper/run-sync-get-dataset-items?token=APIFY_TOKEN
Input    (any ONE of the first four fields is enough):
  {
    "accountOwners": ["HubSpot"],          // advertiser names; the actor finds their video ads
    "keywords": ["crm software"],          // or search the Ad Library by topic
    "videoUrls": ["https://www.linkedin.com/ad-library/detail/1508450294"],
    "datasetId": "<dataset id of any LinkedIn Ad Library scraper run>",
    "includeImageText": true,              // default ON: read image ads' copy (charged like a transcript)
    "includeOnScreenText": false,          // default OFF: read silent video ads' on-screen text
    "includeNonVideo": false,              // optional: free rows for document/carousel/article/text ads
    "maxItems": 1000                       // optional cap — counts video AND image ads
  }
Output   one row per ad: status, charged, advertiser, headline, adText, ctaText, payingEntity,
         adId, detailUrl, format, availability, impressions, impressionsByCountry,
         hook3s, transcript, language, durationSeconds, segments[],
         imageUrl, imageText{headline,body,cta,displayUrl,rawText}, onScreenText{...}
Pricing  pay per event, platform usage INCLUDED, no start fee:
  video-ad-transcript   $0.020 -> $0.008 per delivered transcript OR image-ad text extraction
                        (falls with your Apify plan tier; an image never adds a surcharge)
  long-video-surcharge  $0.005 per started minute past the first 3 minutes
  Charged only on delivery — creatives with no readable text, blocked pages and failures cost $0.
  ~4 in 5 LinkedIn ads are image ads, so a keyword run charges for ~10x more rows than video alone.
  Cap any run with maxTotalChargeUsd (minimum $0.05).
MCP:     reachable through Apify's MCP server; ask for "linkedin ad transcripts".
```

### Why this LinkedIn Ad Library transcript scraper?

- **It reads the whole library, not just the 7% that is video.** The Ad Library has no format filter. This actor reads the format off each search result first, transcribes the video ads, and reads the on-image copy of the image ads — so a keyword search comes back with the ad copy of ~95% of what it saw instead of ~7%.
- **Image ads cost no extra page loads.** The creative image URL is already in the free search result, so reading image ads adds zero requests to LinkedIn.
- **Charged only on delivery.** Text either lands in your dataset or the row is not charged. Text-free stock photo → uncharged row that says so. Silent creative → uncharged row that says so. Blocked page → uncharged row that says so. No "it ran and charged me but returned nothing."
- **The run tells you what it saw.** The status line names every format the search returned, including the ones this actor does not read — nothing is dropped silently.
- **Old datasets still work.** LinkedIn ad video URLs are long-lived — unlike other ad platforms' CDN links, they don't expire in hours or days. A dataset you scraped weeks ago transcribes fine today.
- **No cookies, no login.** Runs entirely on LinkedIn's public Ad Library — nothing to paste, no account at risk.
- **Any video length.** Long-form B2B creatives transcribe fine — videos past 3 minutes add a small per-started-minute surcharge instead of failing.
- **Hook as data.** The first-3s hook is the line media buyers study; you get it as its own field, plus full segment timestamps.
- **Works with any scraper's output.** The dataset input deep-scans your rows for LinkedIn ad video links and ad detail links — no field mapping, no glue code.
- **Ad metadata included.** Advertiser, headline, ad text, paying entity, run dates, and — where LinkedIn shows them (EU-targeted ads) — estimated impressions with the per-country split, on every row.

This actor may fail when the platform changes things — failed items are never charged.

### How to transcribe LinkedIn video ads (no code)

1. Type an advertiser name (e.g. `HubSpot`) into **Advertiser names** — or a topic into **Keywords**.
2. Click **Start**. The actor searches the [Ad Library](https://www.linkedin.com/ad-library/home), picks out the video ads, and transcribes each one.
3. Each ad comes back as one JSON row: a transcript + hook for video ads, the on-image copy for image ads, plus advertiser metadata.
4. Export as JSON/CSV, or read it via API.

Already scraping the Ad Library? Paste your run's **dataset ID** (or use Apify's *Connect Actor* integration) and this actor transcribes the video ads in it.

### How much does it cost to transcribe LinkedIn ads?

**One result = one ad's text payload** — a video ad's transcript + hook + segments, or an image ad's on-image copy. Both cost the same event. The first 3 minutes of each video are included; longer videos add a small per-started-minute surcharge, and an image ad never does. No start fee, no subscription, no third-party API key needed.

| Job | Approx. cost |
|---|---|
| 50 competitor ads (video or image) | ≈ $1.00 |
| 500 ads (a serious creative teardown) | ≈ $10 |
| Apify free plan ($5 credit) | ≈ **250 ad creatives** |

**Sizing a keyword run:** roughly 4 in 5 LinkedIn ads are image ads and about 3 in 4 of those carry
readable copy, so one page of 24 search results yields on the order of 15 charged rows. Set
`maxItems` to the number of ads you actually want, and cap the run with **max total charge** —
both stop the run honestly with a "what's left" message rather than overspending.

Platform usage (compute + transfer) is **included in the event price** — the price you see is the whole price. Searching, unreadable creatives, and failed fetches carry no result fee.

### Works with — LinkedIn Ad Library scrapers you can chain from

The dataset input reads the **values** in each row (any `dms.licdn.com` video link or `ad-library/detail/…` link), not fixed field names — so it works with any Ad Library scraper, including:

| Scraper | Chain by |
|---|---|
| [silva95gustavo/linkedin-ad-library-scraper](https://apify.com/silva95gustavo/linkedin-ad-library-scraper) | dataset ID or pasted rows (`videoUrl` / detail links) |
| [dz\_omar/linkedin-ads-scraper](https://apify.com/dz_omar/linkedin-ads-scraper) | dataset ID or pasted rows (`detailPageUrl`, `detail.videoUrls`) |
| [memo23/linkedin-ads-scraper](https://apify.com/memo23/linkedin-ads-scraper) | dataset ID or pasted rows (`adLibraryUrl` + `format: "VIDEO"`) |
| [ivanvs/linkedin-ad-library-scraper](https://apify.com/ivanvs/linkedin-ad-library-scraper) | dataset ID or pasted rows (`url` detail links) |
| [automation-lab/linkedin-ad-library-scraper](https://apify.com/automation-lab/linkedin-ad-library-scraper) | dataset ID or pasted rows (`detailUrl`, `mediaUrl`) |

**How to chain:** run the scraper → copy the run's **dataset ID** into this actor's *Dataset ID* field (or use Apify's *Connect Actor* integration) → Start. Video rows are transcribed; image rows have their on-image copy read (turn *Read the text on image ads* off to pass them through free instead); rows with no recognizable creative come back as uncharged `no_creative_found`. One caveat for chained rows: most creative **image** links never expire, but a small share are short-signed and can go stale in an older dataset — those rows come back as uncharged `image_expired`, and searching by advertiser/keyword here avoids the problem entirely. You can also skip the other scraper entirely — this actor searches the Ad Library itself.

### Use it via API, MCP, and integrations

- **API**: standard Apify run API — `POST .../acts/steadyfetch~linkedin-ads-transcript-scraper/runs` with `{ "accountOwners": ["HubSpot"] }`. Python/Node clients work as with any actor.
- **MCP**: works from Claude, Cursor, and any MCP client through Apify's MCP server — ask for "linkedin ad transcripts" with an advertiser name or dataset ID.
- **n8n**: a free ready-made template, no community nodes needed — **[LinkedIn Ad Library transcripts →](https://github.com/steadyfetch/n8n-templates#linkedin-ad-library-transcripts--one-advertiser--hooks--transcripts)** (one advertiser → hooks & transcripts → spreadsheet-shaped rows, 3-minute setup).
- **Make / Zapier**: call it as a regular Apify actor step right after your scraper node, or run it standalone with advertiser names.

### FAQ

**Where do the ads come from?** LinkedIn's own [Ad Library](https://www.linkedin.com/ad-library/home) — the public transparency surface LinkedIn publishes so anyone can see who runs which ads. No login or cookies are used, ever.

**Why did some ads come back `non_video_skipped`?** Document, carousel, article, message and text-only creatives are not read — there is no video to transcribe and no single ad image to read. They pass through uncharged with their advertiser/CTA metadata (turn on *Include the remaining formats* to get one uncharged metadata row for each one found in search).

**How accurate is the image-ad text?** It is read by a vision model from the ad's own creative, verbatim and untranslated, and delivered as `imageText.rawText` with the headline / body / CTA split out where the model can tell them apart. Non-English copy works. If nothing readable comes back, the row is `ocr_no_text_found` and free — a plain product photo with no copy on it is never sold to you as a result.

**Can I get the on-screen text of silent video ads?** Yes — turn on *Read on-screen text on silent video ads*. About half of LinkedIn's video ads are silent or music-only, and most of them carry their whole message as on-screen type. With the switch on, those ads' frames are read and delivered as `onScreenText`, charged like a transcript; silent ads with no real copy (plain b-roll) stay free. With the switch off — the default — a silent ad is never charged, exactly as before.

**A search returned `no_videos_found`?** The advertiser or keyword had no video ads and no image ads this actor could read — only document, carousel, article or message creatives, or nothing at all. The row tells you how many creatives were seen and of which formats, so you can widen the query. When you search several advertisers/keywords at once, each one that turns up nothing readable gets its own uncharged row naming it, so a misspelled advertiser never disappears silently. Nothing is charged.

**Silent video ads?** Some B2B creatives ship with no audio track at all (text-overlay videos). We detect that and return an honest, uncharged `no_audio_stream` row instead of an empty transcript — or, with *Read on-screen text on silent video ads* turned on, we read the type off the video's own frames.

**Music-only ads?** Speech-recognition models hallucinate filler on music. We detect that and return an honest, uncharged `no_speech` row instead of selling you a fake transcript.

**What is `blocked_by_challenge` / `search_unavailable`?** LinkedIn occasionally serves a verification page instead of an ad page, or the Ad Library search returns nothing for a while. The actor retries, and if it still can't get through you get an uncharged row that says so — re-running a few minutes later usually picks those ads up.

**Typos in bare ad IDs?** A mistyped numeric ad ID is indistinguishable from a real one, so it surfaces as an honest, uncharged `not_found` row (LinkedIn answers "can't load this ad") rather than an input error.

**Languages?** Whisper-class multilingual ASR — German, French, Spanish, Arabic, Japanese, and ~90 more transcribe out of the box; the detected `language` ships on every row.

**Is it legal to transcribe LinkedIn ads?** The Ad Library is public by design (ad transparency, required by regulations like the EU DSA). This actor reads only that public surface, logged out. As always, how you use the data is on you.

**Is this an official LinkedIn product?** No. This is an independent actor from steadyfetch — unofficial, and not affiliated with, endorsed by, or sponsored by LinkedIn Corporation or Microsoft. "LinkedIn" is a trademark of its respective owner, used here only to name the public Ad Library surface this actor reads.

### Steadyfetch ad-intelligence suite

One actor per ad surface, one job each, the same contract everywhere: **all-inclusive pay-per-event,
no start fee, charged only on delivery** — and the same row shape, so a workflow built for one platform
ports to the next.

**Ad creatives → transcripts (video)**

| Ad surface | Actor | Free n8n template |
|---|---|---|
| Facebook & Instagram Ad Library | [Facebook Ad Library Transcript Scraper — Video Hooks & CTAs](https://apify.com/steadyfetch/facebook-ads-transcript-scraper) | [Facebook ad transcripts →](https://github.com/steadyfetch/n8n-templates#facebook-ad-transcripts--scrape-competitor-ads--hooks-ctas--transcripts) · [Competitor ad teardown →](https://github.com/steadyfetch/n8n-templates#competitor-ad-teardown--one-competitor-pagekeyword--hooks-ctas--transcripts-one-row-per-ad) |
| Google Ads Transparency Center | [Google Ads Video Transcripts & Hooks (Ads Transparency Center)](https://apify.com/steadyfetch/google-ads-video-transcript-scraper) | [Google Ads video transcripts →](https://github.com/steadyfetch/n8n-templates#google-ads-video-transcripts--one-advertiserdomain--hooks--transcripts) |
| TikTok Creative Center Top Ads | [TikTok Ad Transcripts & Hooks (Creative Center Top Ads)](https://apify.com/steadyfetch/tiktok-ads-transcript-scraper) | [TikTok Top Ads transcripts →](https://github.com/steadyfetch/n8n-templates#tiktok-top-ads-transcripts--creative-center-industryregion--hooks--transcripts) |
| **LinkedIn Ad Library** | **this actor** | [LinkedIn Ad Library transcripts →](https://github.com/steadyfetch/n8n-templates#linkedin-ad-library-transcripts--one-advertiser--hooks--transcripts) |
| Instagram Reels (organic posts) | [Instagram Reels to Text · @handle](https://apify.com/steadyfetch/instagram-reel-transcript-scraper) | [Instagram Reel transcripts →](https://github.com/steadyfetch/n8n-templates#instagram-reel-transcripts--scrape-a-profiles-reels--hooks--transcripts) |

**Ad creatives → text (image & text ads, read by OCR)**

| Ad surface | Actor |
|---|---|
| Google Ads Transparency Center | [Google Ads Creative Text & OCR (Transparency Center)](https://apify.com/steadyfetch/google-ads-creative-text-scraper) |

All templates in one place: **[github.com/steadyfetch/n8n-templates](https://github.com/steadyfetch/n8n-templates)** — free, no community nodes needed.

**The rest of the steadyfetch shelf** — same contract everywhere: all-inclusive pay per event,
no start fee, charged only on delivery.

| Family | Actors |
|---|---|
| **Ad creative intelligence** | [Facebook](https://apify.com/steadyfetch/facebook-ads-transcript-scraper) · [Google Ads video](https://apify.com/steadyfetch/google-ads-video-transcript-scraper) · [TikTok](https://apify.com/steadyfetch/tiktok-ads-transcript-scraper) · [LinkedIn](https://apify.com/steadyfetch/linkedin-ads-transcript-scraper) · [Google Ads text & OCR](https://apify.com/steadyfetch/google-ads-creative-text-scraper) |
| Trends & keywords | [Google Trends](https://apify.com/steadyfetch/google-trends-scraper) · Trends Now · Breakout keywords · Autocomplete keywords · Keyword volume & CPC · Social trends |
| YouTube transcripts | YouTube videos · YouTube channels |
| Instagram | [Reel transcripts](https://apify.com/steadyfetch/instagram-reel-transcript-scraper) · Profile posts |
| Jobs | Indeed · Career sites by domain · Glassdoor · Multi-board |
| Amazon | Products · Search · Bestsellers · Sellers |
| Any media file | Speech to Text · any link or file |

Unlinked names are publishing shortly on the same account — search **steadyfetch** on Apify Store.

### Feedback & support

Found an issue? Open it on the **Issues tab** — we respond within one business day. Feature requests welcome.

# Actor input Schema

## `accountOwners` (type: `array`):

Company names as they appear in the Ad Library (e.g. "Salesforce", "HubSpot"). Each is searched with the Ad Library's own advertiser search.

## `keywords` (type: `array`):

Free-text Ad Library searches (e.g. "crm software", "recruiting"). Finds video ads across many advertisers in a niche.

## `videoUrls` (type: `array`):

Ad Library detail URLs (linkedin.com/ad-library/detail/…), numeric ad IDs, or direct video URLs (dms.licdn.com/playlist/vid/…) from any LinkedIn Ad Library scraper result.

## `datasetId` (type: `string`):

The default dataset ID of a finished LinkedIn Ad Library scraper run. With Apify's 'Connect actor' integration this is filled automatically — the cleanest way to chain.

## `datasetItems` (type: `array`):

Paste rows from your Ad Library scraper run. The actor deep-scans each row for video URLs, ad detail links, and metadata — works with any scraper's output shape. Non-video rows come back as uncharged metadata rows. The prefilled demo row shows the honesty contract: it returns one uncharged row — replace it with your own rows, or use the search fields above.

## `includeImageText` (type: `boolean`):

ON (default): image ads get their on-image copy read and delivered as `imageText` — each delivered extraction is charged like a video transcript (same event, same price; never a long-video surcharge). Image ads with no readable text are always free. Most LinkedIn ads are image ads, so a keyword run charges for many more rows with this on than a video-only run did — set `maxItems` and the run's max total charge to match. OFF: image ads pass through free with their metadata, as before.

## `includeOnScreenText` (type: `boolean`):

OFF (default): a video ad with no speech is never charged. ON: silent and music-only video ads have their on-screen text read from the video's own frames and delivered as `onScreenText`, charged like a transcript. Ads with no readable on-screen text stay free either way. About half of LinkedIn's video ads are silent.

## `includeNonVideo` (type: `boolean`):

When searching by advertiser/keyword, also output one uncharged metadata row (advertiser, format, ad link) for each creative this actor does not read — document, carousel, article, message and text-only ads. Off by default.

## `maxItems` (type: `integer`):

Safety cap on how many ads to process in one run (every attempted video ad and image ad counts toward it, including uncharged misses; the formats above never do).

## Actor input object example

```json
{
  "datasetItems": [
    {
      "_demo": "Replace me with rows from your Ad Library scraper run (or use accountOwners / keywords / videoUrls / datasetId). This demo row returns one uncharged row showing the per-row status contract.",
      "advertiser": "HubSpot",
      "format": "SINGLE_IMAGE",
      "headline": "Get The Free Brand Consistency Guide From HubSpot & Canva",
      "body": "Brand consistency drives revenue growth for 68% of organizations."
    }
  ],
  "includeImageText": true,
  "includeOnScreenText": false,
  "includeNonVideo": false,
  "maxItems": 1000
}
```

# Actor output Schema

## `transcripts` (type: `string`):

One row per ad: transcript, first-3s hook, advertiser, headline, format, and a status (transcribed / non\_video\_skipped / no\_speech / not\_found / …). Only 'transcribed' rows are charged.

## `summary` (type: `string`):

Delivered count, uncharged metadata rows, uncharged misses, failures, and the honest status message.

## `errors` (type: `string`):

Present only when fetches/ASR failed after all retries: ad ID and reason.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "datasetItems": [
        {
            "_demo": "Replace me with rows from your Ad Library scraper run (or use accountOwners / keywords / videoUrls / datasetId). This demo row returns one uncharged row showing the per-row status contract.",
            "advertiser": "HubSpot",
            "format": "SINGLE_IMAGE",
            "headline": "Get The Free Brand Consistency Guide From HubSpot & Canva",
            "body": "Brand consistency drives revenue growth for 68% of organizations."
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadyfetch/linkedin-ads-transcript-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "datasetItems": [{
            "_demo": "Replace me with rows from your Ad Library scraper run (or use accountOwners / keywords / videoUrls / datasetId). This demo row returns one uncharged row showing the per-row status contract.",
            "advertiser": "HubSpot",
            "format": "SINGLE_IMAGE",
            "headline": "Get The Free Brand Consistency Guide From HubSpot & Canva",
            "body": "Brand consistency drives revenue growth for 68% of organizations.",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("steadyfetch/linkedin-ads-transcript-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "datasetItems": [
    {
      "_demo": "Replace me with rows from your Ad Library scraper run (or use accountOwners / keywords / videoUrls / datasetId). This demo row returns one uncharged row showing the per-row status contract.",
      "advertiser": "HubSpot",
      "format": "SINGLE_IMAGE",
      "headline": "Get The Free Brand Consistency Guide From HubSpot & Canva",
      "body": "Brand consistency drives revenue growth for 68% of organizations."
    }
  ]
}' |
apify call steadyfetch/linkedin-ads-transcript-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steadyfetch/linkedin-ads-transcript-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/8pbFberNFHs5u2PAJ/builds/KFAilkN7a8sRhhyH0/openapi.json
