Paint Timing

Editor’s Draft,

More details about this document
This version:
Feedback:
GitHub
Inline In Spec
Editors:
(Google)
(Google)
Former Editors:
(Google)
(Google)

Abstract

This document defines an API that can be used to capture a series of key moments (first paint, first contentful paint) during pageload which developers care about.

Status of this document

This is a public copy of the editors’ draft. It is provided for discussion only and may change at any moment. Its publication here does not imply endorsement of its contents by W3C. Don’t cite this document other than as work in progress.

GitHub Issues are preferred for discussion of this specification.

This document is governed by the 18 August 2025 W3C Process Document.

1. Introduction

This section is non-normative.

Much of the purpose of a web browser is to translate HTML, CSS and image resources into pixels on a screen for users. Measuring the performance of a web page often involves measuring the time it takes to perform these tasks - to render content, whether text or image, to the screen. There are many different ways to use this timing to make statemements about the performance of a page, or about the user experience of loading, but fundamentally all of those ways begin with a common means of measuring time.

This is a foundational document which specifies how to measure paint timing as a general-purpose mechanism. That foundation is then used to define the First Paint and First Contentful Paint metrics. Other specific instances of paint measurement may be specified in other documents.

Specifically, this specification covers:

1.1. First Paint and First Contentful Paint

Load is not a single moment in time — it’s an experience that no one metric can fully capture. There are multiple moments during the load experience that can affect whether a user perceives it as "fast" or "slow".

First paint (FP) is the first of these key moments, followed by first contentful paint (FCP). These metrics mark the points in time when the browser renders a given document. This is important to the user because it answers the question: is it happening?

The primary difference between the two metrics is FP marks the first time the browser renders anything for a given document. By contrast, FCP marks the time when the browser renders the first bit of image or text content from the DOM.

1.2. Usage example

const observer = new PerformanceObserver(function(list) {
    const perfEntries = list.getEntries();
    for (const perfEntry of perfEntries) {
        / Process entries
        / report back for analytics and monitoring
        / ...
    }
});

/ register observer for paint timing notifications
observer.observe({entryTypes: ["paint"]});

2. Terminology

Paint: the user agent has performed a "paint" (or "render") when it has converted the render tree to pixels on the screen. Formally, we consider the user agent to have "rendered" a document when it has performed the update the rendering steps of the event loop.

NOTE: The rendering pipeline is very complex, and the timestamp should be the latest timestamp the user agent is able to note in this pipeline (best effort). Typically the time at which the frame is submitted to the OS for display is recommended for this API.

A generated content pseudo-element is a paintable pseudo-element when all of the following apply:

A CSS image img is a contentful image when all of the following apply:

A document white space characters.

An element target is contentful when one or more of the following apply:

An element is timing-eligible if it is one of the following:

To compute the paintable bounding rect of element target, run the following steps:

  1. Let boundingRect be the result of running the getBoundingClientRect() on target.

  2. Clip boundingRect with the scrolling area.

  3. Return boundingRect.

NOTE: elements contained by boxes with overflow: scroll or overflow: hidden don’t have their paintable bounding rect clipped, as in both cases the element can become visible by scrolling.

An element el is paintable when all of the following apply:

  • el is being rendered.

  • el’s used visibility is visible.

  • el and all of its ancestors' opacity is greater than zero.

    NOTE: there could be cases where a paintable element would not be visible to the user, for example in the case of text that has the same color as its background. Those elements would still considered as paintable for the purpose of computing first contentful paint.

  • el’s paintable bounding rect intersects with the document.

    NOTE: This covers the cases where the element is scaled to zero size, has display: none, or display: contents where the contents resolve to an empty rect.

    NOTE: As a general rule, an element is paintable if it is within the viewport, or can potentially be in the viewport as a result of scrolling or zooming.

First paint entry contains a DOMHighResTimeStamp reporting the time when the user agent first rendered after navigation. This excludes the default background paint, but includes non-default background paint and the enclosing box of an iframe. This is the first key moment developers care about in page load – when the user agent has started to render the page.

A browsing context ctx is paint-timing eligible when one of the following apply:

  • ctx is a top-level browsing context.

  • ctx is a nested browsing context, and the user agent has configured ctx to report paint timing.

    NOTE: this allows user agents to enable paint-timing only for some of the frames, in addition to the main frame, if they so choose. For example, a user agent may decide to disable paint-timing for cross-origin iframes, as in some scenarios their paint-timing might reveal information about the main frame.

3. The Paint Timing Mixin

This section is non-normative.

