Why Is This Page Slow?
Turn on a fault and read what moved. Almost every fault here raises the two things a user actually feels, so neither of those can tell you which fault you have — the diagnosis always runs through the evidence signals underneath, and this page is built so that is the only way through.
Every reading below is produced by a model inside Engineer Atlas, and every value is a multiple of that signal's healthy baseline — 3.0x baseline means three times a healthy page, not three milliseconds. A number of milliseconds here would be a fabrication: it would depend on a device, a network, a viewport and a browser this model does not have. What transfers is the shape — which signal moves, and which one separates two faults that look identical from the outside.
Each control addresses one mechanism and nothing else. Turning all five on does not make an arbitrary page fast, and if a reading does not move when you enable one, that is the finding.
What the user feels
Raised by almost every fault below, so on their own they identify nothing. These are the symptom, never the diagnosis.
Field loading metric; Performance panel timings
Field interaction metric; Performance panel Interactions track
An incident report that stops here — “the page got slower” — has not narrowed anything down. Both of these move for a bundle problem, a layout problem, a paint problem and a server problem alike.
The evidence
These are what separate one cause from another, and each one names the panel a real engineer would open to read it.
| Signal | Now | vs baseline | Where you read it |
|---|---|---|---|
| Content movement after paint | 1.0x baseline | unchanged | Field stability metric; Layout Shift regions overlay |
| Main thread occupied | 20% of the main thread | unchanged | Performance panel main-thread track |
| Long tasks | none | unchanged | Performance panel; long-task observer in the field |
| JavaScript downloaded | 1.0x baseline | unchanged | Network panel, filtered to script |
| Script parse + execute | 1.0x baseline | unchanged | Performance panel bottom-up, scripting category |
| Render-blocking requests | 1 | unchanged | Network panel waterfall, before first paint |
| DOM nodes | 1.0x baseline | unchanged | Performance monitor; Elements panel |
| Layout passes per interaction | 1.0x baseline | unchanged | Performance panel, layout events (forced layout is flagged) |
| Area repainted | 1.0x baseline | unchanged | Paint flashing overlay; Performance panel paint events |
| Data endpoint latency | 1.0x baseline | unchanged | Network panel, XHR/fetch timing |
| Repeated identical requests | 1.0x baseline | unchanged | Network panel, grouped by URL |
| Retained memory growth | 1.0x baseline | unchanged | Memory panel, heap snapshots across navigations |
What a person using it would say
Not a metric. The sentence that actually arrives in the bug report.
- —“Nothing to report. The page behaves as a healthy page does.”
Diagnose it
Name the cause from the evidence before you open the answer. Being right from the wrong signal does not transfer to the next page.
Healthy. Every signal sits at its baseline, which is what a page looks like when there is nothing to find.
Reading the evidence in a real session
What each of these panels is actually telling you, stated without a single absolute number.
Nothing paints until every one of these has been fetched and parsed, and the third-party one adds a DNS lookup, a connection and a handshake in front of that. The number matters far more than the bytes: each is a serial dependency, and one on an origin you do not control is one you cannot make faster.
The browser is downloading code for routes this user has not visited. One chunk means no split point, so nothing can be deferred — but bytes alone do not prove the page is slow. Compare this against script execution before concluding anything: a large, cheap bundle and a small, expensive one look identical here.
Parse and execution are main-thread work, so this is time the page cannot respond to anything. Concentrated before first interaction is the hydration signature: the pixels arrived early, and the page will not answer until this finishes. Read together with downloaded bytes — high execution with normal bytes means the code is expensive rather than large.
The thread that owns the DOM is also the thread that answers input. While it is occupied, events queue and no frame is produced. This is the most general signal on the panel and therefore the least diagnostic — it tells you the thread is saturated, not by what.
A task runs to completion; the browser cannot interrupt it to handle input or paint. One landing on an interaction means the interface was not slow to respond, it was unable to respond. Long tasks during load and long tasks on interaction have different causes and should be read separately.
The browser batches layout on purpose. Passes flagged as forced mean something read a layout-dependent property while a style change was pending, cancelling that batching. A count that scales with the size of a loop is the read-write-read pattern, and the fix is to separate the reads from the writes rather than to make either faster.
Style matching, layout and memory all scale with node count, and most of these nodes are outside the viewport where nobody can see them. Stable rather than growing distinguishes rendering everything at once from a leak: a leak keeps climbing across navigations, this one is simply large from the start.
The dirty region is much larger than the element that changed. Usually an expensive effect — a large shadow, a blur, a backdrop filter — whose bounds exceed its element, or a change on an ancestor that owns a much bigger region. Paint cost is measured in area and effect expense, not in elements.
This one is not a frontend defect. The client is waiting, and the only frontend questions are whether it waits honestly — a pending state, a timeout, a failure branch — and whether the page could have rendered anything useful before the answer arrived. Isolated high latency with normal main-thread signals points outward, not inward.
Several components are each fetching what they need on mount, with no deduplication and no reuse of a response that is still fresh. Repeating on navigation rather than within one view means there is no cache at all, as distinct from a cache whose keys are wrong.
Something is retained after the view that created it is gone — typically a subscription that was never removed, holding its closure and the component subtree behind it. The signature is the failure to return to baseline; peak usage alone proves nothing, since a heavy page is allowed to use memory while it is on screen.
Content that was already painted is being moved by something arriving later that had no space reserved for it. Concentrated after media and font arrival names the cause directly: elements with no intrinsic size take up nothing until they decode, then push everything below them down.