# Changelog of Facebook Reels Scraper | Page Reels & Metrics (`arabiainsights/facebook-reels-scraper`) Actor

- **URL**: https://apify.com/arabiainsights/facebook-reels-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/arabiainsights/facebook-reels-scraper.md

## Changelog

All notable changes to this Actor are documented in this file.

### 2.1.0 — 2026-09-03

v2.1 stabilization: makes delivered records carry what the README promises (engagement counts, owner identity), repairs operational truth, and adds the competitor-proven exact-count mode (experimental). Implemented from the [v2.1 spec](.scratch/v2-stabilization/spec.md); live findings from the [2026-09-03 v2.1 probe](docs/research/2026-09-03-v21-probe.md) and [live cloud test report](docs/research/2026-09-03-live-tests.md).

#### Added

- **Engagement metrics on direct-Reel records** (ticket 03): the og:title engagement summary ("6.4K views · 19 reactions | caption") is now parsed in production, so direct reels carry `viewCount`/`reactionCount` (+ display/label/precision/source) with `source: "open_graph"` and `precision: "rounded"` (or `"exact"` for full numbers). Unobserved channels stay `null` — never `0`.
- **Owner identity** (ticket 04): `ownerType`/`ownerName`/`ownerUrl` derived from the 4-segment `og:url`/canonical page-video shape at zero extra requests; profile-shaped URLs classify as `profile`; unresolvable shapes stay `unknown`.
- **Relative and ISO dates** (ticket 05): `dateFrom`/`dateTo` accept `YYYY-MM-DD`, full ISO timestamps, and relative expressions ("7 days", "2 months", "1 year") resolved against run start in UTC, matching the official actor's UX.
- **`metricsMode: "exact"`** (ticket 10, experimental): requests direct-Reel details in a locale proven (2026-09-03 probe) to serve unabbreviated counters ("6.4K views" → "6.492 Aufrufe"); German dot-grouped numbers and labels parse locale-aware. Precision labels always reflect the observed display string; promotion from experimental requires the Phase 0 exact-agreement gates.
- `sourceLocale` now carries the observed `og:locale` (e.g. `en_US`).
- `INTERNAL_ERROR` failure code for unclassified exceptions so block-rate telemetry stays trustworthy (ticket 01).
- `PARSER_DEGRADATION` warnings that actually fire: systemic schema-miss rate above threshold, or zero candidates on every attempted Page after browser escalation (ticket 01).

#### Changed

- **Per-URL error isolation** (ticket 02): one invalid or prohibited URL no longer kills the run. Each rejected URL is skipped with a sanitized error record and a `RUN_REPORT` warning; the run fails (`INVALID_INPUT_URL`) only when zero valid sources remain, with an aggregated, capped rejection message.
- **Platform-truth exit codes** (ticket 01): a run whose terminal status is FAILED exits non-zero so the Apify platform shows FAILED; `SUCCEEDED`/`EMPTY`/`CHARGE_LIMIT` still exit 0.
- **Exclusion-counter truth** (ticket 01): every date-window exclusion increments `RUN_REPORT.totals` (`excludedBeforeRange`, `excludedAfterRange`, `unresolvedTimestamp`), so emitted + excluded + unresolved reconciles with attempted.
- **Docs truth** (ticket 08): README/architecture state the real 57-field record (was "53"); docs-contract pins the count against the dataset schema; `provenOptionalMediaFields` re-baselined through the standard pipeline — only `thumbnailUrl` survives on current logged-out pages.
- **Honest page-discovery claims** (tickets 07/09): live evidence shows logged-out Page Reels tabs deliver zero Reels through the Actor today; the README capability is re-scoped accordingly and page runs degrade loudly (`EMPTY` + `PARSER_DEGRADATION` + per-source stop reasons). Repair is an evidence-gated follow-up (see the probe report §3).
- **Publication timestamps**: documented as unavailable logged-out for direct reels (probe finding); date filtering over direct reels is best-effort with counted exclusions (ticket 06).
- **Related-Reel expansion**: not shipped (ticket 11) — logged-out payloads carry related content only as Video stubs without counts or reel links (documented no-go).

### 2.0.2 — 2026-09-03

