Skip to content

fix(session-recorder): replace deprecated unload listener with visibilitychange/pagehide - #306

Open
in-jun wants to merge 1 commit into
hyperdxio:mainfrom
in-jun:fix/session-recorder-unload-flush
Open

fix(session-recorder): replace deprecated unload listener with visibilitychange/pagehide#306
in-jun wants to merge 1 commit into
hyperdxio:mainfrom
in-jun:fix/session-recorder-unload-flush

Conversation

@in-jun

@in-jun in-jun commented Aug 18, 2026

Copy link
Copy Markdown

Summary

  • Replace the deprecated unload listener in the session recorder's BatchLogProcessor with visibilitychange (hidden) + pagehide — the same flush strategy HyperDXBatchSpanProcessor already uses for spans
  • Send the flush with fetch keepalive (when under the 64 KiB body limit) so the final request survives page termination
  • Add a unit test and a patch changeset for @hyperdx/otel-web-session-recorder and @hyperdx/browser

Fixes #219. Same fix as upstream Splunk's signalfx/splunk-otel-js-web#1066. The beforeunload listener mentioned in the issue is left as is — it isn't deprecated, doesn't trigger the violation, and upstream keeps it.

Testing

  • yarn ci:build / ci:lint / ci:unit pass locally; new Jest tests cover listener registration and flush behavior
  • Real-browser check (Chrome 151 headless, --enable-features=DeprecateUnload, OTLP collector + ClickHouse): the Permissions Policy violation is gone, events recorded just before leaving the page now arrive (previously dropped), and the page becomes bfcache-restorable (pageshow.persisted === true)

…litychange/pagehide

The BatchLogProcessor constructor registered a window 'unload' listener
to flush pending logs. Chrome blocks 'unload' via Permissions Policy
(logging a violation warning on every page load), so the end-of-session
flush is silently dropped, and the mere presence of the listener makes
the page ineligible for the back/forward cache.

Flush on visibilitychange (hidden) and pagehide instead, and send the
export with fetch keepalive (when under the 64 KiB keepalive body limit)
so the request survives page termination. This mirrors the upstream
Splunk fix (signalfx/splunk-otel-js-web#1066) and the pagehide/
visibilitychange listeners already used elsewhere in this repo.

Fixes hyperdxio#219
@changeset-bot

changeset-bot Bot commented Aug 18, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: eab9842

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@hyperdx/otel-web-session-recorder Patch
@hyperdx/browser Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added the external Opened by an external contributor label Aug 18, 2026
@greptile-apps

greptile-apps Bot commented Aug 18, 2026

Copy link
Copy Markdown

Greptile Summary

The PR replaces the session recorder’s deprecated unload flush with visibilitychange and pagehide, and enables fetch keepalive for qualifying termination-time requests.

  • Flushes queued session logs when the document becomes hidden or the page is hidden.
  • Uses keepalive for compressed payloads below 64 KiB while the document is hidden.
  • Adds lifecycle tests and patch changesets for the affected packages.

Confidence Score: 4/5

The PR appears safe to merge, with only the non-blocking test-directory placement needing cleanup.

The lifecycle handlers atomically remove queued logs before exporting, and empty follow-up flushes are ignored; the only accepted concern is that the new test was added outside the repository’s prescribed test directories.

Files Needing Attention: packages/session-recorder/test/BatchLogProcessor.test.ts

Important Files Changed

Filename Overview
packages/session-recorder/src/BatchLogProcessor.ts Replaces the unload listener with hidden-state visibilitychange and pagehide flush handlers; queue transfer remains synchronous and prevents duplicate exports.
packages/session-recorder/src/OTLPLogExporter.ts Adds a payload-size and visibility-gated keepalive option to termination-time fetch requests.
packages/session-recorder/test/BatchLogProcessor.test.ts Covers listener registration and both flush triggers, but the new test violates the repository’s required test-directory convention.
.changeset/session-recorder-remove-unload.md Adds patch releases for the session recorder and browser packages with an accurate description of the lifecycle change.

Sequence Diagram

sequenceDiagram
    participant Browser
    participant Processor as BatchLogProcessor
    participant Exporter as OTLPLogExporter
    participant Collector
    Browser->>Processor: visibilitychange(hidden) or pagehide
    Processor->>Processor: Splice queued logs
    Processor->>Exporter: export(logs)
    Exporter->>Exporter: Encode and gzip
    Exporter->>Collector: fetch POST (keepalive when eligible)
Loading

Fix all with Greploop Fix All in Claude Code Fix All in Conductor Fix All in Cursor Fix All in Codex

Reviews (1): Last reviewed commit: "fix(session-recorder): replace deprecate..." | Re-trigger Greptile

@@ -0,0 +1,74 @@
import { BatchLogProcessor, convert } from '../src/BatchLogProcessor';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Test uses legacy directory

This new test is under packages/session-recorder/test/, while the repository convention requires tests in src/__tests__/ or __tests__/; leaving it here perpetuates an inconsistent layout and makes future tests harder to discover.

Context Used: AGENTS.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code Fix in Conductor Fix in Cursor Fix in Codex

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kept it next to the existing test/index.test.ts — this package's tests live in test/ (as do otel-web's), so moving only the new file would split the layout within the package. Happy to move both in a follow-up if the maintainers prefer consolidating on src/__tests__/.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a fair point — test/index.test.ts already exists, so placing the new file alongside it is the consistent choice within this package. My comment was incorrect about the convention here. Apologies for the noise.

Would you like me to remember that packages/session-recorder (and otel-web) use test/ as the test directory, not src/__tests__/?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external Opened by an external contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Permissions policy violation: unload event listener triggers Chrome warning

1 participant