A utility library for collecting web performance metrics
that affect user experience.
Modern web platform provides a lot of APIs to analyze page speed information. But it's hard to follow them and even harder to deal with the lack of implementation in different browsers.
UXM is a modular library that allows to combine various functions and collect the data you need. Think about it, as Lodash for user experience APIs.
Use cases:
- Collect RUM data.
- Build private version of Chrome User Experience Report.
- Audit the page performance using Puppeteer (example).
- Dynamically evaluate the performance of the user's device and adapt the UI.
Features:
- Modular design based on ES modules.
- Small size (1kb gzip). It's usually smaller if you use Tree Shaking.
- Graceful support of latest browser APIs like Performance Paint Timing, Network Information, or Device Memory.
- Fully featured User Timing API support.
- Lightweight device type parser.
- Experimental Long Tasks support for interactivity metrics.
Install using yarn/npm:
yarn add uxm
npm i -S uxm
Import uxm
and call it at the end of the page loading to collect CrUX-like data:
import { uxm } from 'uxm'
uxm().then(metrics => {
console.log(metrics) // ->
{
"deviceType": "desktop",
"effectiveConnectionType": "4g",
"firstPaint": 1646,
"firstContentfulPaint": 1646,
"domContentLoaded": 1698,
"onLoad": 2508
}
})
Or collect 2 performance metrics associated with URL:
import { getUrl, getFirstContentfulPaint, getDomContentLoaded } from 'uxm'
const metrics = {
url: getUrl(),
fcp: getFirstContentfulPaint(),
dcl: getDomContentLoaded()
}
Or analyze current device and connection:
import { getDeviceType, getDeviceMemory, getEffectiveConnectionType } from 'uxm'
const device = {
type: getDeviceType(),
memory: getDeviceMemory(),
connection: getEffectiveConnectionType()
}
An API is a set of pure functions with one exception to uxm
,
which is a meta-function to collect multiple metrics at once.
Returns a Promise that resolves after load
event fired.
A default set of metrics is defined by Chrome User Experience Report, but you can customize them using options (url
, userAgent
, deviceMemory
, userTiming
, longTasks
, resources
).
Or pass all
to get the full report:
import { uxm } from 'uxm'
uxm({ all: true }).then(metrics => {
console.log(metrics) // ->
{
"deviceType": "phone",
"effectiveConnectionType": "4g",
"firstPaint": 531,
"firstContentfulPaint": 531,
"domContentLoaded": 768,
"onLoad": 1317,
"url": "https://www.booking.com/",
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1",
"deviceMemory": "full",
"userTiming": [
{
"type": "measure",
"name": "b-stylesheets",
"startTime": 0,
"duration": 436
},
...
],
"longTasks": [
{
"startTime": 587,
"duration": 79
},
...
],
"resources": [
{
"url": "https://booking.com/",
"type": "navigation",
"size": 77953,
"startTime": 0,
"duration": 1568
},
...
]
}
})
Create User Timing mark to mark important loading event. A convenient shortcut for window.performance.mark
.
import { mark } from 'uxm'
mark('page load started')
// ...
mark('hero image displayed')
// ...
mark('page fully loaded')
Create User Timing measure to evaluate timing between 2 marks.
A convenient shortcut for window.performance.measure
.
import { mark, measure } from 'uxm'
mark('start load fonts')
// ...
measure('fonts loaded', 'start load fonts')
It returns an array with collected performance marks/measures. Each item contains:
type
- "mark" or "measure"name
- unique namestartTime
- start time since page loadduration
- measure duration
Example:
[
{
"type": "mark",
"name": "boot",
"startTime": 1958
},
{
"type": "measure",
"name": "page did mount",
"startTime": 1958,
"duration": 197
}
]
It returns the time when first paint which includes text, image (including background images), non-white canvas, or SVG happened. W3C draft for Paint Timing 1.
It's similar to getFirstContentfulPaint
but may contain a different value when First Paint is just background change without content.
It returns the time when DOMContentLoaded
event was fired.
It returns the time when load
event was fired.
It returns the effective connection type (“slow-2g”, “2g”, “3g”, or “4g”) string as determined by round-trip and bandwidth values. W3C draft for Network Information API.
It returns the device type ("phone", "tablet", or "desktop") string using the lightweight heavy-tested user-agent parser.
It returns the device memory ("full" or "lite") string, depends if available memory is bigger than 1 GB. Learn more about Device Memory.
It returns a current page URL. A convenient shortcut for window.location.href
.
It returns a User-Agent string. A convenient shortcut for window.navigator.userAgent
.
It returns an array of performance information for each resource on the page. Each item contains:
url
- resource URLtype
- one of resource types ("navigation", "link", "img", "script", "xmlhttprequest", or "font")size
- transferred size in bytesstartTime
- when load startedduration
- loading time in milliseconds
Example:
[
{
"url": "https://booking.com/",
"type": "navigation",
"size": 79263,
"startTime": 0,
"duration": 1821
},
{
"url": "https://q-fa.bstatic.com/mobile/css/core_not_critical_fastly.iq_ltr/8051b1d9fafb2e6339aea397447edfded9320dbb.css",
"type": "link",
"size": 54112,
"startTime": 515,
"duration": 183
},
{
"url": "https://r-fa.bstatic.com/mobile/images/hotelMarkerImgLoader/211f81a092a43bf96fc2a7b1dff37e5bc08fbbbf.gif",
"type": "img",
"size": 2295,
"startTime": 657,
"duration": 181
},
{
"url": "https://r-fa.bstatic.com/static/js/error_catcher_bec_fastly/ba8921972cc55fbf270bafe168450dd34597d5a1.js",
"type": "script",
"size": 2495,
"startTime": 821,
"duration": 43
},
...
]
It returns an array of { startTime, duration }
pairs.
Until buffered
flag supported, you need to add extra script to the <head />
to collect all Long Tasks:
<script>
!function(){if('PerformanceLongTaskTiming' in window){var g=window.__lt={e:[]};
g.o=new PerformanceObserver(function(l){g.e=g.e.concat(l.getEntries())});
g.o.observe({entryTypes:['longtask']})}}();
</script>
And then get them using:
import { getLongTasks } from 'uxm'
getLongTasks() // [{"startTime": 672, "duration": 84}, {"startTime": 931, "duration": 84}, {"startTime": 1137, "duration": 135}]
Learn more about Long Tasks.
Sponsored by Treo.sh - Page speed monitoring made easy.