Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

[Tracker] Scroll-depth tracking still forces layout on large pages after #6174

Aperta
#6,764 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 2 giorni

@trotzig ci sta già lavorando.

Dal 9/10/2026.

  • #6765 di @trotzig — aperta

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
18/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Ferma
Stack tecnologico
javascript

Direzione di ricerca

The scroll-depth code is the minified functions E, L and S in the published plausible.js: S wires a ResizeObserver on document.documentElement and a scroll listener on document, and E and L do the layout reads. Linked PR #6765 is already open, so check it before starting. Done means the reads no longer force layout inside a frame, or the scroll-depth tracking can be turned off through init.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Past Issues Searched
  • I have searched open and closed issues to make sure that the bug has not yet been reported
Issue is a Bug Report
  • This is a bug report and not a feature request, nor asking for self-hosted support
Using official Plausible Cloud hosting or self-hosting?

Plausible Cloud from plausible.io

Describe the bug

This is what remains of #5727 after the fix in #6174. With @plausible-analytics/tracker 0.4.6 (npm), the scroll-depth measurement still forces synchronous layout, in two places:

  1. The ResizeObserver on document.documentElement, whose callback reads scrollHeight, offsetHeight and clientHeight on both body and documentElement.
  2. The scroll listener on document, which reads window.scrollY and window.innerHeight.

When layout is dirty at the time these run, each read makes the browser complete a full layout right then. On a small page that is negligible. On a page with a very large DOM it blocks the main thread for hundreds of milliseconds.

What we measured

We were investigating intermittent freezes on a long list page in our app (about 180,000 DOM elements). We recorded frames with the Long Animation Frames API (PerformanceObserver with type: 'long-animation-frame'), which attributes the time in each frame to individual scripts and reports forcedStyleAndLayoutDuration per script.

Frame Total blocked Tracker's share
First frame after load 1,391 ms ResizeObserverCallback: 670 ms, of which 645 ms forced style and layout
A frame while scrolling 142 ms document.onscroll: 71 ms, of which 61 ms forced style and layout

Both entries pointed at the tracker's code in our bundle. In the published plausible.js it is this:

function E(){var e=document.body||{},t=document.documentElement||{};return Math.max(e.scrollHeight||0,e.offsetHeight||0,e.clientHeight||0,t.scrollHeight||0,t.offsetHeight||0,t.clientHeight||0)}
function L(){var e,t;return e=window.innerHeight,t=window.scrollY,i<=e?i:t+e}
function S(){i=E(),o=L(),new ResizeObserver(function(){i=E()}).observe(document.documentElement),document.addEventListener("scroll",function(){var e=L();e>o&&(o=e)})}

The page renders items lazily as they approach the viewport, so the document's height changes often, and each change fires the ResizeObserver again.

We did not identify what leaves layout dirty before the tracker's callback runs. Other ResizeObserver callbacks in the same delivery round, or writes earlier in the frame, would do it. The cost lands in the tracker's callback because it is the one that reads.

The tracker is initialised with init({ domain, autoCapturePageviews: false, captureOnLocalhost: false, customProperties }).

Expected behavior

Scroll-depth bookkeeping should not force layout inside a rendering frame, or it should be possible to turn it off.

Some options:

  • Defer the reads to a point where layout is already clean, for example requestIdleCallback with a timer fallback, and coalesce repeated calls. The values are only sent with the engagement event, so they don't need to be exact within a frame.
  • In the ResizeObserver callback, use the sizes on the delivered entries where possible, instead of re-reading scrollHeight and the others.
  • Add an init option to turn engagement or scroll-depth tracking off, which several people also asked for in #5727.

As a workaround we wrap init() so that, for the duration of that call, ResizeObserver and document.addEventListener('scroll', …) hand the tracker callbacks that are deferred to idle time. It relies on patching globals around a call into the library, so we'd rather not keep it.

Screenshots

No response

Environment
- OS: macOS
- Browser: Chrome
- Browser Version:
- Tracker: @plausible-analytics/tracker 0.4.6 (npm package)
Lingua principale
Elixir
Stelle
29.7k
Fork
1.9k
Merge medio
3g 22h
PR unite (30g)
50

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di plausible/analytics

Tutte le issue di plausible/analytics

Issue simili

Altre issue su Elixir

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.