Skip to content

fix(autocapture): exposure snapshot - #1948

Open
jxiwang wants to merge 9 commits into
mainfrom
fix-exposure-snapshot
Open

fix(autocapture): exposure snapshot#1948
jxiwang wants to merge 9 commits into
mainfrom
fix-exposure-snapshot

Conversation

@jxiwang

@jxiwang jxiwang commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes [Amplitude] Viewport Content Updated under-reporting on SPAs and duplicate/partial events caused by hydration and history API behavior.

Problem

  • On SSR/hydrated sites (e.g. clubmed.fr), only header/footer elements were exposed during a session; main content was missed until page leave.
  • Many sites (Google, React SPAs) fire same-URL pushState/replaceState during hydration, which triggered spurious page-end flushes and a second snapshot cycle — producing two events where the second was a superset of the first.

Solution

  1. Initial exposure snapshot — after DOM mutations settle, rescan allowlisted elements and flush one Viewport Content Updated event per page view.
  2. DocumentFragment support — observe elements committed via React hydration fragments, not just direct Element nodes.
  3. Same-URL navigation guard — only treat history changes as page end when the normalized URL actually changes.
  4. Sent-event deduplication — elements already included in a flushed event are not re-sent on subsequent flushes within the same page view.

How the initial snapshot works


Note

Medium Risk
Changes browser autocapture event emission, IntersectionObserver scanning, and history API proxies. Incorrect URL comparison or snapshot timing could drop or duplicate analytics events, but this is not auth or data-security critical.

Overview
Fixes [Amplitude] Viewport Content Updated under-reporting on hydrated SPAs and duplicate/partial events from same-URL history changes.

After DOM mutations settle (or a 4s cap), an initial exposure snapshot rescans allowlisted elements and flushes one event per page view. Exposure observation now includes DocumentFragment nodes (React hydration) and can re-observe existing nodes.

SPA page-end flushes only run when the normalized URL actually changes (query-only changes ignored; hash kept). pushState/replaceState flush the previous page before applying history, and already-sent element paths are not re-emitted within the same page view.

Reviewed by Cursor Bugbot for commit ac3e883. Bugbot is set up for automated code reviews on this repo. Configure here.

jxiwang and others added 3 commits August 20, 2026 15:54
The plugin imported this module, but it was never committed, which broke CI builds.

Co-authored-by: Cursor <cursoragent@cursor.com>
@jxiwang
jxiwang marked this pull request as ready for review August 20, 2026 23:41
@jxiwang
jxiwang requested a review from a team as a code owner August 20, 2026 23:41
@jxiwang

jxiwang commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator Author

bugbot run

@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown

size-limit report 📦

Path Size
packages/analytics-browser/lib/scripts/amplitude-min.js.gz 62.26 KB (+1.16% 🔺)
packages/session-replay-browser/lib/scripts/session-replay-browser-min.js.gz 134.97 KB (0%)
packages/unified/lib/scripts/amplitude-min.umd.js.gz 216.29 KB (+0.33% 🔺)
@amplitude/element-selector (gzipped esm) 2.67 KB (0%)

Comment thread packages/plugin-autocapture-browser/src/autocapture-plugin.ts Outdated
Keep lastScroll in sync with the scroll tracker after SPA navigation
so the next snapshot does not fire an empty Viewport Content Updated.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread packages/plugin-autocapture-browser/src/autocapture-plugin.ts
Comment thread packages/plugin-autocapture-browser/src/observables.ts
@jxiwang
jxiwang enabled auto-merge (squash) August 21, 2026 00:31
@jxiwang
jxiwang disabled auto-merge August 21, 2026 00:31
Comment thread packages/plugin-autocapture-browser/src/autocapture-plugin.ts
Comment thread packages/plugin-autocapture-browser/src/autocapture-plugin.ts Outdated
Comment thread packages/plugin-autocapture-browser/src/autocapture-plugin.ts
Comment thread packages/plugin-autocapture-browser/src/helpers.ts
@jxiwang

jxiwang commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit ac3e883. Configure here.

export const EXPOSURE_SNAPSHOT_QUIET_MS = 150;

/** Upper bound to wait for DOM hydration before taking the initial exposure snapshot. */
export const EXPOSURE_SNAPSHOT_MAX_WAIT_MS = 4_000;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Just chose a value for this, do not think it would reach this.

@daniel-graham-amplitude daniel-graham-amplitude left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Lgtm, everything looks good. But I'd want other code reviews on this too.

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.

2 participants