# Instagram Transcript Scraper — Reels to Text, No Login (`autofacts/instagram-transcript-scraper`) Actor

Instagram Reel transcripts in bulk, no login: paste Reel links or whole profiles and get each Reel as text with timestamps, the spoken language, the caption, hashtags and engagement. Transcription included, no API key needed; Reels without speech aren't charged. Export JSON or CSV, or call the API.

- **URL**: https://apify.com/autofacts/instagram-transcript-scraper.md
- **Developed by:** [Richard Feng](https://apify.com/autofacts) (community)
- **Categories:** Social media, Videos, AI
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.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.
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?

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 Transcript Scraper — Reels to Text · No Login

**This Instagram transcript scraper turns any public Reel or Instagram video into text — no Instagram account, no login, no browser.**

Point it at an account and get one clean row per Reel: the **transcript**, its **timestamps**, the language,
plus the caption, hashtags and the Reel's engagement — ready to analyse, search or feed to an LLM.

|  |  |
|---|---|
| 🎙️ **Reels → text** | 🔓 **No login, no account** |
| ⏱️ **Timestamps** per passage | 🌍 **Language detection** |
| 📊 Caption, hashtags, plays, likes | 🧾 Clean JSON, ready for AI |

***

### 📑 Table of contents

- [What can this Actor do?](#-what-can-this-actor-do)
- [Quick start](#-quick-start)
- [Input reference](#-input-reference)
- [Output reference](#-output-reference)
- [Output example](#-output-example)
- [Why choose this Actor?](#-why-choose-this-actor)
- [How much does it cost?](#-how-much-does-it-cost)
- [Use cases](#-use-cases)
- [Automation & AI agents](#-automation--ai-agents)
- [FAQ](#-faq)
- [Notes and limitations](#-notes-and-limitations)
- [Other Actors by autofacts](#-other-actors-by-autofacts)

***

### ✨ What can this Actor do?

| 🧲 Collect | ⚙️ Built in |
|---|---|
| 🎙️ **Transcripts** — the spoken words of every Reel, as one string | 🎯 Per-account caps, so a run's size is predictable |
| ⏱️ **Timestamped segments** — `start`, `end`, `text` per passage | 🌍 Language detection, or give it a hint |
| 👤 **Creator context** — username, full name, verified | 🔗 Canonical public Reel URL on every row |
| 📊 **Engagement** — plays, likes, comments | 📅 The Reel's date and caption |
| 🏷️ **Hashtags & mentions** — parsed out of the caption | 🚦 Hard request cap and concurrency control |
| 🎬 **The audio track itself** — the URL that was transcribed | 🌐 Apify Proxy residential by default |

Point it at a **profile** or a **Reel link**. That's the whole interface.

***

### 🚀 Quick start

1. **Create a free Apify account** 🙋
2. Open this Actor and **paste a profile or a Reel link** 👇
3. Set **Max Reels per profile** to how many you want
4. **Save & Start**, then download the dataset as JSON, CSV or Excel 📦

```json
{
    "startUrls": [{ "url": "https://www.instagram.com/natgeo/" }],
    "maxReelsPerProfile": 10
}
```

#### 🔗 What links can I paste?

| Paste this | And you get |
|---|---|
| `instagram.com/natgeo/` | That profile's Reels, transcribed |
| `instagram.com/reel/DeeUUHNAqQj/` | That one Reel, transcribed |
| `@natgeo` or `natgeo` | Same as the profile link |

The account can also sit in front of a Reel (`instagram.com/natgeo/reel/<code>/`), and `instagr.am` links work
the same way. A share link (`instagram.com/share/…` or `instagram.com/s/…`) carries a code that is not the
Reel's own: open it and paste the address it leads to. The run log names every link it could not use, and why.

💡 Add **Include the timeline** to also pick up videos from the posts grid, not only the Reels tab.

***

### ⬇️ Input reference

| Field | Type | Default | Description |
|---|---|---|---|
| **Start URLs** | array | — | Profile or Reel addresses. |
| **Usernames** | array | — | Extra accounts, with or without `@`. |
| **Max Reels per profile** | integer | `10` | How many of each profile's videos to transcribe. Each one is a download plus a transcription, so this is also the main cost control. |
| **Include the timeline** | boolean | `false` | Also transcribe videos from the posts grid, not only the Reels tab. |
| **Include timestamps** | boolean | `true` | Keep `segments[]`. Turn off for a smaller record with just the full transcript. |
| **Language** | string | *(detect)* | Optional hint, e.g. `en`, `es`, `pt`. |
| **Max concurrency** | integer | `3` | How many Reels to transcribe at once. |
| **Max requests per run** | integer | *(API only)* | Hard stop after this many requests. |
| **Proxy configuration** | object | Residential | Apify Proxy's RESIDENTIAL group, selected in the form and used when the field is left out: Instagram answers logged-out readers far more readily from residential addresses. Audio files are downloaded without it unless a download fails. |

***

### ⬆️ Output reference

One record per Reel. (See the limitations for the two cases where a row can be duplicated or missing.)

| Field | Type | Notes |
|---|---|---|
| `type` | string | `transcript` |
| `url` | string | The public Reel page — what to join on |
| `source` | object | `{id, canonicalUrl, crawlUrl?, username}` |
| `id` / `shortcode` | string | Instagram's media id and the short code in the URL |
| `owner` | object | `{id, username, fullName, isVerified}` |
| `takenAt` | string | ISO 8601 |
| `caption` | string | The Reel's caption |
| `hashtags` / `mentions` | array | Parsed from the caption, without `#` / `@` |
| `transcript` | string | **The whole transcript.** Empty for a Reel without speech |
| `segments` | array | `{start, end, text}` — seconds from the start of the audio |
| `language` | string | As detected by the engine |
| `wordCount` | integer | |
| `hasSpeech` | boolean | `false` for a Reel without speech — its audio held only music, or it was posted without sound. Beside a `transcriptError` it means the transcription did not happen |
| `durationSeconds` | number | The Reel's length |
| `playCount` / `likeCount` / `commentCount` / `viewCount` | integer | Engagement at the time of the run |
| `audioUrl` | string | Instagram's audio-only track of the Reel (a signed link that expires) |
| `audioBytes` | integer | Size of the audio that was transcribed — a few hundred KB for a short Reel, about 1 MB for two minutes. `0` for a Reel posted without sound |
| `transcriptModel` | string | The model that produced the text. `none` for a Reel posted without sound: there was nothing to send to one |
| `transcriptError` | string | Set only when the Reel was read but could not be transcribed. A failure worth retrying is retried by the Actor first; what lands here is final |
| `scrapedAt` | string | ISO 8601 |

***

### 📦 Output example

```json
{
    "type": "transcript",
    "source": {
        "id": "instagram",
        "canonicalUrl": "https://www.instagram.com/reel/DcozHIETCd9/",
        "username": "nasaadmin"
    },
    "id": "3974651461224900477",
    "shortcode": "DcozHIETCd9",
    "url": "https://www.instagram.com/reel/DcozHIETCd9/",
    "owner": { "id": "79712351002", "username": "nasaadmin", "fullName": "NASA Administrator Jared Isaacman", "isVerified": true },
    "takenAt": "2026-08-29T20:31:28.000Z",
    "caption": "An unforgettable day at @nasajohnson. …",
    "hashtags": [],
    "mentions": ["nasajohnson", "potus"],
    "durationSeconds": 114.566,
    "likeCount": 51113,
    "commentCount": 409,
    "audioUrl": "https://…mp4",
    "audioBytes": 1019785,
    "transcript": "… 250,000 miles from Earth. Please join me in congratulating Commander Reed Weissman, Pilot Victor Glover, Mission Specialist Christina Koch, and Mission Specialist Jeremy Hansen. …",
    "segments": [
        { "start": 30.12, "end": 32.7, "text": "250,000 miles from Earth." },
        { "start": 32.7, "end": 44.64, "text": "Please join me in congratulating Commander Reed Weissman, Pilot Victor Glover, Mission Specialist Christina Koch, and Mission Specialist" },
        { "start": 44.64, "end": 45.98, "text": "Jeremy Hansen." }
    ],
    "language": "en",
    "wordCount": 204,
    "hasSpeech": true,
    "transcriptModel": "whisper-large-v3-turbo",
    "scrapedAt": "2026-10-20T01:52:23.613Z"
}
```

***

### ⭐ Why choose this Actor?

|  |  |
|---|---|
| 🎙️ **It only fetches the audio** | A Reel's sound is well under a megabyte, against several megabytes for the video. That is ~10× less to move and transcribe — cheaper and faster than tools that pull whole videos. |
| ⏱️ **Timestamps, not just text** | `segments[]` gives you `start`/`end` per passage, so you can clip, align or subtitle. |
| 🌍 **Language detected** | No need to tell it what it is listening to. |
| 🔓 **No login, no account** | Public Reels only. Nothing to rotate, nothing to leak, no account to get banned. |
| 📊 **Engagement alongside the text** | Plays, likes, comments and the caption on the same row — join performance to content without a second Actor. |
| 🤖 **LLM-ready** | Plain JSON with stable field names; feed `transcript` straight into your model. |
| 🧹 **Honest about silence** | A Reel with only music, or posted without sound, produces a row with `hasSpeech: false` rather than being silently dropped — and this Actor does not charge for it. A transcription that failed says so in `transcriptError`. |

***

### 💰 How much does it cost?

**You pay per transcript**, pay-per-event. A Reel that turns out to have no speech is stored and **not
charged**.

| Event | Free | Starter | Scale | Business and up |
| :--- | ---: | ---: | ---: | ---: |
| 🎙️ **Transcript**, per 1,000 Reels that produced text | $5.00 | $4.50 | $4.00 | $4.00 |
| ▶️ **Actor start**, per run | $0.00005 | $0.00005 | $0.00005 | $0.00005 |

The event price **includes the platform usage this Actor generates** — compute and proxy. Apify bills usage on top only if the publisher has switched to "pay per event + usage"; the Actor's page shows which applies.

💡 **A worked example.** 100 Reels transcribed ≈ **$0.50** on the Free plan, **$0.40** from Scale up. The same
100 Reels as full videos would move roughly 10× the data before transcription even starts.

**Cost levers:** ⬇️ lower **Max Reels per profile** (the only real one — one Reel is one charge), 🚦 set
**Max requests per run**, and use Apify's own **maximum cost per run** — the Actor stops starting new work
when it is reached; a download already in flight finishes. Turning **timestamps** off makes the record
smaller but not cheaper: the timings come back from the same transcription call.

***

### 💡 Use cases

- 📝 **Content research at scale** — search what creators actually *say*, not just what they caption
- 🔎 **Keyword & topic monitoring** — find every Reel in a niche that mentions your brand, your competitors or a trend
- 🤖 **LLM & RAG pipelines** — turn Reels into a text corpus for summarising, clustering or Q\&A
- 🎬 **Subtitling & repurposing** — segments with start/end times, straight into an editor
- 📈 **Creator analytics** — does talking about a topic correlate with plays? The engagement is on the same row
- 🗣️ **Multilingual monitoring** — language detection tells you what you are looking at

***

### 🤖 Automation & AI agents

- 🔌 **Apify API** — start a run and read the dataset from any language
- 🧩 **No-code** — Make, n8n, Zapier and the Apify integrations
- 🤖 **MCP / LLM agents** — callable as an MCP tool from Claude, ChatGPT or any agent that speaks MCP
- 📤 **Exports** — JSON, CSV, Excel and XML straight from the dataset

**Connect over MCP**

```
https://mcp.apify.com?tools=autofacts/instagram-transcript-scraper
```

In a client that reads an `mcpServers` configuration block:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=autofacts/instagram-transcript-scraper",
      "headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
    }
  }
}
```

The agent reads this Actor's parameters and their descriptions straight from the input schema, and the
hosted server infers the result field types from the dataset schema — so a model knows what to send and
what comes back before it ever calls anything.

**Or call the API directly**

```bash
curl -X POST "https://api.apify.com/v2/acts/autofacts~instagram-transcript-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"startUrls": [{"url": "https://www.instagram.com/reel/DeeUUHNAqQj/"}]}'
```

The response body is the dataset records described above: one row for that Reel, with its transcript.

***

### ❓ FAQ

**How do I get the transcript of an Instagram Reel?** 📋 Paste the Reel's link
(`https://www.instagram.com/reel/<code>/`) into **Start URLs** and start the run. The text is in
`transcript`, and its timed passages in `segments[]`. A video post (`/p/<code>/`) or an old IGTV link
(`/tv/<code>/`) works the same way.

**Can I transcribe Instagram Reels in bulk?** 📦 Yes. Give it as many Reel links as you like, or
profiles: each profile's Reels tab is transcribed up to **Max Reels per profile**, plus its timeline if you
turn that on. Every Reel is one row.

**Is there an Instagram transcript API?** 🔌 This is one. Start a run through the Apify API, or call it
from an AI agent over MCP, and read the transcripts back as JSON; see **Automation & AI agents** above.

**Do I need an Instagram or an AI account?** 🙅 Neither. Nothing is logged in, and the transcription engine
is provided by the Actor — you do not need your own API key.

**Which Reels get transcribed?** 🎞️ The videos of the accounts you give it: the Reels tab (the one page it
serves) up to **Max Reels per profile**, plus the timeline — paged until the cap is reached — if you turn
that on. Images have no speech and are skipped; a carousel contributes the first of its videos that has
sound.

**What about Reels that are only music, or have no sound?** 🎵 They produce a row with `hasSpeech: false`,
an empty `transcript`, and **no charge from this Actor**. A Reel posted without sound is recognised before
anything is downloaded; its row has `audioBytes: 0` and `transcriptModel: "none"`. A Reel whose transcription
failed has a `transcriptError` instead, and is not charged either.

**How accurate is the transcript?** 🎯 It is Whisper-class speech recognition on the original audio. Music,
heavy accents, overlapping speakers and very noisy scenes are where any engine struggles; `segments[]`
lets you spot and trim those. The filler such engines are known to invent over music or silence (a lone "Thank you.")
is recognised and dropped, and so are words guessed into sound the engine could not make out, such as a
stadium crowd, which it reports with very low confidence. A Reel with nothing else in it is reported as having
no speech — and not charged.

**Which languages does it transcribe, and can it translate?** 🌍 The speech model covers about 100
languages, Hindi, Spanish, Portuguese and Arabic among them. It returns the text in the language spoken
and names that language in `language`; it does not translate. If you know the language, set
**Language** to skip the guess.

**How long can a Reel be?** ⏱️ Reels are short by nature; the Actor handles them as they come.

**Can it read Stories or followers?** ❌ No. Instagram only serves those to logged-in users, and this Actor
deliberately stays logged out.

**The record says `transcriptError` — what happened?** ⚠️ The Reel was read but the transcription failed for
that one item. Anything that could have been a passing glitch — a rate limit, a server error, a timeout — is
retried by the Actor before the row is written, so what you see here is final for that Reel. Everything else
in the run is unaffected.

**A run returned 0 items — why?** 🤔 Usually the account is private, the link is wrong, or it has no videos.

***

### ⚠️ Notes and limitations

- 📖 Reads **publicly visible** Instagram Reels only, without logging in.
- 🚫 Not available without a login, and therefore not implemented: Stories, highlights, followers,
  following, hashtag pages, keyword search.
- 🎵 A Reel with only music, or without sound, has no transcript — that is a property of the Reel, not a
  failure.
- 🖼️ `audioUrl` is a signed link that expires. If you want the audio yourself, download it soon after the
  run.
- 🗣️ One transcript per Reel: the whole audio, no speaker separation.
- 🔁 **A retried request can leave a duplicate row.** If Instagram's answer to a record write is lost in
  transit and the request is retried, the same Reel can appear twice — the Actor cannot tell a lost
  acknowledgement from a lost write. Rare, but possible on a flaky connection.
- 💳 **A charge is per stored record, and this Actor's "not charged" for a silent Reel assumes the
  account's own per-item charging is off.** If the platform's default per-result event is priced on the
  account, every stored row is charged for it whatever this Actor's own events say.
- ⏳ Instagram changes its surface from time to time. The Actor runs a start-up check and fails loudly
  rather than returning empty results.

***

### 🧰 Other Actors by autofacts

Apify only auto-recommends Actors in the same category, so here are the ones that actually pair with this scraper:

| Actor | What it's for |
| :--- | :--- |
| [Instagram Scraper](https://apify.com/autofacts/instagram-scraper) | Profiles, posts and comments of the same accounts — tagged users, co-authors, topics and engagement, without transcription |
| [TikTok Subtitle & Transcript Scraper](https://apify.com/autofacts/tiktok-subtitle-transcript-scraper) | TikTok captions and transcripts |
| [YouTube Subtitle & Transcript Scraper](https://apify.com/autofacts/youtube-subtitle-transcript-scraper) | Video captions as clean text |
| [Google Trends Trending Now](https://apify.com/autofacts/google-trends-trending-now) | What is trending on Google right now, in 125 countries, to find the Reels worth transcribing |

All of them: [apify.com/autofacts](https://apify.com/autofacts)

***

### 💬 Feedback and support

Found a bug, or a Reel that transcribed badly? Open an issue on the Actor's page — it's read, and it's what
decides what gets built next.

# Actor input Schema

## `startUrls` (type: `array`):

Profile addresses (https://www.instagram.com/natgeo/) or Reel addresses (https://www.instagram.com/reel/…).

## `usernames` (type: `array`):

Profile names, with or without the @. Every video in their Reels tab is transcribed.

## `maxReelsPerProfile` (type: `integer`):

How many of each profile's videos to transcribe. Each one is a download plus a speech-to-text call, so this is also the cost control.

## `includeTimeline` (type: `boolean`):

Also transcribe videos from the profile's posts grid, not only its Reels tab.

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

Keep the per-segment timestamps (start, end, text). Turn off for a smaller record with just the full transcript.

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

Optional language hint for the transcription engine, e.g. en, es, pt. Leave empty to detect it.

## `maxConcurrency` (type: `integer`):

How many Reels to transcribe at once.

## `maxRequestsPerCrawl` (type: `integer`):

Stop after this many requests. Empty means no limit.

## `proxy` (type: `object`):

Instagram answers a logged-out reader far more readily from a residential address, so Apify Proxy's RESIDENTIAL group is selected here and is also what a run gets when the field is left out. It is used for reading Instagram; audio files are downloaded without it unless a download fails.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.instagram.com/natgeo/"
    }
  ],
  "maxReelsPerProfile": 10,
  "includeTimeline": false,
  "includeSegments": true,
  "maxConcurrency": 3,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

One row per Reel: the transcript, its timed segments and the language, with the caption, hashtags, mentions and engagement. A Reel with only music or noise, or with no sound, has a row with hasSpeech false; one that could not be transcribed says why in transcriptError.

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

How the run went: how many Reels were stored, how many had speech, had none or had no sound, how many could not be transcribed, how many requests were handled, failed or left pending, and whether it stopped at the maximum charge you set.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.instagram.com/natgeo/"
        }
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("autofacts/instagram-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 = {
    "startUrls": [{ "url": "https://www.instagram.com/natgeo/" }],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("autofacts/instagram-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 '{
  "startUrls": [
    {
      "url": "https://www.instagram.com/natgeo/"
    }
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call autofacts/instagram-transcript-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,autofacts/instagram-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/6dJSw7lJExE2AzE0O/builds/1zG6LZ1TfXEOHRwwZ/openapi.json
