Skip to content

fix: compute replay mask rects in the same frame as the pixels - #530

Merged
marandaneto merged 6 commits into
mainfrom
posthog-self-driving/fixreplay-compute-mask-rects-in-the-307182
Aug 18, 2026
Merged

fix: compute replay mask rects in the same frame as the pixels#530
marandaneto merged 6 commits into
mainfrom
posthog-self-driving/fixreplay-compute-mask-rects-in-the-307182

Conversation

@posthog

@posthog posthog Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

💡 Motivation and Context

  • Who it hurts: every Flutter customer running maskAllTexts or maskAllImages can ship partially-unmasked replay frames whenever the UI moves during capture — the reporter confirmed masked health data was legible in paused recordings, which halted their production rollout. Affects 5.35.1 and 5.36.1, the default masking path, with no client-side workaround.
  • Root cause (stale-mask race): captureScreenshot() snapshotted the mask rects synchronously up front, then the async body awaited a platform-channel round trip (isSessionReplayActive()) and endOfFrame before grabbing pixels with toImage(). The rects are absolute positions frozen at walk time, so frame N's black boxes get painted onto frame N+k's image. Sit still → looks fine. Scroll or navigate fast → content moved out from under the boxes and renders through.
  • Fail-open second bug: a failed tree walk (walk returns null) silently shipped the raw, unmasked image.

💚 How did you test it?

  • Not run manually. Flutter tooling is not available in this environment, so flutter analyze and the widget tests were not executed here — please run CI / a local reviewer pass before merge.
  • Change is minimal and matches the pattern already used correctly by _collectPlatformViewRects() in the same file, which walks inside the async body.

📝 Checklist

  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

Changes

  • Move both mask walks (getPostHogWidgetWrapperElements() and getCurrentWidgetsElements()) inside the async body, right after await endOfFrame with no await between them and toImage() — rects and pixels now come from the same frame.
  • Fail closed: when maskAllTexts/maskAllImages is on and the walk returns null, drop the frame instead of shipping an unmasked screenshot.

🤖 Agent context

Autonomy: Fully autonomous


Created with PostHog Desktop from this inbox report.

Move both mask tree walks into the async capture body, right after `endOfFrame`
and before `toImage()`, so mask rects and pixels come from the same frame. A walk
done up front froze frame N positions and painted them onto frame N+k, leaking
content when the UI moved.

Also fail closed: when `maskAllTexts` or `maskAllImages` is on and the walk
returns null, drop the frame instead of shipping an unmasked screenshot.

Generated-By: PostHog Desktop
Task-Id: ba9fae9d-1da9-428b-acb7-d5455b503992
@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

posthog-flutter Compliance Report

Date: 2026-08-18 14:19:00 UTC
Duration: 97290ms

✅ All Tests Passed!

45/45 tests passed


Capture Tests

29/29 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields 159ms
Format Validation.Event Has Uuid 135ms
Format Validation.Event Has Lib Properties 130ms
Format Validation.Distinct Id Is String 125ms
Format Validation.Token Is Present 125ms
Format Validation.Custom Properties Preserved 126ms
Format Validation.Event Has Timestamp 126ms
Retry Behavior.Retries On 503 5345ms
Retry Behavior.Does Not Retry On 400 2126ms
Retry Behavior.Does Not Retry On 401 2124ms
Retry Behavior.Respects Retry After Header 8132ms
Retry Behavior.Implements Backoff 15455ms
Retry Behavior.Retries On 500 5234ms
Retry Behavior.Retries On 502 5233ms
Retry Behavior.Retries On 504 5234ms
Retry Behavior.Max Retries Respected 15459ms
Deduplication.Generates Unique Uuids 133ms
Deduplication.Preserves Uuid On Retry 5233ms
Deduplication.Preserves Uuid And Timestamp On Retry 10343ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry 5242ms
Deduplication.No Duplicate Events In Batch 135ms
Deduplication.Different Events Have Different Uuids 125ms
Compression.Sends Gzip When Enabled 124ms
Batch Format.Uses Proper Batch Structure 121ms
Batch Format.Flush With No Events Sends Nothing 113ms
Batch Format.Multiple Events Batched Together 136ms
Error Handling.Does Not Retry On 403 2122ms
Error Handling.Does Not Retry On 413 2122ms
Error Handling.Retries On 408 5235ms

Feature_Flags Tests

16/16 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id 18ms
Request Payload.Flags Request Uses V2 Query Param 16ms
Request Payload.Flags Request Hits Flags Path Not Decide 16ms
Request Payload.Flags Request Omits Authorization Header 16ms
Request Payload.Token In Flags Body Matches Init 14ms
Request Payload.Groups Round Trip 16ms
Request Payload.Groups Default To Empty Object 15ms
Request Payload.Person Properties Distinct Id Auto Populated When Caller Omits It 16ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False 15ms
Request Payload.Disable Geoip Omitted Defaults To False 14ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key 14ms
Request Lifecycle.No Flags Request On Init Alone 7ms
Request Lifecycle.No Flags Request On Normal Capture 119ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests 26ms
Request Lifecycle.Mock Response Value Is Returned To Caller 15ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event 125ms

posthog Bot and others added 3 commits August 13, 2026 14:27
A newer analyzer version in CI flags `unawaited_return_in_try_block` at
posthog_flutter_web.dart:430, which fails both the Dart analyze and Pub publish
dry run required checks. Awaiting the call also lets the surrounding
`on Exception catch` handle failures from `handleWebMethodCall`.

Generated-By: PostHog Desktop
Task-Id: ba9fae9d-1da9-428b-acb7-d5455b503992
@marandaneto
marandaneto marked this pull request as ready for review August 18, 2026 13:56
@marandaneto
marandaneto requested a review from a team as a code owner August 18, 2026 13:56
@marandaneto
marandaneto merged commit e07c8e7 into main Aug 18, 2026
27 checks passed
@marandaneto
marandaneto deleted the posthog-self-driving/fixreplay-compute-mask-rects-in-the-307182 branch August 18, 2026 15:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant