# Instagram Transcript API & Profile Scraper - AI Video to Text (`scraper-engine/instagram-transcript-profile-scraper`) Actor

Instagram Transcript API & Profile Scraper extracts public profile details and converts video content into text transcripts. Collect captions, creator data, video metadata, and transcripts for content research, SEO, AI analysis, and lead generation.

- **URL**: https://apify.com/scraper-engine/instagram-transcript-profile-scraper.md
- **Developed by:** [Scraper Engine](https://apify.com/scraper-engine) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

### Instagram Transcript API & Profile Scraper - AI Video to Text

Turn any public Instagram Reel or video URL into a clean, timestamped transcript, and turn any public username into structured post data — both as typed JSON. The Actor extracts `text`, `segments`, `caption`, `likeCount`, `hashtags`, and `videoUrl` with no login and no third-party transcription API. Transcription runs locally with Whisper AI, and profile posts are pulled straight from Instagram's public feed. Paste a URL or username below and start a run to see the dataset fill in live.

### 🤔 What is the Instagram Transcript API & Profile Scraper?

It is a dual-mode Apify Actor: point it at Reel/video URLs and it downloads the audio and transcribes it locally with Whisper AI; point it at usernames and it paginates that profile's public post feed into structured JSON. Both modes can run in the same job. No Instagram account, login, cookie, or API token is required for either flow — the transcript path is re-verified as zero-secret at the start of every run, and the profile flow pulls its session values from a public, unauthenticated page fetch. It's built for developers, AI/ML engineers, and researchers or marketers who need Instagram video and post data as clean JSON instead of scraping HTML by hand.

### 🔓 What Instagram data is publicly available to scrape?

Everything this Actor returns — Reel captions, engagement counts, media URLs, creator identity, and a profile's recent public posts — is visible to any logged-out visitor on instagram.com; nothing behind a login wall is accessed.

| Data category | Publicly available (no login) | Restricted (requires login as the account) |
| --- | --- | --- |
| Reel/video caption & spoken-audio transcript | Caption yes; transcript is generated locally by this Actor, not scraped from Instagram | — |
| Video/audio download URLs | Yes (`videoUrl`, `audioUrl`) | — |
| Creator identity (username, full name, avatar) | Yes | — |
| Profile's recent public posts (caption, media, engagement) | Yes, via the anonymous feed endpoint | — |
| Hashtags & @mentions in a caption | Yes (parsed from `caption`) | — |
| Pinned-post flag | Yes (post-level metadata) | — |
| Share/reshare count | Not exposed at all by Instagram's anonymous feed API — this Actor reports `0` rather than guessing | — |
| Private-account posts, Stories, DMs, full follower/following lists | — | Yes — requires logging in as the account owner; this Actor never does this |

This Actor only returns publicly visible data — what any visitor sees. Nothing behind a login wall.

### 📊 What data can I extract with this Actor?

Every run returns one dataset item per processed Reel/video or per scraped profile post, discriminated by an `itemType` field — the field groups below cover every key the Actor actually writes to the dataset, not just the default view columns.

#### 🎬 Reel/video identity & media fields (transcript flow)

| Field name | Description |
| --- | --- |
| `itemType` | `"transcript"` for a Reel/video record |
| `url` | The input Reel/video URL |
| `code` | Instagram media shortcode |
| `pk` | Instagram internal post ID |
| `id` | Instagram media ID |
| `title` | The post's caption text |
| `img` | Thumbnail/preview image URL (only when `includeImg` is enabled) |
| `videoUrl` | Direct progressive MP4 URL, highest resolution available |
| `audioUrl` | Direct audio-only DASH track URL |
| `userPk` | Creator's Instagram user ID |
| `userName` | Creator's username |
| `userFullName` | Creator's display name |
| `avatarUri` | Creator's avatar image URL |

#### ⏱️ Reel/video engagement, transcript & timing fields

| Field name | Description |
| --- | --- |
| `duration` | Video duration in seconds |
| `createTime` | Post creation time (Unix timestamp) |
| `likeCount` | Like count |
| `commentCount` | Comment count |
| `text` | Full transcript text, generated locally by Whisper AI |
| `segments` | Array of `{start, end, text}` timestamped transcript segments (present when `includeSegments` is enabled — on by default) |
| `errMsg` | Empty string on success; otherwise the reason this Reel/video could not be transcribed |
| `timestamp` | When this record was processed, ISO 8601 |

#### 👤 Profile post fields (usernames flow)

| Field name | Description |
| --- | --- |
| `itemType` | `"profile_post"` for a profile-scrape record |
| `id` / `pk` | Instagram post ID |
| `type` | `Image`, `Video`, or `Album` |
| `shortCode` | Instagram media shortcode |
| `caption` | Post caption text |
| `url` | Canonical `instagram.com/p/<code>/` post URL |
| `commentsCount` | Comment count |
| `likeCount` | Like count |
| `dimensionsHeight` / `dimensionsWidth` | Media dimensions in pixels |
| `displayUrl` | Cover/display image URL |
| `images` | Array of image URLs (Album posts only) |
| `childPosts` | Array of carousel child items — `type`, `dimensionsHeight`, `dimensionsWidth`, `displayUrl`, `alt`, `id`, `pk`, plus `videoUrl`/`videoDuration` on video children |
| `videoUrl` | Direct video URL (Video posts only) |
| `audioUrl` | Always `""` for profile-post records — not carried over from the feed API by design |
| `videoPlayCount` | Video play count (Video posts only) |
| `videoDuration` | Video duration in seconds (Video posts only) |
| `timestamp` | Post creation time (Unix timestamp, as a string) |
| `ownerId` / `ownerUsername` / `ownerFullName` / `ownerProfilePicUrl` | Post owner's identity fields |
| `productType` | Instagram's internal product-type label for the post |
| `isCommentsDisabled` | Whether comments are disabled on the post |
| `inputUrl` | The username/profile URL you requested that produced this row |
| `alt` | Accessibility alt text, if Instagram generated one |
| `artist_name` / `song_name` | Audio track artist/title, when the post carries music metadata |
| `should_mute_audio` / `should_mute_audio_reason` | Instagram's own audio-mute flag and reason, when present |
| `audio_id` | Audio asset ID, when present |
| `hashtags` / `mentions` | Arrays of `#hashtag` / `@mention` strings parsed out of `caption` |
| `sharesCount` | Only present when `includeSharesCount` is enabled; always `0` — not exposed by the anonymous feed API |
| `errMsg` | Empty string on success; populated once per username if that target could not be resolved or scraped at all |

#### 🤖 Add-on: Need similar data from other platforms?

This Actor is Instagram-only. If your pipeline spans other short-form video or profile platforms, the same account also publishes **TikTok Posts Scraper** and **Best TikTok AI Transcript Extractor** for TikTok, plus **LinkedIn People Profile Scraper** and **Twitter X Profile Viewer** for professional and X/Twitter profile data — all returning the same kind of typed, structured JSON.

### 🆚 How does this Actor differ from the official Instagram API?

Meta's Instagram Platform (Graph) API is scoped to the app user's own connected professional account, with only a few limited public endpoints, and requires Advanced Access plus business verification to serve accounts you don't own or manage — per Meta's Instagram Platform documentation (developers.facebook.com/docs/instagram-platform/overview, checked 2026-09-03). This Actor instead runs against any public Reel/video URL or public username you supply.

| Feature | Instagram Graph API | This Actor |
| --- | --- | --- |
| Account type required | Instagram professional (business/creator) account | None — no Instagram account of any kind |
| Access to accounts you don't own | Requires Advanced Access + business verification | Yes, for any public username, by default |
| App review process | Required for Advanced Access | None — run immediately from the Store |
| Video/audio transcription | Not offered | Built in, via local Whisper AI |
| Setup | Register a Meta developer app, link a professional account, request review | Provide URLs/usernames and click Start |
| Output | Versioned Graph API JSON, scoped to granted permissions | Stable typed JSON dataset, same shape every run |

Use the Graph API when you manage the Instagram account yourself and need to publish, moderate, or read insights on your own content within Meta's terms. Use this Actor when you need transcripts of arbitrary public Reels or bulk public post metadata from accounts you don't manage.

### 🚀 How to use this Actor

This Actor runs on the Apify platform — there's no separate signup, API key, or Instagram login to obtain before your first run.

1. Open **Instagram Transcript API & Profile Scraper - AI Video to Text** on its Apify Store page and click **Try for free** (or **Run**, if you already have it in your Console).
2. Provide input: paste Reel/video URLs into `bulkUrls` (or one URL into `videoUrl`) for transcripts, and/or usernames into `usernames` for profile posts. No single field is strictly required by the schema — at least one of the three must be filled in, or the run exits with a warning and does nothing.
3. Optionally set filters: `resultsLimit` and `onlyPostsNewerThan` for profile scraping, `whisperModel` and `language` for transcription, `skipPinnedPosts` to drop pinned posts.
4. Click **Start**.
5. Open the **Output** tab, pick a view (Overview / Transcripts / Transcript Segments / Profile Posts), and export the results as JSON or CSV.

#### Scaling to bulk transcript & profile extraction

Both entry points are array inputs, not single fields: `bulkUrls` accepts any number of Reel/video URLs one per line, and `usernames` accepts any number of usernames or profile URLs — both processed in the same run, up to the `concurrency` setting. On the FREE `userTier`, `bulkUrls` is capped at `freeBulkUrlsLimit` (default 5); set `userTier` to `paid` to remove that cap. There's no separate bulk-mode toggle — arrays are simply how bulk works.

### 🎯 What can you do with Instagram Reel & profile data?

- A **content repurposing editor** uses `text` and `segments` from a Reel's transcript to auto-generate subtitles and blog drafts from video content, without re-watching every clip.
- A **competitor researcher** uses `caption`, `hashtags`, and `likeCount` from `usernames` results to track a rival account's messaging and engagement trends over time.
- A **growth marketer** uses `videoPlayCount`, `videoDuration`, and `ownerUsername` from profile posts to benchmark a creator's short-form video cadence.
- A **researcher** building a text corpus uses `text`, `userName`, and `createTime` to compile a timestamped, citable dataset of spoken Reel content.
- An **AI engineer** feeds `text` (transcript) and `caption` (profile post) into a RAG pipeline as retrievable context chunks, using `url` as the citation source — the typed JSON drops straight into a vector store or an agent's tool response with no HTML parsing.

### 🛡️ How does this Actor handle rate limits and blocking?

Every request starts with no proxy at all. If Instagram returns a block signal (HTTP 403/429), the Actor escalates through Apify Proxy tiers — no proxy → Datacenter → Residential — retrying once per tier before moving up; once it reaches Residential, it stays there for every remaining request in the run rather than retreating. Once already on Residential (or a user-supplied custom proxy), a further block is retried up to 3 more times on that tier before giving up on that item. Ordinary server errors (500/502/503/504) are retried up to `maxRetries` times with backoff, independent of the block-escalation ladder. A polite `requestDelay` (plus random jitter) is applied before every fetch. If a run hits 12 consecutive transport failures, it stops issuing new requests entirely — a signal of a dead network/proxy path, not empty results — while keeping whatever was already saved. Any Reel/video or profile that ultimately fails still produces a dataset record with a populated `errMsg` instead of silently vanishing from your results.

### ⬇️ Input

At least one of `bulkUrls`, `videoUrl`, or `usernames` should be filled in — none is individually required by the schema, but a run with all three empty exits immediately with a warning.

| Parameter | Required | Type | Description | Example value |
| --- | --- | --- | --- | --- |
| `bulkUrls` | No | array | Public Reel/video/post URLs to transcribe, one per line. FREE tier is capped at `freeBulkUrlsLimit`. | `["https://www.instagram.com/reel/DXtvzz7B3dC/"]` |
| `videoUrl` | No | string | A single Reel/video/post URL for a quick test run alongside or instead of `bulkUrls`. | `""` |
| `userTier` | No | string | Default `"free"`. Enum: `"free"`, `"paid"`. `free` caps `bulkUrls` at `freeBulkUrlsLimit`; `paid` removes the cap. | `"free"` |
| `freeBulkUrlsLimit` | No | integer | Default `5`, min `1`, max `10000`. Max `bulkUrls` processed per run on the FREE tier; extras are skipped with a log warning. | `5` |
| `usernames` | No | array | Public usernames or profile URLs to scrape recent posts from. This mode returns post metadata only, no transcripts. | `["bbcnews"]` |
| `resultsLimit` | No | integer | Default `10`, min `0`. Stop collecting posts for a profile after this many; `0` means unlimited, subject to `maxScanned`. | `10` |
| `onlyPostsNewerThan` | No | string | Accepts `YYYY-MM-DD`, a full ISO timestamp, or a relative value like `1 day` / `2 weeks` / `3 months` / `1 year`, evaluated in UTC. Empty = no date filter. | `"2 weeks"` |
| `skipPinnedPosts` | No | boolean | Default `false`. Exclude posts pinned to the top of the profile grid. | `false` |
| `includeSharesCount` | No | boolean | Default `false`. Attempt a share/reshare count per post; Instagram's public feed does not expose it, so it is emitted as `0` with a log warning rather than guessed. | `false` |
| `maxScanned` | No | integer | Default `2000`, min `50`, max `20000`. Hard ceiling on raw posts examined per username before giving up. | `2000` |
| `whisperModel` | No | string | Default `"base"`. Enum: `"tiny"`, `"base"`, `"small"`, `"medium"`. Local speech-to-text model size — bigger is more accurate but slower. | `"base"` |
| `language` | No | string | ISO 639-1 code (e.g. `en`, `es`, `fr`) to force Whisper's spoken-language detection. Empty = auto-detect. | `""` |
| `includeSegments` | No | boolean | Default `true`. Include the full array of timestamped `{start, end, text}` transcript segments. | `true` |
| `includeImg` | No | boolean | Default `false`. Include a thumbnail/preview image URL per transcribed Reel/video. | `false` |
| `proxyConfiguration` | No | object | Default connects with no proxy; auto-escalates No proxy → Datacenter → Residential on a block, retried up to 3× on Residential. Can be set to force a tier. | `{"useApifyProxy": false}` |
| `concurrency` | No | integer | Default `5`, min `1`, max `10`. How many Reels/profiles are processed in parallel. | `5` |
| `requestDelay` | No | number | Default `1.0`, min `0`, max `10`. Delay in seconds (plus jitter) before every page fetch. | `1.0` |
| `maxRetries` | No | integer | Default `3`, min `1`, max `10`. Retries per request before giving up (each may also trigger a proxy escalation). | `3` |

#### Example input

```json
{
  "bulkUrls": ["https://www.instagram.com/reel/DXtvzz7B3dC/"],
  "videoUrl": "",
  "userTier": "free",
  "freeBulkUrlsLimit": 5,
  "usernames": ["bbcnews"],
  "resultsLimit": 10,
  "onlyPostsNewerThan": "2 weeks",
  "skipPinnedPosts": false,
  "includeSharesCount": false,
  "maxScanned": 2000,
  "whisperModel": "base",
  "language": "",
  "includeSegments": true,
  "includeImg": false,
  "proxyConfiguration": { "useApifyProxy": false },
  "concurrency": 5,
  "requestDelay": 1.0,
  "maxRetries": 3
}
```

### ⬆️ Output

Every processed Reel/video or scraped profile post is pushed to the dataset the instant it's ready, as typed, normalized JSON — no batching, so an interrupted run still leaves a usable partial dataset. Browse it as one of four Console views (Overview, Transcripts, Transcript Segments, Profile Posts), the full unfiltered record set, or export the whole dataset as CSV.

#### Example output

Transcript-flow record:

```json
{
  "itemType": "transcript",
  "url": "https://www.instagram.com/reel/DXtvzz7B3dC/",
  "code": "DXtvzz7B3dC",
  "pk": "3885972322121119554",
  "id": "POLARIS_3885972322121119554",
  "title": "A quick look behind the scenes of today's shoot...",
  "img": "",
  "videoUrl": "https://instagram.fxyz1-1.fna.fbcdn.net/o1/v/t2/f2/m86/reel.mp4",
  "audioUrl": "https://instagram.fxyz1-1.fna.fbcdn.net/o1/v/t2/f2/m86/reel-audio.mp4",
  "duration": 59.9,
  "createTime": 1777464000,
  "likeCount": 62114,
  "commentCount": 6692,
  "userPk": "1501333655",
  "userName": "examplecreator",
  "userFullName": "Example Creator",
  "avatarUri": "https://scontent.cdninstagram.com/v/t51/example-avatar.jpg",
  "text": "Excuse me, miss. This briefcase needs to get to the studio by six...",
  "segments": [
    { "start": 0.3, "end": 1.16, "text": " Excuse me, miss." },
    { "start": 1.16, "end": 3.42, "text": " This briefcase needs to get to the studio by six." }
  ],
  "errMsg": "",
  "timestamp": "2026-09-03T10:00:00.000Z"
}
```

Profile-post record:

```json
{
  "itemType": "profile_post",
  "id": "3976434829319475479",
  "pk": "3976434829319475479",
  "type": "Video",
  "shortCode": "DcvImjCFBEX",
  "caption": "Breaking coverage from the ground, more updates through the day. #BreakingNews #Live",
  "url": "https://www.instagram.com/p/DcvImjCFBEX/",
  "commentsCount": 35,
  "dimensionsHeight": 1920,
  "dimensionsWidth": 1080,
  "displayUrl": "https://instagram.fxyz1-1.fna.fbcdn.net/o1/v/t2/f2/m86/cover.jpg",
  "images": [],
  "childPosts": [],
  "videoUrl": "https://instagram.fxyz1-1.fna.fbcdn.net/o1/v/t2/f2/m86/post.mp4",
  "audioUrl": "",
  "likeCount": 1306,
  "timestamp": "1788248045",
  "ownerId": "16278726",
  "ownerUsername": "bbcnews",
  "ownerFullName": "BBC News",
  "ownerProfilePicUrl": "https://scontent.cdninstagram.com/v/t51/bbc-avatar.jpg",
  "productType": "clips",
  "isCommentsDisabled": false,
  "inputUrl": "bbcnews",
  "alt": "",
  "videoPlayCount": 214500,
  "videoDuration": 42.3,
  "artist_name": "",
  "song_name": "",
  "should_mute_audio": false,
  "should_mute_audio_reason": "",
  "audio_id": "",
  "hashtags": ["#BreakingNews", "#Live"],
  "mentions": [],
  "errMsg": ""
}
```

### ⚙️ How does it work?

For transcripts, the Actor fetches the Reel/post page with a browser-impersonated HTTP client — no headless browser — because the page already carries a server-rendered JSON blob with the media URLs, caption, and engagement counts. It downloads the audio track and transcribes it locally with Whisper AI (`faster-whisper`, running on CPU); nothing is sent to a third-party transcription service. For profiles, it paginates Instagram's own public, anonymous post-feed endpoint page by page, applying your date/pinned filters. Both parsers locate data by shape (recursively, by key names) rather than a fixed DOM path or array index, so the output schema stays stable even if Instagram reshuffles its page structure. Only publicly visible data is ever returned.

### 🔌 Integrations

This Actor is a standard Apify Actor, so it works with everything already built around the Apify platform: the API/SDK for your own code, Apify's MCP server for AI agents, and no-code automation tools.

#### Calling this Actor programmatically

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("<YOUR_APIFY_USERNAME>/instagram-transcript-profile-scraper").call(
    run_input={
        "bulkUrls": ["https://www.instagram.com/reel/DXtvzz7B3dC/"],
        "usernames": ["bbcnews"],
        "resultsLimit": 10,
    }
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

Works in Go, Ruby, Node.js, cURL — any language that can make an HTTP request.

#### MCP integration for AI agents

This Actor is callable through Apify's MCP server without any code of its own. Point an MCP client at `https://mcp.apify.com` (OAuth sign-in, or a bearer token in the `Authorization` header) and scope it to this Actor with `?tools=<your-apify-username>/instagram-transcript-profile-scraper`. Compatible with any MCP-aware client, including Claude Desktop and Claude Code.

#### No-code tools (n8n, Make, LangChain)

In **n8n**, call this Actor's run-sync endpoint with the HTTP Request node (or Apify's own node) to drop transcripts and profile posts straight into your workflow. In **Make**, use Apify's Run Actor module inside a scenario to trigger a run and pass its dataset items to the next step. In **LangChain**, wrap the Actor as a tool via Apify's LangChain integration (`ApifyWrapper`) so an agent can request a transcript or profile scrape as part of its own reasoning loop.

### ⚖️ Is it legal to scrape Instagram Reels and profiles?

Scraping publicly available data is generally lawful, and this Actor only returns data any logged-out visitor can already see on instagram.com — it never accesses private accounts or bypasses a login. Because profile-post records include personal data (usernames, full names, avatar images, captions), GDPR and CCPA govern how you may store and use that data if your users or use case fall under those regimes — you need a lawful basis for collection and a defined retention/use policy, not just the ability to fetch it. ⚠️ Consult legal counsel if your use case involves bulk storage of personal data.

### ❓ Frequently asked questions

#### What Instagram fields does this Actor return?

The top fields are `text` and `segments` for transcripts, and `caption`, `likeCount`, and `hashtags` for profile posts — see the [full field tables](#-what-data-can-i-extract-with-this-actor) above for everything else the Actor writes.

#### Does this Actor require an Instagram account or login?

No. Neither flow needs a login, cookie, or API token — the transcript path is re-verified as zero-secret at the start of every run, and the profile flow gets its session values from an unauthenticated public page fetch.

#### How many Reels or profiles can I process in one run?

`bulkUrls` and `usernames` both accept arrays, so you can queue as many as you like in one job; on the FREE `userTier`, `bulkUrls` is capped at `freeBulkUrlsLimit` (default 5) — switch to `paid` for an unlimited bulk list. Posts per username are separately capped by `resultsLimit` (default 10, or 0 for unlimited up to `maxScanned`).

#### What happens if a Reel is private, deleted, or not found?

The record is still saved, with `errMsg` set to something like `"Media not found or not public"` and every other field left empty — the item is never silently dropped from your dataset.

#### What happens if a profile is private, doesn't exist, or has no matching posts?

If the username can't be parsed or no session token could be obtained, one error record is returned with `errMsg` populated. If the profile is valid but simply has 0 posts matching your date/pinned filters, no records are returned for that username and the run log notes it.

#### Can I scrape multiple Instagram Reels and profiles at once?

Yes — `bulkUrls` and `usernames` are both list inputs, and every entry across both is processed within the same job, subject to the `concurrency` setting.

#### Does this Actor work with Claude, ChatGPT, and other AI agent tools?

Yes. It's reachable through Apify's MCP server (`https://mcp.apify.com`) for MCP-aware clients, and callable as a plain HTTP endpoint by any agent framework that can make a REST call.

#### Does this Actor use a third-party transcription API?

No. Transcription runs locally with `faster-whisper` inside the Actor's own container — no external transcription service is called and no separate API key is needed for it.

#### Does this Actor return data in a format LLMs can use directly?

Yes. Every record is typed, normalized JSON with consistent field names across runs — no HTML parsing or selectors involved. Pass it directly to an LLM, index it into a vector store, or feed it to an agent tool.

#### What happens when Instagram changes its layout or anti-bot system?

Both parsers locate data by shape (key names, not fixed positions), so a reshuffled page structure often doesn't break extraction. The Actor also re-checks the zero-secret transcript path at the start of every run and logs a warning if Instagram starts embedding signed-request token signatures, so a real breaking change surfaces in the run log rather than silently.

#### Can I use this Actor without managing proxies or browser infrastructure?

Yes. There's no headless browser to configure, and proxy tier selection and escalation (No proxy → Datacenter → Residential) is handled automatically — you can still force a specific tier through `proxyConfiguration` if you want to.

#### Which fields work best for AI training data and RAG indexing?

For RAG, index `text` (transcript flow) and `caption` (profile-post flow) as your retrievable content, with `url` as the citation source. For training data, `userName`/`ownerUsername`, `likeCount`, and `timestamp` return as consistently typed primitives across every record.

### 🔗 Related scrapers

| Scraper | What it extracts |
| --- | --- |
| Best TikTok AI Transcript Extractor | Local AI transcripts from public TikTok videos |
| TikTok Posts Scraper | Public TikTok profile posts and engagement metadata |
| TikTok Keyword Search Scraper | TikTok search results by keyword |
| LinkedIn People Profile Scraper | Public LinkedIn profile data |
| Twitter X Profile Viewer | Public X/Twitter profile data |

### 🛟 Your feedback

Found a bug or missing a field? Email **dev.scraperengine@gmail.com** with your run ID and what you expected — this Actor is actively maintained and field-level reports are the fastest way to get something fixed or added.

# Actor input Schema

## `bulkUrls` (type: `array`):

🎞️ One or more public Instagram Reel, video, or post URLs to transcribe — e.g. <code>https://www.instagram.com/reel/DXtvzz7B3dC/</code>. Paste as many as you like, one per line. 🆓 FREE tier is capped at 5 URLs per run (see below) — 💎 switch to PAID tier for unlimited bulk transcription.

## `videoUrl` (type: `string`):

⚡ A single Instagram Reel/video/post URL — handy for a quick one-off test run alongside (or instead of) the bulk list above.

## `userTier` (type: `string`):

🆓 <b>free</b> caps bulk transcription at the limit below. 💎 <b>paid</b> removes the cap for unlimited bulk transcription in one run.

## `freeBulkUrlsLimit` (type: `integer`):

🚧 Maximum number of `bulkUrls` processed per run while on the FREE tier. Extra URLs beyond this are skipped with a clear log warning.

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

📇 One or more public Instagram usernames (or full profile URLs) to scrape recent posts from — e.g. <code>bbcnews</code> or <code>https://www.instagram.com/bbcnews/</code>. This mode returns post metadata and does NOT generate transcripts.

## `resultsLimit` (type: `integer`):

🛑 Stop collecting posts for a profile after this many. Set to <b>0</b> for unlimited (subject to the safety scan cap below).

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

⏳ Only collect posts published on/after this point in time. Accepts <code>YYYY-MM-DD</code>, a full ISO timestamp, or a relative value like <code>1 day</code>, <code>2 weeks</code>, <code>3 months</code>, <code>1 year</code>. All evaluated in UTC. Leave empty for no date filter.

## `skipPinnedPosts` (type: `boolean`):

🙈 Exclude posts pinned to the top of the profile grid from the results — useful when you only want naturally recent content.

## `includeSharesCount` (type: `boolean`):

💰 Attempt to include a share/reshare count per post. ⚠️ Honestly reported: Instagram's public anonymous feed does not expose this value, so it is emitted as <code>0</code> with a clear log warning rather than being guessed.

## `maxScanned` (type: `integer`):

🛡️ Hard ceiling on how many raw posts are examined per username before giving up — protects against runaway runs when filters (date/pinned) reject almost everything.

## `whisperModel` (type: `string`):

🎚️ Local speech-to-text model size. Bigger models are more accurate but slower and use more memory. <b>base</b> is the sweet spot for most Reels.

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

🈯 ISO 639-1 language code (e.g. <code>en</code>, <code>es</code>, <code>fr</code>) to force Whisper to a specific spoken language. Leave empty for automatic language detection.

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

⏱️ Include the full array of timestamped transcript segments (<code>start</code>/<code>end</code>/<code>text</code>) — ideal for subtitles, captions, and clipping workflows.

## `includeImg` (type: `boolean`):

🖌️ Include a preview/thumbnail image URL for each transcribed Reel/video.

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

🌍 By default the Actor connects with <b>NO proxy</b> for maximum speed. If Instagram rejects or blocks a request, it automatically escalates: ⚡ No proxy → 🏢 Datacenter proxy → 🏠 Residential proxy (retried up to 3×) — then sticks with Residential for the rest of the run. You can also force a tier yourself here.

## `concurrency` (type: `integer`):

🏎️ How many reels/profiles to process at the same time. Higher = faster, but more likely to trigger Instagram rate limits.

## `requestDelay` (type: `number`):

🐢 A polite pause (plus random jitter) before every page fetch. Raise this if you're seeing blocks; lower it for smaller, faster runs.

## `maxRetries` (type: `integer`):

💪 How many times to retry a blocked/failed request before giving up (each retry may also trigger a proxy tier escalation — see Proxy configuration above).

## Actor input object example

```json
{
  "bulkUrls": [
    "https://www.instagram.com/reel/DXtvzz7B3dC/"
  ],
  "userTier": "free",
  "freeBulkUrlsLimit": 5,
  "usernames": [
    "bbcnews"
  ],
  "resultsLimit": 10,
  "skipPinnedPosts": false,
  "includeSharesCount": false,
  "maxScanned": 2000,
  "whisperModel": "base",
  "includeSegments": true,
  "includeImg": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "concurrency": 5,
  "requestDelay": 1,
  "maxRetries": 3
}
```

# Actor output Schema

## `overview` (type: `string`):

All records (transcripts + profile posts) with the most important columns.

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

Reel/video transcript records — full text, media URLs, and creator/engagement metadata.

## `segments` (type: `string`):

One row per timestamped transcript segment — ready for subtitles and captions.

## `profilePosts` (type: `string`):

Public post records collected from scraped profiles.

## `fullRecord` (type: `string`):

Every field, unfiltered, exactly as pushed to the dataset.

## `csv` (type: `string`):

The full result set as a CSV file.

# 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 = {
    "bulkUrls": [
        "https://www.instagram.com/reel/DXtvzz7B3dC/"
    ],
    "videoUrl": "",
    "usernames": [
        "bbcnews"
    ],
    "language": "",
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scraper-engine/instagram-transcript-profile-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 = {
    "bulkUrls": ["https://www.instagram.com/reel/DXtvzz7B3dC/"],
    "videoUrl": "",
    "usernames": ["bbcnews"],
    "language": "",
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("scraper-engine/instagram-transcript-profile-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 '{
  "bulkUrls": [
    "https://www.instagram.com/reel/DXtvzz7B3dC/"
  ],
  "videoUrl": "",
  "usernames": [
    "bbcnews"
  ],
  "language": "",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call scraper-engine/instagram-transcript-profile-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scraper-engine/instagram-transcript-profile-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/RbrPXRILigFtt3C0J/builds/rC7DMexB9Xp5ro6Xh/openapi.json
