Skip to content

fix(pixel): drop synthetic above-fold scroll_depth event (SDK-275)#2869

Merged
bkbooth merged 2 commits into
mainfrom
claude/sdk-275-hotfix
May 1, 2026
Merged

fix(pixel): drop synthetic above-fold scroll_depth event (SDK-275)#2869
bkbooth merged 2 commits into
mainfrom
claude/sdk-275-hotfix

Conversation

@bkbooth
Copy link
Copy Markdown
Contributor

@bkbooth bkbooth commented May 1, 2026

Summary

Hotfix for SDK-275. The v0.1.1 ResizeObserver fix in #2868 addressed the original "page grew after init" race, but the synthetic aboveFold: true depth: 100 event was still being emitted on SPAs and pages with internal scroll containers. Confirmed on https://godsunchained.com/ where document.documentElement.scrollHeight is permanently equal to window.innerHeight because the page uses a <div class="website-content"> with overflow: auto as its actual scroll container.

The bug is architectural — any check based on the document element gives the wrong answer when the document itself isn't the scroller. ResizeObserver doesn't help: the document height is locked, so the "page grew" branch can never trigger.

Fix: drop the synthetic above-fold event entirely. Match PostHog / Segment / GTM behaviour and only fire scroll_depth on real scroll events. On pages where the document doesn't scroll, no milestone fires. The previous bounce-filter signal on legitimately short pages is lost, but in exchange we eliminate an entire class of false positives — and none of the established lightweight trackers do this anyway, so we're not losing competitive ground.

Bundle size

CI will post the authoritative delta. As a sanity check, locally measured: 5,670 B gzip (down 181 B from v0.1.1, down 89 B from the pre-SDK-275 baseline). Removing complexity wins.

Follow-up

A new Linear ticket will be opened to cover proper scroll-depth tracking on pages with internal scroll containers (capture-phase scroll listening, ~+50–100 B), plus documenting the iframe limitation in docs.immutable.com — that one needs a separate PR against immutable/documentation.

Test plan

  • All existing scrollable-page tests pass unchanged
  • New tests: non-scrollable pages emit no milestones at setup or on subsequent scroll events
  • Lint clean
  • Bundle size CI will post the delta on this PR

🤖 Generated with Claude Code


Note

Medium Risk
Changes scroll_depth semantics by removing the synthetic 100% event on non-scrollable pages, which may affect downstream analytics/dashboards that relied on those events. Logic is localized to autocapture and is covered by updated tests, with no auth/PII impact.

Overview
Removes the synthetic above-the-fold scroll_depth emission (previously depth: 100 after a dwell via ResizeObserver) and now only emits scroll milestones when the document is actually scrollable and the user scrolls.

Updates tests to drop ResizeObserver/timer-based behavior and assert that non-scrollable pages never emit scroll_depth (including on spurious scroll events), updates README documentation accordingly, and bumps @imtbl/pixel to 0.1.2.

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

The previous fix (v0.1.1) used a ResizeObserver to detect when the
document grew beyond the viewport, but the synthetic above-fold event
still produced false positives on SPAs and pages with internal scroll
containers — where document.documentElement.scrollHeight is permanently
equal to window.innerHeight regardless of actual content depth.
Confirmed in the wild on godsunchained.com, which uses an internal
.website-content scroll container with overflow: auto.

Drop the synthetic event entirely and align with PostHog / Segment /
GTM behaviour: only fire scroll_depth on real scroll events. On pages
where the document doesn't scroll, no milestone fires. This trades
the bounce-filter signal on legitimately short pages for eliminating
an entire class of false positives.

Net bundle impact: -181 bytes gzip vs v0.1.1, -89 bytes vs pre-SDK-275.

Follow-up SDK-XXX will look at proper scroll tracking on pages with
internal scroll containers (capture-phase scroll listening).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@bkbooth bkbooth requested a review from a team as a code owner May 1, 2026 05:55
@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented May 1, 2026

View your CI Pipeline Execution ↗ for commit a327b95

Command Status Duration Result
nx run-many -p @imtbl/sdk,@imtbl/checkout-widge... ✅ Succeeded 2s View ↗
nx affected -t build,lint,test ✅ Succeeded 7s View ↗

☁️ Nx Cloud last updated this comment at 2026-05-01 06:30:01 UTC

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 1, 2026

✅ Pixel Bundle Size — @imtbl/pixel

Metric Size Delta vs main
Gzipped 5703 bytes (5.56 KB) -181 bytes
Raw (minified) 15315 bytes -570 bytes

Budget: 10.00 KB gzipped (warn at 8.00 KB)

- README: scroll_depth row no longer mentions the removed aboveFold
  property or 2s dwell.
- autocapture.ts: tighten the setupScrollTracking jsdoc; drop the
  ticket reference (belongs in the PR description, not source code)
  and the competitor name-check (changelog territory).
- autocapture.test.ts: remove the 'does not include aboveFold property'
  test — it was a redundant guard once the property was gone from the
  source, and the existing toEqual assertions cover it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@bkbooth bkbooth enabled auto-merge May 1, 2026 06:12
@bkbooth bkbooth added this pull request to the merge queue May 1, 2026
Merged via the queue into main with commit 96d78d6 May 1, 2026
10 checks passed
@bkbooth bkbooth deleted the claude/sdk-275-hotfix branch May 1, 2026 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants