Copyright © 2025 World Wide Web Consortium . W3C ® liability , trademark and permissive document license rules apply.
This specification extends the High Resolution Time specification [ HR-TIME-3 ] by providing methods to store and retrieve high resolution performance metric data.
This section describes the status of this document at the time of its publication. A list of current W3C publications and the latest revision of this technical report can be found in the W3C standards and drafts index at https://www.w3.org/TR/.
This Performance Timeline specification replaces the first version of [ PERFORMANCE-TIMELINE ] and includes:
Performance
interface
defined
by
[
HR-TIME-3
];
PerformanceEntry
in
Web
Workers
[
WORKERS
];
PerformanceObserver
.
This document was published by the Web Performance Working Group as an Editor's Draft.
Publication as an Editor's Draft does not imply endorsement by W3C and its Members.
This is a draft document and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the W3C Patent Policy . W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy .
This document is governed by the 03 November 2023 W3C Process Document .
This section is non-normative.
Accurately measuring performance characteristics of web applications is an important aspect of making web applications faster. This specification defines the necessary Performance Timeline primitives that enable web developers to access, instrument, and retrieve various performance metrics from the full lifecycle of a web application.
[ NAVIGATION-TIMING-2 ], [ RESOURCE-TIMING-2 ], and [ USER-TIMING-2 ] are examples of specifications that define timing information related to the navigation of the document, resources on the page, and developer scripts, respectively. Together these and other performance interfaces define performance metrics that describe the Performance Timeline of a web application. For example, the following script shows how a developer can access the Performance Timeline to obtain performance metrics related to the navigation of the document, resources on the page, and developer scripts:
<!doctype html>
<html>
<head></head>
<body onload="init()">
<img id="image0" src="https://www.w3.org/Icons/w3c_main.png" />
<script>
function init() {
// see [[USER-TIMING-2]]
performance.mark("startWork");
doWork(); // Some developer code
performance.mark("endWork");
measurePerf();
}
function measurePerf() {
performance
.getEntries()
.map(entry => JSON.stringify(entry, null, 2))
.forEach(json => console.log(json));
}
</script>
</body>
</
html
>
Alternatively,
the
developer
can
observe
the
Performance
Timeline
and
be
notified
of
new
performance
metrics
and,
optionally,
previously
buffered
performance
metrics
of
specified
type,
via
the
PerformanceObserver
interface.
The
PerformanceObserver
interface
was
added
and
is
designed
to
address
limitations
of
the
buffer-based
approach
shown
in
the
first
example.
By
using
the
PerformanceObserver
interface,
the
application
can:
The
developer
is
encouraged
to
use
PerformanceObserver
where
possible.
Further,
new
performance
API's
and
metrics
may
only
be
available
through
the
PerformanceObserver
interface.
The
observer
works
by
specifying
a
callback
in
the
constructor
and
specifying
the
performance
entries
it's
interested
in
via
the
observe()
method.
The
user
agent
chooses
when
to
execute
the
callback,
which
receives
performance
entries
that
have
been
queued.
There
are
special
considerations
regarding
initial
page
load
when
using
the
PerformanceObserver
interface:
a
registration
must
be
active
to
receive
events
but
the
registration
script
may
not
be
available
or
may
not
be
desired
in
the
critical
path.
To
address
this,
user
agents
buffer
some
number
of
events
while
the
page
is
being
constructed,
and
these
buffered
events
can
be
accessed
via
the
buffered
flag
when
registering
the
observer.
When
this
flag
is
set,
the
user
agent
retrieves
and
dispatches
events
that
it
has
buffered,
for
the
specified
entry
type,
and
delivers
them
in
the
first
callback
after
the
observe()
call
occurs.
The number of buffered events is determined by the specification that defines the metric and buffering is intended to used for first-N events only; buffering is not unbounded or continuous.
<!doctype html>
<html>
<head></head>
<body>
<img id="image0" src="https://www.w3.org/Icons/w3c_main.png" />
<script>
// Know when the entry types we would like to use are not supported.
function detectSupport(entryTypes) {
for (const entryType of entryTypes) {
if (!PerformanceObserver.supportedEntryTypes.includes(entryType)) {
// Indicate to client-side analytics that |entryType| is not supported.
}
}
}
detectSupport(["resource", "mark", "measure"]);
const userTimingObserver = new PerformanceObserver(list => {
list
.getEntries()
// Get the values we are interested in
.map(({ name, entryType, startTime, duration }) => {
const obj = {
"Duration": duration,
"Entry Type": entryType,
"Name": name,
"Start Time": startTime,
};
return JSON.stringify(obj, null, 2);
})
// Display them to the console.
.forEach(console.log);
// Disconnect after processing the events.
userTimingObserver.disconnect();
});
// Subscribe to new events for User-Timing.
userTimingObserver.observe({entryTypes: ["mark", "measure"]});
const resourceObserver = new PerformanceObserver(list => {
list
.getEntries()
// Get the values we are interested in
.map(({ name, startTime, fetchStart, responseStart, responseEnd }) => {
const obj = {
"Name": name,
"Start Time": startTime,
"Fetch Start": fetchStart,
"Response Start": responseStart,
"Response End": responseEnd,
};
return JSON.stringify(obj, null, 2);
})
// Display them to the console.
.forEach(console.log);
// Disconnect after processing the events.
resourceObserver.disconnect();
});
// Retrieve buffered events and subscribe to newer events for Resource Timing.
resourceObserver.observe({type: "resource", buffered: true});
</script>
</body>
</
html
>
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key words MUST , MUST NOT , and SHOULD in this document are to be interpreted as described in BCP 14 [ RFC2119 ] [ RFC8174 ] when, and only when, they appear in all capitals, as shown here.
Conformance requirements phrased as algorithms or specific steps may 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 follow, and not intended to be performant).
Each global object has:
DOMString
,
representing
the
entry
type
to
which
the
buffer
belongs.
The
map
's
value
is
the
following
tuple:
PerformanceEntry
objects,
that
is
initially
empty.
boolean
availableFromTimeline
,
initialized
to
the
registry
value
for
this
entry
type.
Each Document has:
PerformanceEntry
,
initially
unset.
In order to get the relevant performance entry tuple , given entryType and globalObject as input, run the following steps:
Performance
interface
This
extends
the
Performance
interface
from
[
HR-TIME-3
]
and
hosts
performance
related
attributes
and
methods
used
to
retrieve
the
performance
metric
data
from
the
Performance
Timeline
.
WebIDLpartial interface Performance {
PerformanceEntryList
getEntries
();
PerformanceEntryList
getEntriesByType
(DOMString type);
PerformanceEntryList
getEntriesByName
(DOMString name, optional DOMString type);
};
typedef
sequence
<
PerformanceEntry
>
PerformanceEntryList
;
The
PerformanceEntryList
represents
a
sequence
of
PerformanceEntry
,
providing
developers
with
all
the
convenience
methods
found
on
JavaScript
arrays.
Returns
a
PerformanceEntryList
object
returned
by
the
filter
buffer
map
by
name
and
type
algorithm
with
name
and
type
set
to
null
.
Returns
a
PerformanceEntryList
object
returned
by
filter
buffer
map
by
name
and
type
algorithm
with
name
set
to
null
,
and
type
set
to
the
method's
input
type
parameter.
Returns
a
PerformanceEntryList
object
returned
by
filter
buffer
map
by
name
and
type
algorithm
with
name
set
to
the
method
input
name
parameter,
and
type
set
to
null
if
optional
entryType
is
omitted,
or
set
to
the
method's
input
type
parameter
otherwise.
The
PerformanceEntry
interface
hosts
the
performance
data
of
various
metrics.
WebIDL[Exposed=(Window,Worker)]
interface PerformanceEntry
{
readonly attribute unsigned long long id
;
readonly attribute DOMString name
;
readonly attribute DOMString entryType
;
readonly attribute DOMHighResTimeStamp startTime
;
readonly attribute DOMHighResTimeStamp duration
;
[Default] object toJSON
();
};
name
PerformanceEntry
object.
This
identifier
does
not
have
to
be
unique.
entryType
All
entryType
values
are
defined
in
the
relevant
registry
.
Examples
include:
"mark"
and
"measure"
[
USER-TIMING-2
],
"navigation"
[
NAVIGATION-TIMING-2
],
and
"resource"
[
RESOURCE-TIMING-2
].
startTime
duration
duration
attribute
are
to
return
0
if
this
's
end
time
is
0;
otherwise
this
's
end
time
-
this
's
startTime
.
navigationId
When
toJSON
is
called,
run
[
WebIDL
]'s
default
toJSON
steps
.
A
PerformanceEntry
has
a
DOMHighResTimeStamp
end
time
,
initially
0.
To
initialize
a
PerformanceEntry
entry
given
a
DOMHighResTimeStamp
startTime
,
a
DOMString
entryType
,
a
DOMString
name,
and
an
optional
DOMHighResTimeStamp
endTime
(default
0
):
startTime
to
startTime
.
entryType
to
entryType
.
name
to
name
.
The
PerformanceObserver
interface
can
be
used
to
observe
the
Performance
Timeline
to
be
notified
of
new
performance
metrics
as
they
are
recorded,
and
optionally
buffered
performance
metrics.
Each
PerformanceObserver
has
these
associated
concepts:
PerformanceObserverCallback
observer
callback
set
on
creation.
PerformanceEntryList
object
called
the
observer
buffer
that
is
initially
empty.
DOMString
observer
type
which
is
initially
"undefined"
.
The
PerformanceObserver(callback)
constructor
must
create
a
new
PerformanceObserver
object
with
its
observer
callback
set
to
callback
and
then
return
it.
A
registered
performance
observer
is
a
struct
consisting
of
an
observer
member
(a
PerformanceObserver
object)
and
an
options
list
member
(a
list
of
PerformanceObserverInit
dictionaries).
WebIDLcallback PerformanceObserverCallback
= undefined (PerformanceObserverEntryList
entries,
PerformanceObserver
observer,
optional PerformanceObserverCallbackOptions
options = {});
[Exposed=(Window,Worker)]
interface PerformanceObserver
{
constructor
(PerformanceObserverCallback
callback);
undefined observe
(optional PerformanceObserverInit
options = {});
undefined disconnect
();
PerformanceEntryList
takeRecords
();
[SameObject] static readonly attribute FrozenArray<DOMString> supportedEntryTypes
;
};
To keep the performance overhead to minimum the application ought to only subscribe to event types that it is interested in, and disconnect the observer once it no longer needs to observe the performance data. Filtering by name is not supported, as it would implicitly require a subscription for all event types — this is possible, but discouraged, as it will generate a significant volume of events.
WebIDLdictionary PerformanceObserverCallbackOptions
{
unsigned long long droppedEntriesCount
;
};
droppedEntriesCount
PerformanceObserver
's
requires
dropped
entries
is
set.
The
observe()
method
instructs
the
user
agent
to
register
the
observer
and
must
run
these
steps:
entryTypes
and
type
members
are
both
omitted,
then
throw
a
"
TypeError
".
entryTypes
is
present
and
any
other
member
is
also
present,
then
throw
a
"
TypeError
".
"undefined"
:
entryTypes
member
is
present,
then
set
this
's
observer
type
to
"multiple"
.
type
member
is
present,
then
set
this
's
observer
type
to
"single"
.
"single"
and
options
's
entryTypes
member
is
present,
then
throw
an
"
InvalidModificationError
".
"multiple"
and
options
's
type
member
is
present,
then
throw
an
"
InvalidModificationError
".
"multiple"
,
run
the
following
steps:
entryTypes
sequence.
"single"
.
type
is
not
contained
in
the
relevantGlobal
's
frozen
array
of
supported
entry
types
,
abort
these
steps.
The
user
agent
SHOULD
notify
developers
when
this
happens,
for
instance
via
a
console
warning.
PerformanceObserverInit
item
currentOptions
whose
type
is
equal
to
options
's
type
,
replace
currentOptions
with
options
in
obs
's
options
list
.
buffered
flag
is
set:
type
and
relevantGlobal
.
For each entry in tuple 's performance entry buffer :
A
PerformanceObserver
object
needs
to
always
call
observe()
with
options
's
entryTypes
set
OR
always
call
observe()
with
options
's
type
set.
If
one
PerformanceObserver
calls
observe()
with
entryTypes
and
also
calls
observe
with
type
,
then
an
exception
is
thrown.
This
is
meant
to
avoid
confusion
with
how
calls
would
stack.
When
using
entryTypes
,
no
other
parameters
in
PerformanceObserverInit
can
be
used.
In
addition,
multiple
observe()
calls
will
override
for
backwards
compatibility
and
because
a
single
call
should
suffice
in
this
case.
On
the
other
hand,
when
using
type
,
calls
will
stack
because
a
single
call
can
only
specify
one
type.
Calling
observe()
with
a
repeated
type
will
also
override.
WebIDLdictionary PerformanceObserverInit
{
sequence<DOMString> entryTypes
;
DOMString type
;
boolean buffered
;
};
entryTypes
type
buffered
WebIDL[Exposed=(Window,Worker)]
interface PerformanceObserverEntryList
{
PerformanceEntryList
getEntries
();
PerformanceEntryList
getEntriesByType
(DOMString type);
PerformanceEntryList
getEntriesByName
(DOMString name, optional DOMString type);
};
Each
PerformanceObserverEntryList
object
has
an
associated
entry
list
,
which
consists
of
a
PerformanceEntryList
and
is
initialized
upon
construction.
Returns
a
PerformanceEntryList
object
returned
by
filter
buffer
by
name
and
type
algorithm
with
this
's
entry
list
,
name
and
type
set
to
null
.
Returns
a
PerformanceEntryList
object
returned
by
filter
buffer
by
name
and
type
algorithm
with
this
's
entry
list
,
name
set
to
null
,
and
type
set
to
the
method's
input
type
parameter.
Returns
a
PerformanceEntryList
object
returned
by
filter
buffer
by
name
and
type
algorithm
with
this
's
entry
list
,
name
set
to
the
method
input
name
parameter,
and
type
set
to
null
if
optional
entryType
is
omitted,
or
set
to
the
method's
input
type
parameter
otherwise.
The
takeRecords()
method
must
return
a
copy
of
this
's
observer
buffer
,
and
also
empty
this
's
observer
buffer
.
The
disconnect()
method
must
do
the
following:
supportedEntryTypes
attribute
Each global object has an associated frozen array of supported entry types , which is initialized to the FrozenArray created from the sequence of strings among the registry that are supported for the global object, in alphabetical order.
When
supportedEntryTypes
's
attribute
getter
is
called,
run
the
following
steps:
This attribute allows web developers to easily know which entry types are supported by the user agent.
To queue a PerformanceEntry ( newEntry ), run these steps:
id
is
unset:
id
to
id
.
PerformanceObserver
objects.
entryType
value.
navigationId
to
the
value
of
relevantGlobal
's
associated
document
's
most
recent
navigation
's
id
.
navigationId
to
null.
If
regObs
's
options
list
contains
a
PerformanceObserverInit
options
whose
entryTypes
member
includes
entryType
or
whose
type
member
equals
to
entryType
:
When asked to queue the PerformanceObserver task , given relevantGlobal as input, run the following steps:
PerformanceObserverEntryList
,
with
its
entry
list
set
to
entries
.
PerformanceObserverInit
item
in
registeredObserver
's
options
list
:
type
or
in
item
's
entryTypes
:
PerformanceObserverCallbackOptions
with
its
droppedEntriesCount
set
to
droppedEntriesCount
if
droppedEntriesCount
is
not
null,
otherwise
unset.
report
the
exception
.
",
and
po
.
The performance timeline task queue is a low priority queue that, if possible, should be processed by the user agent during idle periods to minimize impact of performance monitoring code.
When asked to run the filter buffer map by name and type algorithm with optional name and type , run the following steps:
startTime
When asked to run the filter buffer by name and type algorithm, with buffer , name , and type as inputs, run the following steps:
PerformanceEntry
entry
in
buffer
,
run
the
following
steps:
entryType
attribute,
continue
to
next
entry
.
name
attribute,
continue
to
next
entry
.
startTime
To determine if a performance entry buffer is full , with tuple as input, run the following steps:
When
asked
to
generate
an
id
for
a
PerformanceEntry
entry,
run
the
following
steps:
A user agent may choose to increase the last performance entry id it by a small random integer every time. A user agent must not pick a single global random integer and increase the last performance entry id of all global objects by that amount because this could introduce cross origin leaks.
The last performance entry id has an initial random value, and is increased by a small number chosen by the user agent instead of 1 to discourage developers from considering it as a counter of the number of entries that have been generated in the web application.
This
specification
extends
the
Performance
interface
defined
by
[
HR-TIME-3
]
and
provides
methods
to
queue
and
retrieve
entries
from
the
performance
timeline
.
Please
refer
to
[
HR-TIME-3
]
for
privacy
considerations
of
exposing
high-resoluting
timing
information.
Each
new
specification
introducing
new
performance
entries
should
have
its
own
privacy
considerations
as
well.
The
last
performance
entry
id
is
deliberately
initialized
to
a
random
value,
and
is
incremented
by
another
small
value
every
time
a
new
PerformanceEntry
is
queued.
User
agents
may
choose
to
use
a
consistent
increment
for
all
users,
or
may
pick
a
different
increment
for
each
global
object
,
or
may
choose
a
new
random
increment
for
each
PerformanceEntry
.
However,
in
order
to
prevent
cross-origin
leaks,
and
ensure
that
this
does
not
enable
fingerprinting,
user
agents
must
not
just
pick
a
unique
random
integer,
and
use
it
as
a
consistent
increment
for
all
PerformanceEntry
objects
across
all
global
objects
.
This
specification
extends
the
Performance
interface
defined
by
[
HR-TIME-3
]
and
provides
methods
to
queue
and
retrieve
entries
from
the
performance
timeline
.
Please
refer
to
[
HR-TIME-3
]
for
security
considerations
of
exposing
high-resoluting
timing
information.
Each
new
specification
introducing
new
performance
entries
should
have
its
own
security
considerations
as
well.
The [ INFRA ] specification defines the following: key , getting the value of an entry .
WebIDLpartial interface Performance {
PerformanceEntryList
getEntries
();
PerformanceEntryList
getEntriesByType
(DOMString type);
PerformanceEntryList
getEntriesByName
(DOMString name, optional DOMString type);
};
typedef sequence<PerformanceEntry
> PerformanceEntryList
;
[Exposed=(Window,Worker)]
interface PerformanceEntry
{
readonly attribute unsigned long long id
;
readonly attribute DOMString name
;
readonly attribute DOMString entryType
;
readonly attribute DOMHighResTimeStamp startTime
;
readonly attribute DOMHighResTimeStamp duration
;
readonly attribute unsigned long long navigationId
;
[Default] object toJSON
();
};
callback PerformanceObserverCallback
= undefined (PerformanceObserverEntryList
entries,
PerformanceObserver
observer,
optional PerformanceObserverCallbackOptions
options = {});
[Exposed=(Window,Worker)]
interface PerformanceObserver
{
constructor
(PerformanceObserverCallback
callback);
undefined observe
(optional PerformanceObserverInit
options = {});
undefined disconnect
();
PerformanceEntryList
takeRecords
();
[SameObject] static readonly attribute FrozenArray<DOMString> supportedEntryTypes
;
};
dictionary PerformanceObserverCallbackOptions
{
unsigned long long droppedEntriesCount
;
};
dictionary PerformanceObserverInit
{
sequence<DOMString> entryTypes
;
DOMString type
;
boolean buffered
;
};
[Exposed=(Window,Worker)]
interface PerformanceObserverEntryList
{
PerformanceEntryList
getEntries
();
PerformanceEntryList
getEntriesByType
(DOMString type);
PerformanceEntryList
getEntriesByName
(DOMString name, optional DOMString type);
};
Thanks to Arvind Jain, Boris Zbarsky, Jatinder Mann, Nat Duca, Philippe Le Hegaret, Ryosuke Niwa, Shubhie Panicker, Todd Reifsteck, Yoav Weiss, and Zhiheng Wang, for their contributions to this work.
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: