fix(pixel): use ResizeObserver to detect above-fold scroll state (SDK-275)#2868
Merged
Conversation
…-275)
The above-fold check was a synchronous snapshot taken at tracker init
time. On third-party sites that initialise the pixel before images or
JS-rendered content has expanded the page, scrollHeight could equal
innerHeight at that moment — locking in isAboveFold = true and firing
a false scroll_depth { depth: 100, aboveFold: true } event ~2s later
even on long pages.
Replace the one-shot check with a ResizeObserver on documentElement
that manages the dwell timer reactively: starts when the page is
above-fold, cancels if the page later grows, fires once stable for
the dwell window. Feature-detected to avoid breaking autocapture
on the ~3% of browsers without ResizeObserver.
Also adds AGENTS.md to packages/audience/{pixel,core} flagging the
inline-bundling relationship and CI bundle-size enforcement, since
core changes silently affect the pixel CDN bundle's size budget.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
✅ Pixel Bundle Size — @imtbl/pixel
Budget: 10.00 KB gzipped (warn at 8.00 KB) |
|
View your CI Pipeline Execution ↗ for commit d6c497f
☁️ Nx Cloud last updated this comment at |
✅ Audience Bundle Size — @imtbl/audience
Budget: 24.00 KB gzipped (warn at 20.00 KB) |
Local rebuilds are useful for fast iteration while cutting bytes; the CI workflow remains the source of truth. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The link to bundlebudget.json is enough; inlining the values risks staleness if the budgets are tuned. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Patch bump for the ResizeObserver above-fold fix (SDK-275). Version is compiled into the bundle via PIXEL_VERSION_INJECTED and sent on every event, allowing the analytics backend to segment by pixel version. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
nattb8
approved these changes
May 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes SDK-275 — the pixel tracker was firing a false
scroll_depth { depth: 100, aboveFold: true }event on long pages when installed on third-party sites.Root cause: the above-fold determination in
autocapture.tswas a synchronous snapshot taken at tracker init time. If the pixel initialised before images or JS-rendered content had expanded the page,scrollHeightcould equalinnerHeightat that moment — locking inisAboveFold = trueand firing the synthetic event ~2s later regardless of how large the page had grown by then.Fix: replace the one-shot check with a
ResizeObserverondocument.documentElementthat manages the dwell timer reactively. Starts the timer when the page is above-fold, cancels it if the page later grows beyond the viewport, fires once the page has been stably above-fold for the dwell window. Feature-detected so the ~3% of browsers withoutResizeObserverskip the synthetic event rather than crashing the rest of autocapture.See the Linear ticket for the competitive analysis (PostHog, GTM, Segment, robflaherty/scroll-depth) and the option-by-option assessment behind the chosen approach.
Also included
AGENTS.mdforpackages/audience/pixelandpackages/audience/coreflagging the inline-bundling relationship (core is bundled into the pixel CDN snippet viatsup.config.tsalias) and pointing at the CI-enforced size budget.corechanges silently affect the pixel's bundle size and there was no way for an agent or new contributor to discover that without reading the build config.Test plan
setupAutocapturedoes not throw whenResizeObserveris undefined (graceful degradation)🤖 Generated with Claude Code
Note
Medium Risk
Changes production analytics emission logic for
scroll_depthon above-the-fold pages and adds a new dependency onResizeObserverbehavior (with a fallback when unavailable), which could affect event firing timing/volume in the pixel snippet.Overview
Fixes false
scroll_depth{ depth: 100, aboveFold: true }events by replacing the one-time “above fold” snapshot with aResizeObserver-driven check that starts the dwell timer only while the document remains within the viewport and cancels it if the page grows.Updates tests to stub/mimic
ResizeObserver, adds coverage for cancelling the dwell timer on late content expansion, and verifies graceful behavior whenResizeObserveris missing. Also bumps@imtbl/pixelto0.1.1and addsAGENTS.mdnotes documenting the pixel bundle-size budget and that@imtbl/audience-coreis bundled inline into the pixel.Reviewed by Cursor Bugbot for commit d6c497f. Bugbot is set up for automated code reviews on this repo. Configure here.