The short answer
Instagram has no button or API that gives the text of an account's reels. Give the account to our Instagram Transcript Scraper: it reads the latest posts Instagram shows, skips the photos, and transcribes each video in the language spoken. A short Python script then saves a text file and an SRT subtitle file per reel, with an index in CSV. The latest 6 posts of @bbcnews took a 30-second call and cost $0.04: 5 transcripts, and 1 reel without speech, free.
What you can and cannot read on an account
Without signing in, Instagram shows the 12 latest posts of a public account, pinned posts first. That is what the scraper reads; no tool that stays signed out sees further back. Older reels can still be transcribed one by one from their links. Meta's own API does not help here: it serves professional accounts their own media, and no transcript at all (details in our guide on Instagram transcripts).
| Setting | What it does |
|---|---|
urls | Accounts as @bbcnews, https://www.instagram.com/bbcnews/ or …/bbcnews/reels/, mixed with reel and post links. |
maxVideosPerAccount | How many videos to take from each account, newest first: 12 by default. Photo posts do not count. |
includeSrt, includeVtt | Add the transcript as an SRT or WebVTT subtitle file to each record. |
language | A preference, never a translation: a reel in another language comes back in its own, flagged. |
maxDurationMinutes | Skip videos longer than this, before anything is transcribed (30 by default). |
A carousel with several videos gives one record per video, numbered by carouselIndex. A reel found both in an account and as a link is transcribed and charged once.
A text and a subtitle file per reel, in Python
import csv
import pathlib
from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("quarra/instagram-transcript-scraper").call(run_input={
"urls": ["@bbcnews"],
"maxVideosPerAccount": 6,
"includeSrt": True,
})
folder = pathlib.Path("bbcnews")
folder.mkdir(exist_ok=True)
reels = list(client.dataset(run.default_dataset_id).iterate_items())
reels.sort(key=lambda r: (r.get("position") or 0, r.get("carouselIndex") or 0)) # records arrive as reels finish
with open(folder / "index.csv", "w", newline="", encoding="utf-8") as f:
w = csv.writer(f)
w.writerow(["videoId", "publishedAt", "durationSeconds", "language", "wordCount", "likeCount", "status", "caption"])
for r in reels:
if r["status"] == "ok":
name = r["videoId"] + (f"-{r['carouselIndex']}" if r.get("carouselIndex") else "")
(folder / f"{name}.txt").write_text(r["transcript"], encoding="utf-8")
(folder / f"{name}.srt").write_text(r["srt"], encoding="utf-8")
w.writerow([r.get("videoId"), r.get("publishedAt"), r.get("durationSeconds"), r.get("language"),
r.get("wordCount"), r.get("likeCount"), r.get("missingReason") or r["status"],
(r.get("caption") or "")[:100]])
print(run.status, len(reels), "reels ->", folder.resolve())
Tested with apify-client 3.3 on October 10, 2026, in a 30-second call. It wrote 5 text files, 5 SRT files and this index:
| Reel | Length | Words | Likes | Status |
|---|---|---|---|---|
| Here's what we know so far about the death of a man who entered a tiger enclosure… | 44 s | 118 | 1,894 | ok |
| Have you heard of the Help to Save scheme? | 65 s | 220 | 818 | ok |
| “I was encouraged whenever I made a mistake to jump up and try again.” | 41 s | 145 | 602 | ok |
| Is Zack Polanski in control of the Green Party? | 36 s | 104 | 421 | ok |
| Sara Sharif's paternal grandfather has been granted guardianship of her siblings… | 90 s | 289 | 2,144 | ok |
DeUfH5UEQ-b | 15 s | no_speech, free |
On that last reel, plain Whisper writes “Thank you.”: the phrase it tends to invent on music. A reel without a transcript keeps its row in the index, with its reason and no file. With apify-client 2.x, write run["defaultDatasetId"] instead of run.default_dataset_id.
The start of the first SRT file, ready to edit or to upload as captions:
1
00:00:00,000 --> 00:00:06,000
Somehow a man got into the enclosure of Yorkshire Wildlife Park's land of the tigers
2
00:00:06,000 --> 00:00:10,800
with a 300m long raised walkway above allowing visitors to get close enough
Keep up with an account
Schedule the Actor on Apify with the same input, daily for example, and keep the reels you have not seen yet: the videoId of each record is stable, so a set of the IDs already saved is enough. Each run costs the transcripts of the reels it reads, so set maxVideosPerAccount to what an account posts between two runs.
Limits
- 12 latest posts per account, the most Instagram shows without signing in. No stories, highlights, tagged posts or hashtag pages.
- The no-speech check keeps a margin: a short exclamation, distant speech or a narration over loud music can come back as
no_speech, free. In our tests, a documentary trailer narrated over loud music was one of them. - Instagram hides play counts from visitors who are not signed in:
viewCountis usually empty. Likes and comments are there. - Private accounts and age-restricted reels need a signed-in account; we do not use one, so they come back as free error records.
What it costs
$0.001 per transcript plus $0.0045 per started minute of video on Apify's free plan ($0.0034 a minute on Gold and above), and a start fee of $0.004 per run at the default memory. A 40-second reel costs $0.0055. The 6 posts of @bbcnews above cost $0.04: 5 transcripts, 7 minutes, the start fee; the reel without speech was free. Apify's free plan includes $5 of usage a month.
Run it on the Apify Store
Transcripts cost $0.001 each plus $0.0045 per started minute of video on the Free plan (less on paid plans), plus $0.004 per run; reels without speech are free. Errors and empty results are not charged, and you can set a maximum cost per run.