⏱ Collect and measure browser performance metrics
All metrics are converted to snake_case
import { navigation, paint } from 'page-timing';
window.addEventListener(
'load',
() => {
const metrics = {
...paint(),
...navigation()
};
fetch('/browser-performance-metrics', {
method: 'POST',
body: JSON.stringify({
page_name: 'my page',
metrics
}),
});
}
);
navigation
: Navigation Timing Illustration 🎨paint
: Paint Timingassets
: Information about page resources when this function is calledconnection
: Network Informationmemory
: Memory API informationdisplay
: Screen and document informationdom
: Calculated metrics from the document objectall
: A compound object containing all of the abovemeasure
: A helper function: Add measure entries to navigation timing API
Group | Name | Type | Meaning |
---|---|---|---|
navigation | navigation_start |
number | Termination of previous document upon navigating |
navigation | unload_event_start |
number | Previous document unload |
navigation | unload_event_end |
number | |
navigation | redirect_start |
number | Redirect from previous document |
navigation | redirect_end |
number | |
navigation | fetch_start |
number | Ready to fetch the document |
navigation | domain_lookup_start |
number | |
navigation | domain_lookup_end |
number | |
navigation | connect_start |
number | Sent request to open a connection |
navigation | connect_end |
number | |
navigation | secure_connection_start |
number | Secure connection handshake |
navigation | request_start |
number | Request the document |
navigation | response_start |
number | Received the first byte of the response |
navigation | response_end |
number | Received the last byte of the response |
navigation | dom_loading |
number | Parser started work |
navigation | dom_interactive |
number | Parser finished work on main document. Changed document readyState to "interactive" |
navigation | dom_content_loaded_event_start |
number | Executed required scripts after parsing the document |
navigation | dom_content_loaded_event_end |
number | |
navigation | dom_complete |
number | Changed document readyState to "complete" |
navigation | load_event_start |
number | Document fires "load" event |
navigation | load_event_end |
number | |
navigation | transfer_size |
number | Size (octets) of response headers and payload body |
navigation | encoded_body_size |
number | Size (octets) of payload body |
navigation | decoded_body_size |
number | Size (octets) of message body |
paint | first_paint |
number | User agent first rendered after navigation |
paint | first_contentful_paint |
number | Document contains at least one element that is paintable and contentful† |
assets | final_asset_javascript_count |
number | Total number of Javascript resources |
assets | final_asset_javascript_load |
number | Loading time spent on Javascript resources |
assets | final_asset_javascript_size |
number | Total size of Javascript resources |
assets | final_asset_stylesheets_count |
number | Total number of CSS resources |
assets | final_asset_stylesheets_load |
number | Loading time spent on CSS resources |
assets | final_asset_stylesheets_size |
number | Total size of CSS resources |
assets | final_asset_images_count |
number | Total number of image resources |
assets | final_asset_images_load |
number | Loading time spent on image resources |
assets | final_asset_images_size |
number | Total size of image resources |
assets | final_asset_other_count |
number | Total number of other resources |
assets | final_asset_other_load |
number | Loading time spent on other resources |
assets | final_asset_other_size |
number | Total size of other resources |
connection | connection_type |
string | bluetooth, cellular, ethernet, none, wifi, wimax, other, unknown |
connection | effective_bandwidth |
number | Mbps |
connection | effective_connection_type |
string | slow-2g, 2g, 3g, 4g |
connection | effective_max_bandwidth |
number | Mbps |
connection | reduced_data_usage |
boolean | Vendor's "Data Saver" feature enables |
connection | round_trip_time |
number | Estimated effective round-trip in ms |
memory | js_heap_size_limit |
number | Maximum bytes available for JS heap |
memory | total_js_heap_size |
number | Total allocated bytes for JS heap |
memory | used_js_heap_size |
number | Currently active bytes of JS heap |
display | window_inner_height |
number | Height of the window's layout viewport |
display | window_inner_width |
number | Width of the window's layout viewport |
display | screen_color_depth |
number | Color depth of the screen |
display | screen_pixel_depth |
number | Bit depth of the screen |
display | screen_orientation_type |
string | landscape-primary, landscape-secondary, portrait-primary, portrait-secondary |
dom | final_dom_node_count |
number | Total number of nodes under the document object |
dom | final_dom_nest_depth |
number | Highest nesting depth of DOM element under the document |
dom | final_html_size |
number | Character count of the HTML document |
† contentful element: A visible element which contains non empty text, media content or input.
Measure page frame rate at a certain point in time
import { fps } from 'page-timing';
const frames_per_second = await fps();
console.log({ frames_per_second });
Increase sample rate by checking more than one second. (Result is still in frames per second)
const frames_per_second = await fps({ sample: 5 });
console.log({ frames_per_second });
Wrap a function and measure it's execution time in milliseconds into a performance measure entry.
import { measure } from 'page-timing';
async function myFunction(
await wait(50);
doSomethingElse();
}
await measure(myFunction, 'my-function');
// Example: Convert entries to a named array
Object.assign(
...performance.getEntriesByType('measure').map(
({ name, duration }) => ({[name]: duration})
)
);
// {my-function: 53.35999990347773}
// Example: Retrieve a specific entry
const { duration } = performance.getEntriesByName('my-function');
// 53.35999990347773
Also send web vitals, a simple example
import { all } from 'page-timing';
import { getLCP, getFID, getCLS } from 'web-vitals';
window.addEventListener(
'load',
() => {
// Send metrics from browser performance API
fetch('/browser-performance-metrics', {
method: 'POST',
body: JSON.stringify({
page_name: 'my page',
metrics: all()
}),
});
// Send web vitals to the same endpoint
[
[getLCP, 'largest_contentful_paint'],
[getFID, 'first_input_delay'],
[getCLS, 'comulative_layout_shift'],
].forEach(
([ fn, name ]) => fn(
({ value }) => fetch('/browser-performance-metrics', {
method: 'POST',
body: JSON.stringify({
page_name: 'my page',
metrics: { [name]: value }
}),
})
)
);
}
);