- Fixed: every cloud run crashed at startup because the named browser-fallback request queue (`BROWSER_FALLBACK`) violated Apify storage naming rules (lowercase letters, digits, hyphens only). The queue is now run-scoped (`browser-fallback-<runId>`), which also prevents aborted runs from leaking browser work into later runs. Discovered by the first live cloud run of v2 on 2026-09-03; local runs never hit it because local storage does not enforce the naming rule.
- Fixed: `saveErrors: true` runs crashed on the first recorded error because the named dataset `ERROR_RECORDS` also violated the naming rule. The dataset is now named `error-records` (README and docs updated accordingly).

***

### 2.0.1 — 2026-08-18

- Fixed: `extractReelIdFromUrl` now resolves the numeric Reel ID from Facebook's modern 4-segment `/videos/<descriptive-slug>/<id>/` `og:url`/canonical shape. Previously it returned the descriptive slug, so direct-Reel records were discarded with `PARSER_SCHEMA_MISS` even though the page carried extractable OpenGraph data.
- Changed: a 200 OK Page seed that yields zero reel candidates now reports `JS_REQUIRED` and escalates once to the bounded browser fallback (per-source attempt ledger), instead of silently reporting "no more public results" with no verification. Facebook client-side renders Reels grids for logged-out visitors on all HTML surfaces. Browser requests are now counted in `RUN_REPORT.requests.browserRequests`.
- Both findings verified by live logged-out runs on 2026-08-18 (public NASA Page + a public direct Reel).

***

### 2.0.0 — 2026-08-17

This major release delivers an **HTTP-first architecture overhaul** designed for high throughput, predictable memory footprint (1,024 MB baseline), granular metric precision, and seamless Pay-Per-Event (PPE) integration.

- **Migration Guide**: See [v1 to v2 Migration Guide](docs/migrations/v1-to-v2.md) for field mappings and migration steps.
- **Release Evidence Receipts**: Local development consistency receipts are archived in [Release Evidence Receipts](docs/evidence/facebook-reels-v2/release/README.md). Cloud deployment, beta canaries, and production promotions remain blocked while Phase 0 is `HOLD`.
- **Evidence-Selected Completeness**: Operates using the `seed_and_direct_only` finite pagination route under the current Phase 0 `HOLD` decision as recorded in [Phase 0 Decision](docs/evidence/facebook-reels-v2/decision.json). Deep page history pagination remains unproven.

#### Breaking Changes

- **Flat Dataset Schema (2.0.0)**: Emitted records conform to `schemaVersion: "2.0.0"`. All nested objects (`author`, `page`, `audio`, `fieldStatus`) are replaced with a flat 53-field schema for zero-transformation analytics and direct CSV export compatibility.
- **Field Renames**:
  - `canonicalUrl` is replaced by `url`.
  - `publishedAt` is replaced by `createdAt` (with companion `createdAtTimestamp` and `createdAtPrecision`).
  - `caption` is replaced by `text`.
  - Nested `author.*` and `page.*` are flattened into `ownerType` (`page`, `profile`, `unknown`), `ownerName`, `ownerId`, `ownerUrl`, and `sourcePageUrl`.
  - Nested `audio.*` is flattened into `musicTitle` and `musicArtist`.
- **Metric Decomposition**: The old ambiguous engagement counters are replaced by 5 independent, non-coalesced metric channels:
  - `play`: `playCount`, `playCountDisplay`, `playCountLabel`, `playCountPrecision`, `playCountSource`
  - `view`: `viewCount`, `viewCountDisplay`, `viewCountLabel`, `viewCountPrecision`, `viewCountSource`
  - `reaction`: `reactionCount`, `reactionCountDisplay`, `reactionCountLabel`, `reactionCountPrecision`, `reactionCountSource`
  - `comment`: `commentCount`, `commentCountDisplay`, `commentCountLabel`, `commentCountPrecision`, `commentCountSource`
  - `share`: `shareCount`, `shareCountDisplay`, `shareCountLabel`, `shareCountPrecision`, `shareCountSource`
- **Zero Coercion Policy**: Unobserved or missing metrics remain `null` and are never coerced to `0`. A value of `0` strictly indicates that Facebook explicitly published an observed zero count.
- **Removed Inputs**:
  - `maxListingScrolls` and `maxConcurrency` are removed. Concurrency and pagination are handled automatically by the HTTP crawler engine and bounded browser resource pool.
  - Personal profile listing discovery is removed; only public Facebook Page URLs and direct Reel URLs are accepted.

