# TikTok Transcript Scraper + Facebook Reels Transcript (`tactful_anvil/short-video-transcript`) Actor

TikTok transcript & Facebook Reels transcript scraper (+ Instagram Reels transcript): any username, profile or video link → speech to text with hook, timestamps, SRT/VTT, language, views & likes. Facebook video transcript, TikTok to text. Whisper, 99 languages. Pay only for transcribed videos.

- **URL**: https://apify.com/tactful_anvil/short-video-transcript.md
- **Developed by:** [Mr Zack](https://apify.com/tactful_anvil) (community)
- **Categories:** Videos, Social media, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.00 / 1,000 transcripts

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Instagram Reels, TikTok & Facebook Transcript by Username — Video to Text

Type a **username** — `@zachking`, `nasa`, or a profile link — and get the **transcript of that creator's newest Instagram Reels or TikToks**: what is actually said, the **hook** (first line), timestamps, language, views and likes. Or paste single **TikTok, Instagram Reel and Facebook Reel links**. One Actor for all three platforms, no login, no cookies.

| Profile | Hook (first ~3 s) | Transcript (start) | Views |
| --- | --- | --- | --- |
| `@nasa` (Instagram) | *Think about hundreds of square miles where we have different assets.* | Think about hundreds of square miles where we have different assets. Definitely mobility systems… | 3.6M |
| `@nasa` (TikTok) | *NASA is accelerating Artemis.* | NASA is accelerating Artemis. In this week, we shared some major updates on our path back to the moon… | 163K |
| `@mkbhd` (TikTok) | *Alright, so the memory price hikes have finally hit Apple and they have really hit.* | Alright, so the memory price hikes have finally hit Apple and they have really hit. So already on Apple.com… | 1.2M |

*(Real output of this Actor, 25 Oct 2026.)*

```json
{ "handles": ["@nasa", "tiktok:@nasa", "tiktok:@mkbhd"], "maxVideosPerProfile": 10 }
```

Speech recognition is **OpenAI Whisper** (99 languages, automatic language detection), running inside the Actor — no third-party transcription API, no extra keys. **You only pay for videos that were transcribed** — music-only clips, private profiles, deleted videos, login walls and duplicates come back as a status row and are **free**.

- **Instagram Reels transcript by username** — newest (or most viewed) Reels of any public profile, **up to 500 per profile**, no login.
- **TikTok profile transcript** — newest (or most viewed) videos of any public TikTok account, up to 500 per profile.
- **Facebook Reel transcript** — public Facebook Reels and videos, including `fb.watch` short links.
- **Single links** — TikTok, Instagram Reels, Facebook Reels / videos, short links (`vm.tiktok.com`, `vt.tiktok.com`, `fb.watch`).
- **Hook line** — the opening sentence of every video as its own column, with `hookStartSeconds` / `hookEndSeconds`, plus speaking pace (`wordsPerMinute`).
- **Filters** — only posts newer than a date or "7 days", skip pinned videos, minimum views, newest vs most viewed. Filtered videos are never downloaded or charged.
- **Outliers** — `viewsVsCreatorMedian` and `isOutlier` show which videos beat the creator's usual views.
- **Timestamps, SRT, WebVTT, per-word timing** — and `chunks` of N words for RAG / embeddings.
- **English translation** — `translationEn` for non-English videos, by Whisper itself, same price.
- **Top TikTok comments** — most-liked comments (pinned first) next to the transcript.
- **Chain from any scraper** — give a `datasetId` from an Instagram / TikTok / Facebook scraper run and every video in it is transcribed.
- **Watchlists** — named monitoring jobs; every row says `isNew` and `firstSeenAt`, and *Only new videos* skips what you already have.
- **Honest billing** — a `charged` column on every row, so your bill reconciles to the row.

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

```
Actor:   tactful_anvil/short-video-transcript  (Apify Store)
Does:    Instagram / TikTok username -> that creator's newest videos -> spoken transcript,
         hook (opening line), language, timestamped segments, optional SRT, views/likes/comments.
         Also single TikTok, Instagram Reel and Facebook Reel/video links. No login, no cookies.
Run:     POST https://api.apify.com/v2/acts/tactful_anvil~short-video-transcript/run-sync-get-dataset-items?token=APIFY_TOKEN
         (sync waits up to 5 minutes; for big batches use /runs and read the dataset afterwards)
Input    (every field optional; give handles and/or urls):
  {
    "handles": ["@nasa", "tiktok:@mkbhd", "https://www.instagram.com/zachking/"],
                                  // @user / user / profile URL; prefix tiktok: or ig: picks the platform per line
    "profilePlatform": "instagram",   // platform for plain usernames: instagram | tiktok | both
    "maxVideosPerProfile": 10,    // videos per profile after filters, up to 500 (Instagram + TikTok)
    "onlyPostsNewerThan": "",     // "2026-10-01" or "7 days" / "24 hours" / "2 weeks" / "3 months"
    "skipPinned": false,          // leave out pinned videos
    "minViews": 0,                // only videos with at least this many views
    "sortBy": "newest",           // newest | most_viewed (top by views among ~3x the videos listed)
    "urls": ["https://www.tiktok.com/@nasa/video/7699974130153590029",
             "https://www.instagram.com/reel/DeuH0dDFGcg/",
             "https://www.facebook.com/reel/1795689255099117"],
    "datasetId": "",              // dataset of any Instagram / TikTok / Facebook scraper run -> transcribe its videos
    "datasetItems": [],           // or paste scraper rows directly (any shape with a url / webVideoUrl / shortCode)
    "onlyNew": false,             // true: skip videos an earlier run of yours already transcribed
    "watchlistId": "",            // named memory per monitoring job; rows get isNew + firstSeenAt
    "language": "",               // ISO 639-1 like "en", "es", "id"; empty = auto-detect per video
    "model": "base",              // base (recommended) | tiny (fastest, clear English)
    "preferNativeCaptions": true, // use captions the platform already publishes (TikTok) when present
    "includeSegments": true,      // segments [{start,end,text}] in seconds
    "includeSrt": false,          // add an SRT subtitle string
    "includeVtt": false,          // add a WebVTT subtitle string
    "wordTimestamps": false,      // add words[{start,end,word}] inside every segment
    "chunkWords": 0,              // >0: add chunks[{index,start,end,text,wordCount}] of ~N words (RAG)
    "translateToEnglish": false,  // add translationEn (Whisper speech translation), same price
    "maxComments": 0,             // >0: add topComments (TikTok only; IG/FB need a login)
    "maxVideos": 100,             // hard cap on unique videos per run (links + all profiles), up to 5000
    "maxDurationSec": 180         // transcribe at most this many seconds of each video (10-600)
  }
  Empty input {} -> a FREE 2-Reel sample from Instagram @nasa (nothing charged but the start fee).
Output   one row per video (or per profile that could not be listed):
         url, platform, profile, status, charged, error, videoId, author, authorId, caption,
         durationSec, uploadedAt, viewCount, likeCount, commentCount, shareCount, saveCount,
         musicTitle, musicArtist, thumbnailUrl, ownerFullName, isVerified, followerCount,
         isPinned, isPaidPartnership, taggedUsers[], coauthors[], hashtags[], mentions[],
         hook, hookStartSeconds, hookEndSeconds, hasSpeech, transcript, wordCount,
         wordsPerMinute, language, languageProbability, transcriptSource (whisper |
         native_captions), model, speechSeconds, truncated, segments[], processedAt,
         creatorMedianViews, viewsVsCreatorMedian, isOutlier
         + when asked: srt, vtt, chunks[], translationEn, topComments[], isNew, firstSeenAt.
         Run receipt: key-value store record SUMMARY (counts per status, charged, filtered,
         per-profile listed/selected) — reconciles with the per-row `charged` column.
         status "ok" = transcribed and charged. Any other status is FREE and `error` says why:
         no_speech, no_videos, caption_only, blocked, network_error, private, login_required,
         not_found, no_audio, geo_restricted, download_failed, transcribe_failed,
         budget_limit, timeout, invalid, unsupported, youtube.
         The run always ends SUCCEEDED; its status message sums up the rows per status.
Pricing  pay per event: $0.008 per transcribed video (up to 3 min of audio) + start fee $0.001 per GB
         of run memory ($0.002 with the default 2 GB).
         Platform usage is included. Respects "Maximum cost per run": videos that would exceed it
         come back as budget_limit rows and are not transcribed or charged.
Not for  YouTube (returns status youtube, free), private / followers-only / age-restricted videos.
```

**MCP in one line:** add `https://mcp.apify.com/?tools=tactful_anvil/short-video-transcript` as an MCP server in Claude, Cursor, VS Code or any MCP client (sign in with your Apify account or pass your token). The Actor then shows up as one tool your agent can call: *"Transcribe the 10 newest Reels of @garyvee and list the hooks that start with a question."*

### What does this Actor do?

It turns short-form video into text, at scale, from three platforms:

1. **Lists profiles.** For every username you give, it fetches that creator's public videos — Instagram Reels through Instagram's public Reels tab (12 per page, paged up to 500), TikTok videos through the public profile page. Pinned videos are sorted back into date order (or skipped), then your filters pick which ones to transcribe: newer than a date, minimum views, newest or most viewed.
2. **Gets the audio.** For each video it downloads only the smallest file that carries the sound (Instagram profile listings already include the video file, so no extra page visit is needed).
3. **Uses existing captions when they exist.** Many TikToks ship captions published by the creator or by TikTok. When **Use the platform's own captions** is on, those are returned directly — faster, and exactly what TikTok shows.
4. **Transcribes everything else with Whisper.** The audio is converted to 16 kHz mono and transcribed by faster-whisper (OpenAI Whisper weights, int8) inside the Actor's own container. Voice activity detection skips music and silence, which also tells the Actor when a clip has *no speech at all*.
5. **Writes one clean row per video** — transcript, hook, segments, optional SRT, language, word count, speech seconds, plus the post's caption, views, likes, comments, shares, sound title, upload date and thumbnail.
6. **Bills only real transcripts.** A clip that is only music, a deleted link or a login wall becomes a free status row with a plain-language reason.

Two videos are processed at the same time (one downloading while the other is being transcribed), and every platform request is spaced out politely.

### Who is this for?

- **Content repurposers & clippers** — turn viral short videos into scripts, hooks, captions, blog posts, newsletters and threads.
- **Marketers & agencies** — study what top creators and competitors actually *say* in their Reels and TikToks, not just what they write in the caption.
- **UGC & ad researchers** — collect ad scripts and opening hooks from trending videos into a swipe file.
- **Social media managers** — subtitle your own videos (SRT) and keep a searchable archive of everything your brand has said.
- **Researchers & analysts** — speech-level datasets from public short-form video, ready for LLMs, sentiment, topic modelling or claim checking.
- **Brand & reputation monitoring** — watch what creators say about a product, a launch or a category, every day.
- **AI agents (MCP)** — "transcribe these 20 TikToks and summarize the hooks" is one tool call.

### Input

You can mix every kind of input in one run. All fields are optional; with nothing at all you get a free sample.

| Field | Type | Default | What it does |
| --- | --- | --- | --- |
| `handles` | list of strings | — | Profiles to list: `@zachking`, `zachking`, `https://www.instagram.com/zachking/`, `https://www.tiktok.com/@zachking`. Prefix `tiktok:` or `ig:` (`tiktok:@nasa`, `ig:nasa`) to pick the platform per line. |
| `profilePlatform` | `instagram` | `tiktok` | `both` | `instagram` | Where plain usernames are looked up. `both` lists the same username on Instagram **and** TikTok. Profile links always use their own platform. |
| `maxVideosPerProfile` | integer 1–500 | `10` | Videos to transcribe per profile, after the filters. |
| `onlyPostsNewerThan` | string | empty | `2026-10-01`, `7 days`, `24 hours`, `2 weeks`, `3 months`, `1 year`. Older videos are skipped before download. For Instagram the listing stops paging as soon as a whole page is older. |
| `skipPinned` | boolean | `false` | Leave out videos pinned to the top of the profile. |
| `minViews` | integer | `0` | Only videos with at least this many views (videos with hidden views are kept). |
| `sortBy` | `newest` | `most_viewed` | `newest` | `most_viewed` lists about 3× **Videos per profile** (at least 36) and transcribes the most viewed of them. |
| `urls` | list of strings | — | Single videos: TikTok, Instagram Reels (`/reel/…`, `/p/…`), Facebook Reels and videos, short links. Profile links pasted here are listed like `handles`. Tracking parameters are removed and duplicates skipped. |
| `datasetId` | string | — | Dataset ID of another Actor run (Instagram / TikTok / Facebook scraper). Post links are read from `url`, `webVideoUrl`, `postUrl`, `shortCode` and similar fields; Instagram rows with a `videoUrl` file are transcribed straight from that file. Photo posts are skipped. |
| `datasetItems` | array | — | The same, with rows pasted directly. |
| `onlyNew` | boolean | `false` | Skip videos an earlier run of yours already finished (transcribed, or found to have no speech / no audio). Remembered in a key-value store in your own Apify account (`short-video-transcript-seen`, or your watchlist's store). |
| `watchlistId` | string | — | A named memory per monitoring job (`competitors`, `client-acme`) → store `svt-watch-<name>`. Rows get `isNew` and `firstSeenAt`. |
| `language` | string | empty | Spoken language as an ISO 639-1 code (`en`, `es`, `pt`, `id`, `de`, `fr`, `hi`, `ar`, `ja`, …). Empty = detected separately for every video. Setting it helps with very short clips and mixed-language creators. |
| `model` | `base` | `tiny` | `base` | `base` = good accuracy, recommended. `tiny` = fastest, fine for clear English speech. Same price. |
| `preferNativeCaptions` | boolean | `true` | Return captions the platform already publishes (mostly TikTok) instead of running speech recognition. Turn off to always transcribe the audio. |
| `includeSegments` | boolean | `true` | Add `segments`: `[{start, end, text}]` in seconds. |
| `includeSrt` | boolean | `false` | Add `srt`: a ready-to-save SubRip subtitle string. |
| `includeVtt` | boolean | `false` | Add `vtt`: a WebVTT subtitle string (HTML5 video, YouTube upload, most editors). |
| `wordTimestamps` | boolean | `false` | Add `words` \[{start, end, word}] inside every segment. Always uses Whisper (not platform captions). |
| `chunkWords` | integer 0–2000 | `0` | Add `chunks`: the transcript cut into pieces of about N words with start/end seconds, for embeddings / RAG. |
| `translateToEnglish` | boolean | `false` | Add `translationEn`: the speech translated to English by Whisper (non-English videos; English videos get their transcript). Same price. |
| `maxComments` | integer 0–50 | `0` | Add `topComments` for every transcribed TikTok: most liked first, pinned on top. Instagram and Facebook hide comments from logged-out visitors → `null`. |
| `maxVideos` | integer 1–5000 | `100` | Stop after this many unique videos in total (links + all profiles). Extra profiles/links are counted in the status message, not charged. |
| `maxDurationSec` | integer 10–600 | `180` | Transcribe at most this many seconds of each video. Longer videos are transcribed from the start and marked `truncated: true`. |
| `proxyConfiguration` | proxy | off | Not needed for most runs. If a platform keeps answering `blocked`, a residential proxy can help. |

#### Input examples

**Instagram Reels transcript by username** (the 12 newest Reels of three creators):

```json
{ "handles": ["@garyvee", "@hormozi", "nasa"], "profilePlatform": "instagram", "maxVideosPerProfile": 12 }
```

**TikTok profile transcript** (50 newest TikToks of one account, with SRT):

```json
{ "handles": ["tiktok:@mkbhd"], "maxVideosPerProfile": 50, "includeSrt": true }
```

**Same creator on both platforms:**

```json
{ "handles": ["@nasa"], "profilePlatform": "both", "maxVideosPerProfile": 5 }
```

**Facebook Reel transcript & single links:**

```json
{
  "urls": [
    "https://www.facebook.com/reel/1795689255099117",
    "https://fb.watch/xyz123/",
    "https://vm.tiktok.com/ZMabc123/",
    "https://www.instagram.com/reel/DeuH0dDFGcg/"
  ]
}
```

**Spanish creators, daily, only new videos:**

```json
{ "handles": ["tiktok:@creador1", "tiktok:@creador2"], "language": "es", "maxVideosPerProfile": 10, "onlyNew": true }
```

### Output

One row per video. Example (real row, segments shortened):

```json
{
  "url": "https://www.instagram.com/reel/DeuH0dDFGcg/",
  "platform": "instagram",
  "profile": "@nasa",
  "status": "ok",
  "charged": true,
  "error": null,
  "videoId": "DeuH0dDFGcg",
  "author": "nasa",
  "authorId": "528817151",
  "caption": "There's a lot of ground to cover when you're building a Moon Base. …",
  "durationSec": 45.82,
  "uploadedAt": "2026-10-20T15:10:43.000Z",
  "viewCount": 3671149,
  "likeCount": 54014,
  "commentCount": 447,
  "shareCount": null,
  "musicTitle": "Original audio",
  "thumbnailUrl": "https://scontent-iad6-1.cdninstagram.com/…",
  "hook": "Think about hundreds of square miles where we have different assets.",
  "transcript": "Think about hundreds of square miles where we have different assets. Definitely mobility systems. There's a lot of people spend a lot of time making sure every detail is right …",
  "wordCount": 141,
  "language": "en",
  "languageProbability": 0.98,
  "transcriptSource": "whisper",
  "model": "whisper-base",
  "speechSeconds": 43.15,
  "truncated": false,
  "segments": [
    { "start": 0, "end": 5.68, "text": "Think about hundreds of square miles where we have different assets. Definitely" },
    { "start": 5.68, "end": 10.04, "text": "mobility systems. There's a lot of people spend a lot of time making sure" },
    { "start": 10.04, "end": 13.88, "text": "every detail is right and it's really specific to the job it needs to do." }
  ],
  "processedAt": "2026-10-25T04:30:09.093Z"
}
```

A music-only Reel from the same run — free, and it says why:

```json
{
  "url": "https://www.instagram.com/reel/Dez3pRXgW1d/",
  "platform": "instagram",
  "profile": "@nasa",
  "status": "no_speech",
  "charged": false,
  "error": "No spoken words found (music, sound only or silence) — not charged.",
  "durationSec": 32.17
}
```

#### All output fields

| Field | Example | Notes |
| --- | --- | --- |
| `url` | `https://www.tiktok.com/@nasa/video/7699974130153590029` | the video link without tracking parameters (for a profile that could not be listed: the profile link) |
| `platform` | `tiktok` | `tiktok`, `instagram`, `facebook` — or `invalid` / `unsupported` / `youtube` for entries this Actor does not handle |
| `profile` | `@nasa` | the username this video was listed from (`null` for videos given as links) |
| `status` | `ok` | see the status table below; only `ok` is charged |
| `charged` | `true` | true only for status `ok` — sum this column to check your bill |
| `error` | `null` | plain-language reason for every status other than `ok` |
| `videoId` | `7699974130153590029` | platform id (Instagram shortcode, TikTok id, Facebook id) |
| `author`, `authorId` | `nasa`, `528817151` | username / page name and account id |
| `caption` | `There's a lot of ground to cover…` | what the creator **wrote** — not what was said |
| `durationSec` | `45.82` | video length |
| `uploadedAt` | `2026-10-20T15:10:43.000Z` | ISO timestamp of the post |
| `viewCount` | `3671149` | views / plays when shown publicly |
| `likeCount` | `54014` | likes (Facebook: reactions) |
| `commentCount`, `shareCount` | `447`, `null` | when the platform shows them publicly (Instagram hides shares) |
| `saveCount` | `1498` | saves / bookmarks (TikTok) |
| `musicTitle`, `musicArtist` | `Original audio`, `nasa` | sound / track title and its artist |
| `ownerFullName`, `isVerified`, `followerCount` | `NASA`, `true`, `104378961` | creator display name, badge, followers (followers: the listed Instagram profile's own Reels) |
| `isPinned` | `false` | pinned to the top of the profile |
| `isPaidPartnership`, `taggedUsers`, `coauthors` | `false`, `["esa"]`, `["nasaadmin"]` | Instagram sponsorship label, tagged accounts, collab co-authors |
| `hashtags`, `mentions` | `["ArtemisII"]`, `["esa"]` | from the caption, without `#` / `@` |
| `thumbnailUrl` | `https://…` | cover image (platform links expire after a few days — save it if you need it) |
| `hook` | `NASA is accelerating Artemis.` | the opening line: speech that starts in the first ~3 seconds, cut at the first full sentence, max 20 words |
| `hookStartSeconds`, `hookEndSeconds` | `0.11`, `2.13` | where the hook sits in the video |
| `hasSpeech` | `true` | `false` for music-only / silent clips (`no_speech`) |
| `transcript` | `NASA is accelerating Artemis. In this week…` | everything said, as one text |
| `wordCount` | `141` | spoken words (sound tags like "\[Music]" excluded) |
| `wordsPerMinute` | `199` | speaking pace over the seconds that contain speech |
| `language`, `languageProbability` | `en`, `0.98` | detected (or your requested) language and the detector's confidence |
| `transcriptSource` | `whisper` | `whisper` (speech recognition) or `native_captions` (captions published on the platform) |
| `model` | `whisper-base` | speech model used (`null` for native captions) |
| `speechSeconds` | `43.15` | seconds of actual speech found; music and silence excluded |
| `truncated` | `false` | true when the video was longer than **Max video length** and only its start was transcribed |
| `segments` | `[{"start":0,"end":5.68,"text":"…"}]` | timestamped pieces in seconds (when **Timestamped segments** is on) |
| `srt` | `1\n00:00:00,000 --> 00:00:05,680\n…` | SRT subtitle text (when **SRT subtitles** is on) |
| `vtt` | `WEBVTT\n\n00:00:00.000 --> 00:00:05.680\n…` | WebVTT subtitle text (when **WebVTT subtitles** is on) |
| `segments[].words` | `[{"start":0,"end":0.4,"word":"Alright"}]` | per-word timing (when **Per-word timestamps** is on) |
| `chunks` | `[{"index":0,"start":0,"end":12.17,"wordCount":32,"text":"…"}]` | ~N-word pieces for RAG (when **Chunks** > 0) |
| `translationEn` | `They gave me a…` | English translation (when **Translate to English** is on) |
| `topComments` | `[{"text":"Hi NASA, when is Artemis III launching?","likes":13,"author":"…","pinnedByAuthor":false,…}]` | TikTok only (when **Top comments** > 0) |
| `creatorMedianViews` | `5139534` | median views of the videos listed from this profile (5+ needed) |
| `viewsVsCreatorMedian`, `isOutlier` | `21.12`, `true` | this video's views ÷ the creator's median; outlier = 2× or more |
| `isNew`, `firstSeenAt` | `true`, `2026-10-26T06:16:49Z` | with a watchlist or **Only new videos**: first time seen and when |
| `processedAt` | `2026-10-25T04:30:09.093Z` | when the row was produced |

Every run also writes a **receipt** to its key-value store, record `SUMMARY`: rows per status, how many were charged, how many were filtered out (older / pinned / views), duplicates, and per profile how many videos were listed and selected.

Download the dataset as **JSON, CSV, Excel, XML, HTML or RSS**, or read it through the API. The **Transcripts** view in the Console shows profile, status, hook, transcript, views, likes, length, language, author, caption and link side by side.

### Status values — what every row means

| Status | Charged | Meaning | What to do |
| --- | --- | --- | --- |
| `ok` | **yes** | Transcribed. | — |
| `no_speech` | no | Only music, sound effects or silence — nothing was said. | Nothing; this is the correct answer for that clip. |
| `no_videos` | no | The profile exists but shows no public videos (or is private). | Check the username. |
| `caption_only` | no | Instagram did not serve this single Reel's file without a login; the public caption is returned instead. | Use the creator's username in **Profiles** — profile listings usually include the file. |
| `blocked` | no | The platform refused the request (temporary IP block; on TikTok also deleted / non-existent videos). | Open the link in a browser. If it works, retry later or turn on a residential proxy. |
| `network_error` | no | The connection dropped twice. | Retry later. |
| `private` | no | Private or followers-only. | Never accessed by design. |
| `login_required` | no | The platform wants a login for this video. | Never bypassed by design. |
| `not_found` | no | Deleted, never existed, or a mistyped link. | Check the link. |
| `no_audio` | no | The video has no sound track. | — |
| `geo_restricted` | no | Not available from the region the run connected from. | A proxy in the right country can help. |
| `download_failed` | no | The file could not be downloaded for another reason. | Retry; report the link if it keeps failing. |
| `transcribe_failed` | no | The audio file could not be decoded. | Report the link. |
| `budget_limit` | no | Not processed because the run reached your **Maximum cost per run**. | Raise the limit or split the input. |
| `timeout` | no | Not processed because the run was about to hit its timeout. | Raise the run timeout (Run options) or lower **Max videos**. |
| `invalid` | no | Not a URL or username. | Fix the line. |
| `unsupported` | no | A link from another site. | — |
| `youtube` | no | YouTube is not handled by this Actor. | — |

Every run ends **SUCCEEDED** and its status message sums it up, for example: *"7 transcribed (charged) · 2 no speech · 1 not found (free) · 3 duplicate video(s) skipped"*. A bad link never fails the run.

### Pricing — pay only for transcripts

- **$0.008 per transcribed video** (up to 3 minutes of audio) — **$8 per 1,000 transcripts**.
- **Start fee: $0.001 per GB of run memory** — $0.002 per run with the default 2 GB.
- **Platform usage is included** — no compute, proxy or storage costs on top.
- **Free:** `no_speech`, `private`, `not_found`, `login_required`, `blocked`, `no_audio`, `caption_only`, duplicates, links over your limits, and anything not processed because of your cost limit or the timeout.

| Job | Transcribed videos | Cost |
| --- | --- | --- |
| Try it: empty input (2-Reel sample) | 2 (free) | $0.002 |
| 1 creator, 12 newest Reels | ~10 (2 are often music-only → free) | ~$0.08 |
| 10 competitors × 10 TikToks, once | ~90 | ~$0.72 |
| Daily monitor, 20 creators, **Only new videos** on (~1 new video per creator per day) | ~20 / day | ~$0.17 / day · ~$5 / month |
| Hook library: 1,000 videos | ~900 | ~$7.20 |

**Maximum cost per run** is respected exactly: before transcribing a video, the Actor checks that the transcript still fits in your limit. Videos that would go over it come back as `budget_limit` rows (free) instead of being transcribed and thrown away — you never pay for work you cannot receive.

### How to use it (no code)

1. Open the **Input** tab.
2. **Profiles**: type usernames or profile links, one per line. Plain usernames use **Platform for usernames** (Instagram by default, or TikTok, or both); `tiktok:@name` / `ig:name` choose per line.
3. **Videos per profile**: how many of the newest videos to transcribe (default 10).
4. Or paste single links into **Video URLs** (short links like `vm.tiktok.com/…` and `fb.watch/…` work). Profiles and links can be mixed.
5. Optional: set the **Spoken language** (`en`, `es`, `id`, `pt`, …) if you already know it.
6. Click **Start**. Rows appear in the **Output** tab while the run is going. Export as CSV / Excel / JSON.

Started with an empty input, the Actor transcribes a **free 2-Reel sample** from Instagram `@nasa`, so you can see the output before spending anything.

### Recipes

#### 1. Daily creator monitoring (only new videos)

Watch competitors or favourite creators and get each new video's transcript the morning after it is posted.

1. Input: `{ "handles": ["@creator1", "@creator2", "tiktok:@creator3"], "maxVideosPerProfile": 12, "onlyNew": true }`.
2. Save it as a **Task**, then **Schedule** it daily (Console → Schedules → Create, e.g. `0 7 * * *`).
3. The first run transcribes the backlog (up to **Videos per profile** each); every later run transcribes only what was posted since. Already-seen videos are skipped **before** download, so they cost nothing.
4. Connect the dataset to Google Sheets, Slack, email or a webhook (see Integrations) to get the new transcripts delivered.

The memory lives in a key-value store named `short-video-transcript-seen` in your own account. Delete that store to start fresh. Music-only clips are remembered too, so they are not re-checked every day.

#### 1b. One memory per client: watchlists

Running monitors for several clients or niches? Give each schedule its own `watchlistId` (`"client-acme"`, `"fitness-creators"`). Each gets a separate memory (`svt-watch-client-acme`), and every row carries `isNew` and `firstSeenAt` — even without *Only new videos*, so you can flag fresh videos in a full refresh.

#### 2. Hook swipe file

Collect the opening lines of what works in your niche:

1. Input: 10–30 top creators, `maxVideosPerProfile: 12`.
2. Export to Excel / Google Sheets and sort by `viewCount`.
3. Read the `hook` column next to `viewCount` and `likeCount` — the hooks of the top 10% of videos are your swipe file.

`hook` is built from the real timestamps (speech that starts in the first ~3 seconds), so it is what the viewer actually hears first — not the caption. Faster: `{ "handles": [...], "sortBy": "most_viewed", "maxVideosPerProfile": 10, "onlyPostsNewerThan": "90 days" }` transcribes only each creator's top 10 of the last 90 days.

#### 2b. Find outliers — what beat the creator's usual

Every video listed from a profile is compared with that creator's median views: `viewsVsCreatorMedian: 4.2` means 4.2× the usual, `isOutlier: true` from 2×. Sort by it to see which topics and hooks broke out — a better signal than raw views, which favour big accounts.

#### 3. Repurpose videos into blog posts, threads and newsletters

Feed `transcript` + `caption` of each row to ChatGPT / Claude with a prompt like *"Rewrite this transcript as a 600-word blog post with H2 headings, keep the speaker's examples."* With the API, one Make/Zapier/n8n scenario does it for every new row.

#### 4. Subtitles for your own videos

Turn on **SRT subtitles** and paste your own Reel / TikTok / Facebook links. Save the `srt` field as `video.srt` and upload it to your editor (CapCut, Premiere, DaVinci Resolve) or to the platform. `segments` gives the same timing as JSON for burned-in captions.

#### 5. Multilingual research

Leave **Spoken language** empty and every video gets its own detected `language` and `languageProbability`. Filter the dataset by language, or set `language` when a creator always speaks the same one (more accurate on very short clips). Whisper covers 99 languages, including English, Spanish, Portuguese, Indonesian, Hindi, Arabic, German, French, Japanese, Korean, Turkish, Vietnamese and Russian.

#### 6. Chain after any scraper (datasetId)

Ran an Instagram, TikTok or Facebook scraper already? Pass its dataset: `{ "datasetId": "<dataset id>" }`. The Actor reads the post link from the usual fields (`url`, `webVideoUrl`, `postUrl`, `shortCode`, …), skips photo posts and duplicates, and — for Instagram rows that include the `videoUrl` file — transcribes straight from that file with the row's own views, likes and caption. Video file links from scrapers expire after a few hours, so run it soon after the scraper (a webhook or Make/Zapier step does that). Links from a spreadsheet work too: paste them into `urls` (up to 5,000 per run with `maxVideos`).

#### 7. Transcripts for AI / RAG

Set `chunkWords` to 150–300: each row gets `chunks` with start/end seconds, ready to embed. Store the video `url` + `chunk.start` as metadata and your chatbot can cite the exact second. `wordTimestamps: true` adds per-word timing for word-level search or karaoke captions.

#### 8. Foreign-language creators in English

`{ "handles": ["tiktok:@luisitocomunica"], "translateToEnglish": true }` gives the Spanish `transcript` and an English `translationEn` side by side. Whisper's translation is literal — good for research and search; polish it with an LLM before publishing.

### Use it via API

**One call, wait for the rows** (best for up to ~20 videos):

```bash
curl -X POST "https://api.apify.com/v2/acts/tactful_anvil~short-video-transcript/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "handles": ["tiktok:@nasa"], "maxVideosPerProfile": 3 }'
```

**Python** (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("APIFY_TOKEN")
run = client.actor("tactful_anvil/short-video-transcript").call(run_input={
    "handles": ["@nasa", "tiktok:@mkbhd"],
    "maxVideosPerProfile": 10,
    "onlyNew": True,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["status"] == "ok":
        print(row["profile"], row["viewCount"], row["hook"])
```

**Node.js** (`npm i apify-client`):

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('tactful_anvil/short-video-transcript').call({
  urls: ['https://www.tiktok.com/@nasa/video/7699974130153590029'],
  includeSrt: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].transcript);
```

Big batches: start with `POST /v2/acts/tactful_anvil~short-video-transcript/runs`, then poll the run or use a webhook on `ACTOR.RUN.SUCCEEDED`, and read `GET /v2/datasets/{defaultDatasetId}/items?format=csv`.

### Use with AI agents (MCP)

This Actor is available through the [Apify MCP server](https://mcp.apify.com). To give your agent exactly this one tool:

```json
{
  "mcpServers": {
    "short-video-transcript": {
      "url": "https://mcp.apify.com/?tools=tactful_anvil/short-video-transcript"
    }
  }
}
```

Works with Claude (Desktop, Code, claude.ai connectors), ChatGPT, Cursor, VS Code, Windsurf, n8n's MCP client and the OpenAI Agents SDK. Prompts that work well:

- *"Transcribe the 12 newest Reels of @hormozi and give me the 5 strongest hooks with their view counts."*
- *"Here are 15 TikTok links — transcribe them and tell me which ones mention our brand."*
- *"Every morning, check @competitor1 and @competitor2 on TikTok for new videos and summarize what they said."* (with `onlyNew: true`)

Why it is agent-friendly: flat rows, a `status` on every row instead of exceptions, `charged` for cost tracking, `hook` pre-extracted, and the run never fails on a bad link — the agent gets a readable reason and can carry on.

### Integrations

- **Google Sheets** — Apify's Google Sheets integration (or Make / Zapier) appends every new transcript as a row.
- **Make** — "Apify → Watch Actor Runs" → "Get Dataset Items" → any of 1,500+ apps.
- **Zapier** — "New Finished Actor Run" trigger → filter `status = ok` → Notion, Airtable, Slack, Gmail.
- **n8n** — the Apify node (run Actor + get dataset items), or the MCP client node with the URL above.
- **Webhooks** — POST to your endpoint on every finished run.
- **LangChain / LlamaIndex** — load the dataset with the Apify loaders and index `transcript` with `segments` for timestamped retrieval.

### Instagram Reels transcript by username

Type the username (`@garyvee`, `garyvee` or `https://www.instagram.com/garyvee/`) into **Profiles** and keep **Platform for usernames** on *Instagram Reels*. The Actor reads the profile's Reels tab the way a logged-out visitor sees it and transcribes the newest Reels — **up to 500 per profile**, read 12 per page with polite pauses, never logged in. Pinned Reels are put back into date order or skipped (`skipPinned`). Collab Reels that appear on the profile are included with their real owner in `author`. Private accounts return `private` (free). Views, likes, comments, caption, sound and upload date come with every row.

### TikTok profile transcript

Use `tiktok:@username`, a `https://www.tiktok.com/@username` link, or set **Platform for usernames** to *TikTok*. Up to **500 videos per profile**, newest or most viewed. Many TikToks carry captions published by the creator or TikTok — with **Use the platform's own captions** on, those are returned directly (`transcriptSource: native_captions`); otherwise the audio is transcribed with Whisper. If TikTok refuses to list a profile to cloud servers, that profile comes back as `blocked` (free) after one automatic retry; single video links are not affected.

### Facebook Reel transcript

Paste public Facebook Reels or video links into **Video URLs** — `facebook.com/reel/…`, `facebook.com/watch?v=…`, `facebook.com/<page>/videos/…`, `facebook.com/share/r/…` and `fb.watch/…` short links. You get the transcript plus views and reactions (parsed from the public page), page name and caption. Facebook *profiles* by username are not listed; use links.

### TikTok / Instagram video to text — how it compares

- **Spoken words, not just captions.** Many tools return the caption the creator typed. This Actor returns what is *said*, with timestamps, and tells you which source it used.
- **Three platforms, one schema.** TikTok, Instagram and Facebook rows have the same columns, so one sheet or one prompt handles all of them.
- **Usernames, not just links.** Give a creator, get their newest videos.
- **You pay for transcripts, not attempts.** Music-only clips are detected by voice activity detection and are free; so is everything that failed.
- **No login, no cookies, no third-party API key.** Whisper runs inside the Actor.
- **Built for schedules.** *Only new videos* and named watchlists skip already-processed videos before download, so a daily monitor costs only what is new.
- **Filters before download.** Date, pinned, views and most-viewed are applied before any file is fetched — nothing filtered is charged.
- **More than a transcript.** Hook timing, speaking pace, outlier score, hashtags, collaborators, English translation, TikTok comments, chunks for RAG — in the same row, same price.

### Platform notes (honest)

- **TikTok** — public videos: transcribed. Creator / TikTok captions are used when present (faster).
- **TikTok profiles** — TikTok sometimes refuses to list a profile to cloud servers; that profile then comes back as `blocked` (free). Single TikTok video links are not affected — paste them into **Video URLs**, or retry with a proxy.
- **Facebook** — public Reels and videos: transcribed.
- **Instagram profiles** — up to 500 Reels of public profiles, listed 12 per page. Private profiles return `private` (free). If Instagram stops answering mid-listing, the Reels listed so far are still transcribed.
- **Instagram single Reel links** — transcribed when Instagram serves the file without a login; otherwise you get the **public caption** with status `caption_only` (free). Tip: the profile's username usually works better than single links.
- **Photo posts and carousels** have nothing to transcribe and are skipped by profile listings.
- **YouTube** is not handled here.
- Private, followers-only and age-restricted videos are never accessed.

### Limits

- Instagram: up to 500 Reels per profile (12 per page, ~1.5 s per page).
- TikTok: up to 500 videos per profile; TikTok sometimes refuses profile listings to cloud servers (`blocked`, free).
- Comments: TikTok only. Follower counts: Instagram only.
- Up to 5,000 unique videos per run (`maxVideos`); split very large jobs into several runs.
- Up to 600 seconds of audio per video (`maxDurationSec`, default 180). Reels and TikToks are almost always shorter.
- Speed: about 5 typical 30–60 s Reels per minute with the default 2 GB memory (cloud test, 25 Oct 2026); long videos take longer. More memory = more CPU = faster speech recognition (4 GB gives a full CPU core).

### FAQ

**How do I get the transcript of an Instagram Reel?**
Paste the creator's username into **Profiles** (best) or the Reel link into **Video URLs**, then click Start. The `transcript` column has the spoken text, `segments` the timestamps.

**How do I transcribe all TikToks of a profile?**
`{ "handles": ["tiktok:@username"], "maxVideosPerProfile": 500 }`. Raise **Max videos** if you add more profiles.

**Can I get a transcript of a Facebook Reel?**
Yes — paste the public Reel link (or `fb.watch` link) into **Video URLs**.

**How accurate is it?**
Whisper *base* handles clear speech in major languages very well; heavy background music, slang and crosstalk lower accuracy. Set **Spoken language** for very short clips. Choose **Fast (tiny)** only for clear English speech.

**What if a video is only music?**
You get a `no_speech` row and pay nothing. The voice activity detector measures real speech (`speechSeconds`), so a song with a few words in it is still transcribed when words are actually sung or spoken.

**Does it translate?**
Yes, to English: turn on **Translate to English** and non-English videos get `translationEn` (Whisper's own speech translation, same price). Other target languages: translate `transcript` or `translationEn` with your LLM of choice.

**Can I get only recent videos?**
`"onlyPostsNewerThan": "7 days"` (or a date). Older videos are skipped before download and cost nothing.

**Can I get a creator's most viewed videos?**
`"sortBy": "most_viewed"` — the top videos by views among about 3× the number you ask for (at least 36). Add `minViews` for a hard floor.

**Does it get comments?**
TikTok yes (`maxComments`, up to 50 most liked, pinned first). Instagram and Facebook do not show comments to logged-out visitors, and this Actor never logs in.

**Does it read text shown on screen?**
Not yet — only spoken words (and creator captions). The written `caption` of the post is always included.

**Does it work with private accounts?**
No. Only public videos, without logging in.

**Why is `shareCount` empty for Instagram?**
Instagram does not show share counts to logged-out visitors.

**Do thumbnail links expire?**
Yes, Instagram and TikTok image links expire after a few days. Download them right after the run if you need them.

**Daily monitoring?**
Turn on **Only new videos** and schedule the run (Recipe 1). Videos already transcribed by your earlier runs are skipped and never charged twice.

**Long videos?**
Audio after **Max video length** (default 180 s, max 600 s) is not transcribed and the row is marked `truncated`.

**Can I limit my spend?**
Yes — set **Maximum cost per run** in Run options. The Actor stops transcribing before it would cross that limit and marks the rest `budget_limit` (free).

**Is there an API / can my AI agent use it?**
Yes — see *Use it via API* and *Use with AI agents (MCP)* above.

**Is this legal?**
The Actor only reads publicly available videos, without logging in, at a polite pace. You are responsible for how you use the transcripts (copyright, privacy, platform terms). Do not use it to collect personal data you have no legitimate reason to process.

**Something broke?**
Open an Issue on this page with the failing link and your run ID — fixes usually ship within a day.

### Changelog

- **0.3 (26 Oct 2026)** — Instagram up to 500 Reels per profile (paging); filters (`onlyPostsNewerThan`, `skipPinned`, `minViews`, `sortBy`); `datasetId` / `datasetItems` input; named watchlists with `isNew` / `firstSeenAt`; `hookStartSeconds` / `hookEndSeconds`, `wordsPerMinute`, `hasSpeech`; WebVTT, per-word timestamps, `chunks`; owner name, verified, followers, pinned, paid partnership, tagged users, collaborators, hashtags, mentions, saves, sound artist; outlier score vs creator median; `translationEn`; TikTok top comments; `SUMMARY` receipt; two speech workers on 16 GB+ runs.
- **0.2 (25 Oct 2026)** — Profiles by username (Instagram + TikTok), `hook` column, *Only new videos*, free sample on empty input, TikTok profile retry.
- **0.1 (24 Oct 2026)** — First release: TikTok, Instagram Reels and Facebook Reels links → Whisper transcript, native TikTok captions, SRT, pay only for transcripts.

# Actor input Schema

## `handles` (type: `array`):

Instagram or TikTok creators — <code>@zachking</code>, <code>zachking</code>, <code>https://www.instagram.com/zachking/</code> or <code>https://www.tiktok.com/@zachking</code>. The Actor lists each profile's newest videos and transcribes them. Plain usernames use <b>Platform for usernames</b> below; <code>tiktok:@name</code> / <code>ig:name</code> pick the platform per line.

## `profilePlatform` (type: `string`):

Where to look up plain usernames (<code>@name</code> / <code>name</code>). Profile links always use their own platform.

## `maxVideosPerProfile` (type: `integer`):

Newest videos to transcribe from each profile (after the filters below). Instagram: up to 500 Reels (listed 12 per page without a login); TikTok: up to 500.

## `onlyPostsNewerThan` (type: `string`):

A date (<code>2026-10-01</code>) or a period (<code>7 days</code>, <code>24 hours</code>, <code>2 weeks</code>, <code>3 months</code>). Older videos are skipped before download and never charged. Empty = no date filter.

## `skipPinned` (type: `boolean`):

Leave out the videos a creator pinned to the top of the profile (they are often old).

## `minViews` (type: `integer`):

Only transcribe videos with at least this many views (0 = all). Videos whose views are not public are kept.

## `sortBy` (type: `string`):

<b>Newest</b> = the most recent videos. <b>Most viewed</b> = the top videos by views among the latest ones listed (about 3× <i>Videos per profile</i>, at least 36).

## `urls` (type: `array`):

Single TikTok videos, Instagram Reels and Facebook Reels / videos — one link per line. Short links (vm.tiktok.com, fb.watch) work, profile links pasted here are listed like Profiles. Duplicates are skipped automatically.

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

Transcribe the videos found by another Actor run — paste its dataset ID (e.g. from an Instagram, TikTok or Facebook scraper). The post link is read from <code>url</code>, <code>webVideoUrl</code>, <code>postUrl</code>, <code>shortCode</code> and similar fields; Instagram rows with a <code>videoUrl</code> file are transcribed straight from that file. Photo posts are skipped.

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

Same as Dataset ID, but with the rows pasted directly (any shape, e.g. <code>\[{"url": "https://www.tiktok.com/@nasa/video/…"}]</code>).

## `onlyNew` (type: `boolean`):

Skip videos that an earlier run of yours already transcribed (remembered in a key-value store named <code>short-video-transcript-seen</code> in your account). Ideal for a daily schedule that watches the same creators.

## `watchlistId` (type: `string`):

Give a monitoring job its own memory, e.g. <code>competitors</code> or <code>client-acme</code>. Every row then gets <code>isNew</code> and <code>firstSeenAt</code>; with <b>Only new videos</b> on, videos already on this list are skipped. Empty = the shared memory of <b>Only new videos</b>.

## `language` (type: `string`):

Two-letter code such as <code>en</code>, <code>es</code>, <code>id</code>, <code>pt</code>. Leave empty to detect the language of every video automatically (99 languages).

## `model` (type: `string`):

<b>base</b> = good accuracy, recommended. <b>tiny</b> = fastest, fine for clear English speech. Same price.

## `preferNativeCaptions` (type: `boolean`):

Some TikToks carry captions published by the creator / TikTok. When on, those are returned instead of running speech recognition (faster). Off = always transcribe the audio.

## `includeSegments` (type: `boolean`):

Add a <code>segments</code> array (start, end, text) for subtitles, clipping and hooks.

## `includeSrt` (type: `boolean`):

Add a ready-to-use <code>srt</code> subtitle string to every row.

## `includeVtt` (type: `boolean`):

Add a ready-to-use <code>vtt</code> (WebVTT) subtitle string to every row — the web/HTML5 subtitle format.

## `wordTimestamps` (type: `boolean`):

Add <code>words</code> \[{start, end, word}] inside every segment — for karaoke captions, precise clipping and word search. Uses speech recognition even when the platform has captions.

## `chunkWords` (type: `integer`):

Also cut each transcript into <code>chunks</code> of about this many words, each with start / end seconds — ready for embeddings and retrieval. 0 = off.

## `translateToEnglish` (type: `boolean`):

Add <code>translationEn</code>: the spoken words translated to English by Whisper itself (non-English videos only; English videos get their transcript). Same price.

## `maxComments` (type: `integer`):

Add the most-liked comments of every transcribed TikTok (pinned first) as <code>topComments</code>. 0 = off. Instagram and Facebook do not show comments without a login.

## `maxVideos` (type: `integer`):

Stop after this many unique videos in total (links + all profiles).

## `maxDurationSec` (type: `integer`):

Audio after this point is not transcribed and the row is marked <code>truncated</code>. Reels and TikToks are almost always shorter than 3 minutes.

## `proxyConfiguration` (type: `object`):

Not needed for most runs. If a platform starts blocking downloads (status <code>blocked</code>), a residential proxy can help.

## Actor input object example

```json
{
  "handles": [
    "@nasa"
  ],
  "profilePlatform": "instagram",
  "maxVideosPerProfile": 10,
  "onlyPostsNewerThan": "",
  "skipPinned": false,
  "minViews": 0,
  "sortBy": "newest",
  "onlyNew": false,
  "language": "",
  "model": "base",
  "preferNativeCaptions": true,
  "includeSegments": true,
  "includeSrt": false,
  "includeVtt": false,
  "wordTimestamps": false,
  "chunkWords": 0,
  "translateToEnglish": false,
  "maxComments": 0,
  "maxVideos": 100,
  "maxDurationSec": 180,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Every row of the run, in input order of completion.

# 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 = {
    "handles": [
        "@nasa"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tactful_anvil/short-video-transcript").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 = { "handles": ["@nasa"] }

# Run the Actor and wait for it to finish
run = client.actor("tactful_anvil/short-video-transcript").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 '{
  "handles": [
    "@nasa"
  ]
}' |
apify call tactful_anvil/short-video-transcript --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tactful_anvil/short-video-transcript"
        }
    }
}
```

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/FRADm95DKmFbC110P/builds/ax5c2rzqbxotRh8Jk/openapi.json
