Reading the Paint Profiler in DevTools

Part of Paint Invalidation & Repaint Boundaries in Performance Budgeting & GPU Architecture.

The problem

A card’s hover animation shows Paint events of four milliseconds in the Performance panel. The card animates transform and opacity only, so the paint must come from something else — but the trace says “Paint, 4.1ms” and nothing more. Guessing which of the card’s shadow, gradient, rounded corners, image or text is responsible means removing them one at a time and re-measuring.

The paint profiler removes the guessing: it records the individual draw commands a Paint event performed and how long each took.

Root cause analysis: a Paint event is a list of commands

When the browser paints, it produces a display list — a sequence of drawing commands such as “draw rounded rectangle”, “draw text run”, “draw image”, “draw shadow with blur radius 40” — and then rasterises them. The Performance panel’s Paint event shows the total time; the paint profiler shows the commands.

It must be enabled before recording. Advanced paint instrumentation is off by default because it makes traces larger and slower. It is a checkbox in the Performance panel’s settings.

The profiler shows per-command timing. Selecting a Paint event and opening the Paint Profiler tab lists the commands with their durations and lets you step through them visually, seeing the canvas build up. The expensive ones are usually few: a large blurred shadow, an image drawn at a size that needs resampling, a long text run, or a filter.

Paint flashing shows where, the profiler shows what. The Rendering drawer’s paint flashing highlights repainted regions, which identifies the element; the profiler explains the cost inside it. Used together they answer both questions for an animation that should not be painting at all.

Layerisation matters for interpretation. Paint work is attributed to the layer being painted. An element promoted to its own layer paints alone; an element sharing a layer paints alongside everything else in it, which is why a small hover effect can show a large Paint event.

From a slow animation to a specific draw commandEach tool answers one question.From a slow animation to a specific draw commandPerformancetraceis there paint?Paint flashingwhich region?Layers panelwhich layer?Paint profilerwhich command?CSS changeremove or isolate
Each tool answers one question.

Step-by-step resolution

A paint profiling sessionEnable, record, select, read, change, re-measure.A paint profiling session1Open Performance panel settings and enable advanced paint instrumentation.Commands will be recorded2Record while performing the animation several times.Multiple Paint events to compare3Select the largest Paint event in the Main track.Its details appear below4Open the Paint Profiler tab and sort by duration.The expensive commands surface5Map the command back to CSS: shadow, image, text or filter.A concrete target6Apply the change and record again with the same steps.
Enable, record, select, read, change, re-measure.

Production code pattern

/* Before: the profiler showed one command taking most of the paint time —
   a large blurred shadow redrawn on every hover frame. */
.card-old {
  box-shadow: 0 18px 40px -12px rgb(16 12 32 / 0.45);
  transition: box-shadow 200ms ease-out, translate 200ms ease-out;
}
.card-old:hover {
  box-shadow: 0 28px 60px -12px rgb(16 12 32 / 0.55);   /* re-blurred every frame */
  translate: 0 -4px;
}

/* After: the shadow is painted once on a pseudo-element and cross-faded. */
.card {
  position: relative;
  isolation: isolate;
  transition: translate 200ms ease-out;
}
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  box-shadow: 0 28px 60px -12px rgb(16 12 32 / 0.55);   /* painted once */
  opacity: 0;
  transition: opacity 200ms ease-out;
}
.card:hover {
  translate: 0 -4px;
}
.card:hover::after {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .card, .card::after { transition: none; }
  .card:hover { translate: none; }
}

Rendering Impact: composite after the change. The profiler’s evidence — one command dominating the Paint event — pointed directly at the shadow; the fix is the layered-opacity substitution from replacing box-shadow animation with layered opacity.

Recording the animation several times in one trace is worth the extra seconds: the first Paint after a change often includes work that will not repeat, such as decoding an image or rasterising a newly promoted layer, and comparing several events shows the steady-state cost.

Paint command timings inside one hover frameRead from the paint profiler before the change; the shadow dominates.Paint command timings inside one hover frameDrawShadow (blur 40)2.9 msDrawTextBlob (title + body)0.7 msDrawImageRect (thumbnail)0.3 msDrawRRect (card surface)0.1 ms
Read from the paint profiler before the change; the shadow dominates.

What the command names tell you

The command names map closely onto CSS. Shadow commands with a large blur radius come from box-shadow, text-shadow or drop-shadow(); their cost grows with the blur radius and the area. Text commands come from glyph rasterisation, which is expensive for large runs and for fonts without cached glyphs. Image commands are cheap when the drawn size matches the source and expensive when the browser must resample. Filter and blend commands come from filter, backdrop-filter and mix-blend-mode, and are among the costliest per pixel.

A Paint event dominated by a single command is the good case: there is one thing to fix. A long tail of small commands usually means the layer contains too much — many elements sharing one layer — in which case the answer is a repaint boundary rather than any individual property, as covered in using contain to scope repaints.

Verification checklist

Constraints and trade-offs

  • Paint instrumentation slows recording and inflates trace size; keep recordings short.
  • The profiler is available in Chromium-based DevTools; other engines offer different paint tooling.
  • Command names and granularity vary between browser versions.
  • A single fast Paint event can still be a problem if it happens every frame.
  • Fixing the dominant command can reveal a new one; re-measure rather than assuming.

Frequently asked questions

Where is the paint profiler in DevTools?

Enable advanced paint instrumentation in the Performance panel’s settings, record a trace, select a Paint event in the Main track, and open the Paint Profiler tab.

What is the difference between paint flashing and the paint profiler?

Paint flashing shows which regions are repainting. The profiler shows which draw commands inside a paint took the time.

Why is my Paint event large when I only animate transform?

Something else in the same layer is painting, or the element was not promoted and shares a layer with expensive content. Check the Layers panel alongside the profiler.

Which draw commands are usually the expensive ones?

Blurred shadows, filters and blends, large or resampled images, and long text runs.