The PaintTimingMixin interface exposes timestamps related to the rendering cycle. It is included in PerformanceEntry, specifically by PerformanceLongAnimationFrameTiming.

The paintTime attribute represent the timestamp at the end of the update the rendering loop while the presentationTime represents an implementation-specific timestamp marked when the frame is presented to the user. The mark paint timing alorithm, called from update the rendering in the HTML standard, populates both attributes.

Attributes in entries that rely on paint timing, like renderTime (as well as its startTime), usually return the default paint timestamp rather than one of the specific timestamps, making them agnostic to the implementation-specific nature of presentationTime.

3.1. The PaintTimingMixin interface

[Exposed=Window]
interface mixin PaintTimingMixin {
    readonly attribute DOMHighResTimeStamp paintTime;
    readonly attribute DOMHighResTimeStamp? presentationTime;
};

Objects including the PaintTimingMixin interface mixin have an associated paint timing info (null or a paint timing info).

paint timing info is a items:

rendering update end time

A DOMHighResTimeStamp

implementation-defined presentation time

Null or a DOMHighResTimeStamp

The paintTime attribute’s getter step is to return this’s paint timing info’s rendering update end time.

The presentationTime attribute’s getter step, if exists, is to return this’s paint timing info’s implementation-defined presentation time.

To get the default paint timestamp for a paint timing info paintTimingInfo, return paintTimingInfo’s implementation-defined presentation time if it is non-null, otherwise paintTimingInfo’s rendering update end time.

4. The PerformancePaintTiming interface