#### Added Features & Improvements

- **HTTP-First Streaming Engine**: Direct Reel extractions and seed Page discoveries execute via fast, lightweight HTTP streaming parser without browser launch overhead. Deep pagination is held in Phase 0 pending live public web evidence.
- **Bounded Browser Escalation**: Browser execution is strictly bounded and invoked only when JavaScript hydration or anti-bot verification requires DOM evaluation.
- **Pay-Per-Event (PPE) Billing**: Integrated exact per-event charging per successfully emitted dataset item with crash recovery reconciliation.
- **Deduplication Key**: Added deterministic `dedupeKey` (`facebook:reel:<reelId>`) across all records for at-least-once downstream reconciliation.
- **Signed Media Transparency**: Added `videoUrlSd`, `videoUrlHd`, `thumbnailUrl`, `mediaUrlObservedAt`, and `mediaUrlMayExpire: true` for short-lived CDN URLs.
- **Operational Diagnostics**: End-of-run `RUN_REPORT` persisted to the default Key-Value Store with per-source progress counters, parser health rates, and warnings. Dedicated `ERROR_RECORDS` dataset available when `saveErrors: true`.

#### Known Limitations

- **Public Content Only**: Only publicly accessible Facebook Page Reels and direct Reel URLs are scraped. Private profiles, groups, and authenticated reels requiring login are unsupported.
- **Transient Media CDN URLs**: Media URLs (`videoUrlSd`, `videoUrlHd`, `thumbnailUrl`) are signed CDN URLs that may expire after several hours (`mediaUrlMayExpire: true`). Downstream pipelines should download or ingest media promptly.
- **Deep Pagination Feeds**: Reel discovery operates over public Page listing feeds without login; pagination depth reflects Facebook's publicly exposed feed window.
- **Zero Automated Auth Bypass**: The Actor strictly respects platform boundaries and does not attempt CAPTCHA solving, checkpoint evasion, or credential stuffing.

***

### 1.0.1 — 2026-08-16

This hardening release follows a ten-perspective production-readiness review. It adds a separate candidate-detail budget for narrow date ranges, strengthens Reels-only URL admission, binds hydration metadata to the target Reel identity, preserves mixed source-kind provenance, bounds browser snapshot capture, adds deterministic response-capture draining, emits sanitized debug diagnostics, rejects detail pages that no longer resolve to a Reel, and expands parser/deduplication regression coverage.

The release also upgrades and pins the production browser runtime to the matching Apify Node 22 / Playwright 1.62.1 image, moves the TypeScript runtime loader into production dependencies, and verifies zero production dependency advisories with `npm audit --omit=dev`.

Pre-publication fixes folded into this release: the request-handler timeout now scales with `maxListingScrolls` so default discovery runs no longer exceed the previous fixed 180-second budget; malformed URL strings inside captured hydration JSON no longer crash detail parsing; `profile.php?id=…` Page sources normalize to the correct `sk=reels` listing target; zero-millisecond durations parse as `0` instead of falling through to unrelated keys; and dead failure-classification branches were removed. Platform-side schema files were corrected for Apify build validation: unsupported per-field `advanced` flags were removed from the input schema, and the dataset schema was restructured to the required `actorSpecification`/`fields`/`views` shape with a full record schema. Dataset schema field types were then aligned with the emitted records (`mediaUrlExpiryWarning` is boolean-or-null and `reelId` is nullable), push failures now log the platform rejection reason and a sanitized record type signature, and a CI contract test validates fixture, fully populated, and sparse records against the deployed schema.

***

### 1.0.0 — 2026-08-16

The initial production release adds public-only Facebook Reel collection from Page/Profile discovery URLs and exact direct Reel URLs. It provides a 1,000-result default, configurable limit through 10,000, exact inclusive UTC date bounds, canonical URL deduplication, public metadata normalization, aggregate engagement counters, transient-media warnings, source-level diagnostics, and `RUN_REPORT` coverage reporting.

The release includes a Node.js 22 TypeScript/Playwright Apify Actor, strict runtime input validation, Console input/output schemas, durable queue/checkpoint behavior, sanitized error records, fixture-based tests, and deployment documentation.
