# Changelog of 🎬 Facebook Reels Scraper - MP4, Views, Audio \[NO LOGIN] (`unseenuser/fb-reels`) Actor

- **URL**: https://apify.com/unseenuser/fb-reels/changelog.md
- **Full Actor documentation**: https://apify.com/unseenuser/fb-reels.md

## Changelog

All notable changes to the Facebook Reels Scraper (`unseenuser/fb-reels`) are documented here.

The format is loosely based on [Keep a Changelog](https://keepachangelog.com/), 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**.
- **`comments` sub-dataset** (when `fetchComments` is on). Views: **Comments overview**, **Top-level only**, **Verified commenters**.
- **`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.
- **Enhanced transcript output**: `transcriptText`, `lines`, `transcriptAvailable`, `transcript_note`, `transcript_note_code` (`ok`, `over_2_minutes`, `no_captions_on_video`, `upstream_error`), `transcript_cached`, `transcript_cached_at`.
- **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.