[Exposed=Window]
interface PerformancePaintTiming : PerformanceEntry {
    [object toJSON();
};
PerformancePaintTiming includes PaintTimingMixin;

PerformancePaintTiming extends the following attributes of PerformanceEntry interface:

NOTE: A user agent implementing PerformancePaintTiming would need to include "paint" in browsing context is paint-timing eligible. This allows developers to detect support for paint timing for a particular browsing context.

5. Processing model

5.1. Associated Image Requests

Each image request or null, initially null.

When the processing model for an Element element of type HTMLVideoElement creates a new image resource (e.g., to be displayed as an image or poster image), element’s associated image request is set to the image request of the created image resource.

Note: Every image resource that is obtained from a URL whose image request which is not fetched but still needs to be loaded. This request can be the associated image request of an Element.

Note: The current language is vague since it does not point to specific algorithms. This can be made more rigorous when the corresponding processing models have a more unified processing model.

Every Element has a list of associated background image requests which is initially an empty array. When the processing model for the Element element’s style requires a new image resource (to be displayed as background image), the image request created by the new resource is appended to element’s associated background image requests.

NOTE: An image requests, e.g. if its background-image property has multiple values. For instance, in the following example, a single background-image property produces four image requests, each of which will be recorded and reported by the algorithms below.

<!DOCTYPE html>
<style>
div {
  background-image: url(https://images.example/background1.png),
                    url(https://images.example/background2.png);
}
</style>
<div></div>
<div></div>

5.2. Recording paint timing

A pending image record is a struct with the following items:

Each Text nodes, initially empty.

Each strings, initially empty.

Each list of pending image records, initally empty.

Each Elements, initially empty.

5.2.1. Modifications to the CSS specification

Whenever an image request as inputs.

5.2.2. Modifications to the HTML specification

When an completely available, run the algorithm to process an image that finished loading passing in element and its associated image request as inputs.

When the user agent paints a Text node text for the first time, it should execute the following steps:

5.2.3. Process image that finished loading

To process an image that finished loading given an image request imageRequest:
  1. Let root be element’s root.

  2. If root is not a Document, return.

  3. Let now be the relevant global object.

  4. Let record be a pending image record with element element, request imageRequest and loadTime now.

  5. Add record to root’s images pending rendering.

5.3. Reporting paint timing

5.3.1. First Contentful Paint

To know whether Document document should report first contentful paint, perform the following steps:
  1. If document’s set of previously reported paints contains "first-contentful-paint", then return false.

  2. If document contains at least one element that is both paintable and contentful, then return true.

  3. Otherwise, return false.

5.3.2. Mark paint timing

When asked to mark paint timing given a Document document as input, perform the following steps:
  1. If the browsing context is not paint-timing eligible, return.

  2. Let paintTimingInfo be a new paint timing info, whose rendering update end time is the relevant global object.

  3. Let paintedImages be a new ordered set

  4. Let paintedTextNodes be a new ordered set

  5. For each record in doc’s images pending rendering list:

    1. If record’s request is available and ready to be painted, then run the following steps:

      1. Append record to paintedImages.

      2. Remove record from doc’s images pending rendering list.

  6. For each descendants:

    1. If element is contained in doc’s set of elements with rendered text, continue.

    2. If element’s set of owned text nodes is empty, continue.

    3. Append element to doc’s set of elements with rendered text.

    4. Append element to paintedTextNodes.

  7. Let reportedPaints be the document’s set of previously reported paints.

  8. Let frameTimingInfo be document’s current frame timing info.

  9. Set document’s current frame timing info to null.

  10. Let flushPaintTimings be the following steps:

    1. If reportedPaints does not contain "first-paint", and the user agent is configured to mark first paint, then report paint timing given document, "first-paint", and paintTimingInfo.

      NOTE: First paint excludes the default background paint, but includes non-default background paint.

      This should be turned into a normative note.

    2. If document should report first contentful paint, then:

      1. Report paint timing given document, "first-contentful-paint", and paintTimingInfo.

      NOTE: A parent frame should not be aware of the paint events from its child iframes, and vice versa. This means that a frame that contains just iframes will have first paint (due to the enclosing boxes of the iframes) but no first contentful paint.

      NOTE: A document containing only elements that are not contentful may never mark first contentful paint.

      NOTE: The marking of first paint is optional. User-agents implementing paint timing should at the very least mark first contentful paint.

    3. Report largest contentful paint given document, paintTimingInfo, paintedImages and paintedTextNodes.

    4. Report element timing given document, paintTimingInfo, paintedImages and paintedTextNodes.

    5. If frameTimingInfo is not null, then queue a long animation frame entry given document, frameTimingInfo, and paintTimingInfo.

  11. If the user-agent does not support implementation-defined presentation times, call flushPaintTimings and return.

  12. Run the following steps In parallel:

    1. Wait until an implementation-defined time when the current frame has been presented to the user.

    2. Set paintTimingInfo’s implementation-defined presentation time to the relevant global object.

    3. If document’s cross-origin isolated capability is false, then:

      1. Coarsen paintTimingInfo’s implementation-defined presentation time to the next multiple of 4 milliseconds, or coarser.

      2. Wait until the current high resolution time is paintTimingInfo’s implementation-defined presentation time.

    4. relevant global object to run flushPaintTimings.

5.3.3. Report paint timing

To report paint timing given document, paintType, and a paint timing info paintTimingInfo as arguments, perform the following steps:
  1. Create a relevant realm and set its attributes as follows:

    1. Set newEntry’s name attribute to paintType.

    2. Set newEntry’s entryType attribute to "paint".

    3. Set newEntry’s startTime attribute to the default paint timestamp given paintTimingInfo.

    4. Set newEntry’s duration attribute to 0.

  2. Set newEntry’s paint timing info to paintTimingInfo.

  3. relevant realm.

  4. Append paintType to document’s set of previously reported paints.

5.4. Common algorithms

5.4.1. Exposed for paint timing

To determine whether an Document or null document, perform the following steps:

  1. If element is not connected, return false.

  2. If document is null, let document be element’s associated document.

  3. If document is not fully active, return false.

  4. If element’s root is not equal to document, return false.

  5. Return true.

6. Acknowledgements

Special thanks to all the contributors for their technical input and suggestions that led to improvements to this specification.

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Conformant Algorithms

Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and abort these steps") are to be interpreted with the meaning of the key word ("must", "should", "may", etc) used in introducing the algorithm.

Conformance requirements phrased as algorithms or specific steps can be implemented in any manner, so long as the end result is equivalent. In particular, the algorithms defined in this specification are intended to be easy to understand and are not intended to be performant. Implementers are encouraged to optimize.

Index

Terms defined by this specification

Terms defined by reference

  • [] defines the following terms:
    • available
    • browsing context
    • CSS image
    • generated content pseudo-element
    • image
    • nested browsing context
    • poster frame
    • represents
    • scrolling area
    • typographical pseudo-element
    • url valued
  • [CR-SVG2] defines the following terms:
    • svg element with rendered descendants
  • [CSS-BACKGROUNDS-3] defines the following terms:
    • background-image
    • background-size
  • [CSS-CASCADE-5] defines the following terms:
    • used value
  • [CSS-COLOR-3] defines the following terms:
    • opacity
  • [CSS-DISPLAY-4] defines the following terms:
    • box
    • containing block
    • replaced element
    • text node
  • [CSS-FONTS-4] defines the following terms:
    • font block period
  • [CSS-TEXT-4] defines the following terms:
    • document white space characters
  • [CSSOM-VIEW-1] defines the following terms:
    • getBoundingClientRect()
  • [DOM] defines the following terms:
    • Document
    • Element
    • Text
    • connected
    • descendant
    • document
    • element
    • root
  • [ELEMENT-TIMING] defines the following terms:
    • PerformanceElementTiming
    • Report element timing
    • Report largest contentful paint
  • [EVENT-TIMING] defines the following terms:
    • PerformanceEventTiming
  • [HR-TIME-3] defines the following terms:
    • DOMHighResTimeStamp
    • current high resolution time
  • [HTML] defines the following terms:
    • HTMLImageElement
    • HTMLVideoElement
    • associated Document
    • being rendered
    • browsing context (for Document)
    • browsing context (for Window)
    • canvas
    • completely available
    • context mode
    • cross-origin isolated capability
    • fully active
    • global object
    • image request
    • img
    • in parallel
    • input
    • queue a global task
    • relevant global object
    • relevant realm
    • relevant settings object
    • top-level browsing context
    • update the rendering
    • value
    • video
  • [INFRA] defines the following terms:
    • append (for list)
    • append (for set)
    • item
    • list
    • ordered set
    • string
    • struct
  • [LARGEST-CONTENTFUL-PAINT] defines the following terms:
    • LargestContentfulPaint
    • renderTime
  • [LONG-ANIMATION-FRAME] defines the following terms:
    • current frame timing info
    • Queue a long animation frame entry
  • [LONG-ANIMATION-FRAMES] defines the following terms:
    • PerformanceLongAnimationFrameTiming
  • [PERFORMANCE-TIMELINE] defines the following terms:
    • PerformanceEntry
    • duration
    • entryType
    • name
    • performance timeline task source
    • queue a PerformanceEntry
    • startTime
    • supportedEntryTypes
  • [SELECTORS-4] defines the following terms:
    • originating element
  • [SVG2] defines the following terms:
    • SVGImageElement
    • image
    • svg
  • [URL] defines the following terms:
    • scheme
  • [WEBIDL] defines the following terms:
    • DOMString
    • Default
    • Exposed
    • default toJSON steps
    • new
    • object
    • platform object
    • this

References

Normative References

[CSS-BACKGROUNDS-3]
Elika Etemad; Brad Kemper. [CSS-CASCADE-5]
Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. https://drafts.csswg.org/css-cascade-5/
[CSS-COLOR-3]
Tantek Çelik; Chris Lilley; David Baron. https://drafts.csswg.org/css-color-3/
[CSS-DISPLAY-4]
Elika Etemad; Tab Atkins Jr.. https://drafts.csswg.org/css-display-4/
[CSS-FONTS-4]
Chris Lilley. https://drafts.csswg.org/css-fonts-4/
[CSS-TEXT-4]
Elika Etemad; et al. https://drafts.csswg.org/css-text-4/
[CSSOM-VIEW-1]
Simon Fraser; Emilio Cobos Álvarez. [DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[ELEMENT-TIMING]
[HR-TIME-3]
Yoav Weiss. [HTML]
Anne van Kesteren; et al. https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[PERFORMANCE-TIMELINE]
Nicolas Pena Moreno. [RFC2119]
S. Bradner. https://datatracker.ietf.org/doc/html/rfc2119
[SELECTORS-4]
Elika Etemad; Tab Atkins Jr.. https://drafts.csswg.org/selectors/
[SVG2]
Amelia Bellamy-Royds; et al. [WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

Informative References

[EVENT-TIMING]
Michal Mocny. [LARGEST-CONTENTFUL-PAINT]
Yoav Weiss; Nicolas Pena Moreno. https://w3c.github.io/largest-contentful-paint/
[LONG-ANIMATION-FRAMES]
https://w3c.github.io/long-animation-frames/
[URL]
Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/

IDL Index

[Exposed=Window]
interface mixin PaintTimingMixin {
    readonly attribute DOMHighResTimeStamp paintTime;
    readonly attribute DOMHighResTimeStamp? presentationTime;
};

[Exposed=Window]
interface PerformancePaintTiming : PerformanceEntry {
    [object toJSON();
};
PerformancePaintTiming includes PaintTimingMixin;

Issues Index

This should be turned into a normative note.
MDN

PerformancePaintTiming

In all current engines.

Firefox84+Safari14.1+Chrome60+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?

Follow Lee on X/Twitter - Father, Husband, Serial builder creating AI, crypto, games & web tools. We are friends :) AI Will Come To Life!

Check out: eBank.nz (Art Generator) | Netwrck.com (AI Tools) | Text-Generator.io (AI API) | BitBank.nz (Crypto AI) | ReadingTime (Kids Reading) | RewordGame | BigMultiplayerChess | WebFiddle | How.nz | Helix AI Assistant