Scrape and download public Facebook Reels in bulk from any page or profile: direct MP4 URLs, view counts, play time, audio track, verified-author flag. Optional enrich (likes, comments, shares, HD/SD URLs), transcripts, date filter. No login, no cookies, no proxies. JSON/CSV/Excel.
All notable changes to the Facebook Reels Scraper (unseenuser/fb-reels) are documented here.
The format is loosely based on Keep a Changelog , and versions follow the version field in .actor/actor.json.
[2.0] - 2026-09-09
Major feature release. Comments, translation, four dedicated sub-datasets, an optional pay-per-event pricing model, richer derived fields, and a friendlier input schema.
Added
Comments feature (default OFF): fetch public comments and optional replies for each reel into a dedicated comments sub-dataset. New inputs: fetchComments, maxCommentsPerReel (0 = all), fetchCommentReplies, maxRepliesPerComment (0 = all). Replies land in the same sub-dataset with parent_comment_id filled.
Translation add-on: translate transcripts into any of 100 languages using OpenAI gpt-4o-mini. Bring your own OpenAI API key (never logged or stored, redacted from every error message). New inputs: translateTo, openaiApiKey. Only fires when a transcript exists.
Author / page profile add-on (enrichAuthorProfile, default ON): follower count, category, is-running-ads flag from Meta Ad Library, business hours, contact info (email, phone, website, address), rating, creation date. Charged once per unique page URL, not per reel.
audio_tracks sub-dataset: one row per unique audio track found across the run (deduped by music.id, falling back to music.track_title). Views: Trending sounds, Album art gallery.
authors sub-dataset: one row per unique page pulled from. Views: Authors overview, Contact info, Growth signals.
errors sub-dataset: only rows where something failed or was skipped (source URL wrong platform, transcript failed, enrich failed, author profile failed). Views: Errors and skips, Source-level only, Transcript skips. No clean rows ever appear here.
URL classifier: accepts single reel, watch, video, share, and fb.watch URLs in addition to pages and profiles. Non-Facebook URLs (Instagram, TikTok, YouTube, Reddit, X) are skipped for free with a clear note.
Derived fields on every row: hashtags, mentions, description_urls, description_length_chars, age_days, views_per_hour, views_per_second_of_reel, aspect_ratio, engagement_rate, is_original_audio, hook_text_from_description, hook_text_from_transcript.
Cache add-on (cacheMaxAge, default 7d): repeat runs skip live calls when a cached response is still fresh. Applies to Deep enrich, Transcript, and Author profile. Cache hits cost nothing. Cached rows flagged in _metadata.enrich_from_cache, _metadata.transcript_from_cache, _metadata.author_profile_from_cache.
Date filter (onlyReelsNewerThan): pagination stops early once a full page of reels is entirely older than the filter, so scheduled runs only pay for genuinely new reels.
Pay-per-event pricing available in Apify Store settings. Six events: reel ($4.50/1k), reel_details ($5.00/1k), transcript ($8.00/1k), author_profile ($10.00/1k), audio_track ($2.00/1k), comment ($12.00/1k). The default apify-default-dataset-item auto-event is explicitly omitted so pushes to the main dataset are not double-billed. Existing pay-per-result tasks stay on their $4.50/1k rate until a user switches pricing model.
chargeEvent helper in code is defensive: probes both Actor.charge and Actor.chargeEvent, and swallows failures so a billing SDK hiccup never crashes the run.
CHARGE_COUNTERS key-value record at run end, plus RUN_SUMMARY.chargeCounters, for auditing which events fired and how many times.
Changed
Add-on defaults flipped ON in the input schema: enrichReelDetails, fetchTranscript, enrichAuthorProfile all default true. Console users get a fully-loaded run out of the box. Legacy API callers who never set these fields are protected: runtime detects undefined and keeps prior (off) behavior via Boolean(undefined) === false grandfathering.
maxReels: 0 now means "all reels" in the schema. Legacy API callers who omit the field still get the safe default of 30 reels via LEGACY_MAX_REELS_FALLBACK, protecting older integrations from silently going unlimited.
maxCommentsPerReel: 0 and maxRepliesPerComment: 0 mean "all". Legacy API callers who omit those fields get safe fallbacks (20 comments per reel, 5 replies per comment).
Input schema simplified: sections renamed to plain English ("Where to scrape from", "How much to pull", "Extra data (recommended)", "Comments", "Translate transcripts", "Cache (saves cost on repeat runs)"). Field titles trimmed of jargon. Descriptions shortened.
Reels overview, Deep enrich, and Transcripts views on the main dataset flatten nested fields (reel.*, enrich.*, _metadata.*, translations.<code>.*) so the Apify Console renders them as flat tables instead of "N fields" chips.
Transcripts view now shows per-language translation columns (one flat column per language you requested).
Storage config in actor.json migrated from storages.dataset (singular) to storages.datasets (plural alias map) so sub-datasets can each carry their own schema and views. Requires apify SDK 3.7.0+ (bumped from 3.2.6).
Aliased sub-datasets opened via Actor.openDataset({ alias: 'name' }) with a defensive fallback to plain-string named datasets when the platform hasn't populated ACTOR_STORAGES_JSON.
Errors moved from a main-dataset view (which noisily showed every reel row) to a dedicated errors sub-dataset (which only ever contains actual error/skip rows).
README rewritten to reflect all new features. The Complete Specification section is byte-identical to prior versions.
Fixed
HTTP 400 retry bug: apiGet no longer wastes 3 retries on non-retryable HTTP errors. Only 429/502/503/504 are retried; other error codes throw immediately.
Transcript pre-emptive skip now works when Deep enrich is off. Falls back to reel.play_time_in_ms / 1000 when enrich data is unavailable, avoiding wasted upstream calls on 2+ minute reels.
Stale copy on empty transcripts on short reels: was "likely longer than 2 minutes", now "Upstream returned no transcript for this reel (video may have no captions)."
API key redaction: SCRAPECREATORS_API_KEY and openaiApiKey are scrubbed from every error message before logging.
Errors view false-positive: rows with transcript_note_code: "ok" no longer show up as errors.
Backward compatibility
Existing scheduled tasks continue to run unchanged. Task input is stored as an explicit JSON blob, so a saved task with maxReels: 30, enrichReelDetails: false keeps that behavior forever. Schema default changes only affect new task creations and ad-hoc Console runs.
Existing API callers continue to run unchanged. Runtime detects undefined fields via Boolean(undefined) === false and keeps prior behavior (add-ons off, no cache, legacy safe caps).
Existing pay-per-result users continue on their $4.50/1k rate. Pay-per-event is dormant until a user switches pricing model in Apify Store settings.
Author profile, audio tracks, comments, and errors sub-datasets were all introduced in this session and are additive; no existing task or downstream automation references them by name.
Removed
Errors view on the main dataset: replaced by the errors sub-dataset with three focused views. Row-level filtering isn't supported by Apify dataset views, so the sub-dataset approach is the only way to guarantee that only actual errors appear.
[1.0] - Prior
Initial release. Base scraping via /v1/facebook/profile/reels, optional enrichReelDetails (deep enrich per reel) and fetchTranscript (per short reel). Pay-per-result pricing at $4.50 / 1,000 reels. Free-plan cap of 50 results.