The Chrome User Experience Report provides metrics for how real-world Chrome users experience popular destinations on the web. You can integrate with the Chrome UX Report API to monitor metrics, extract insights, and better understand the user's experience.
Prerequisites
This tutorial assumes that you have general knowledge of command line interfaces and web development. You will also need an API key to use the API.
Acquiring and using an API key
Get a KeyOr create one in the Credentials page.
After you have an API key, your application can append the query parameter
key=yourAPIKey
to all request URLs.
The API key is safe for embedding in URLs; it doesn't need any encoding.
cURL
To try out the Chrome UX Report API from the command line:
- Open a terminal.
In the following command, replace
API_KEY
in the request URL with a key you’ve generated:curl https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=API_KEY \ --header 'Content-Type: application/json' --data '{"origin":"https://google.com"}'
The response is a JSON object. See Response to learn more about each of the properties in the response object.
{ "record": { "key": { "origin": "https://google.com" }, "metrics": { "largest_contentful_paint": { "histogram": [ { "start": 0, "end": 2500, "density": 0.42234999999999934 }, { "start": 2500, "end": 4000, "density": 0.19334999999999969 }, { "start": 4000, "density": 0.38429999999999509 } ], "percentiles": { "p75": 5269 } }, "cumulative_layout_shift": { "histogram": [ { "start": "0.00", "end": "0.10", "density": 0.6688337667533506 }, { "start": "0.10", "end": "0.25", "density": 0.23934786957391477 }, { "start": "0.25", "density": 0.091818363672734646 } ], "percentiles": { "p75": "0.14" } }, "first_contentful_paint": { "histogram": [ { "start": 0, "end": 1800, "density": 0.52295229522952436 }, { "start": 1800, "end": 3000, "density": 0.19611961196119665 }, { "start": 3000, "density": 0.280928092809278 } ], "percentiles": { "p75": 3230 } }, "first_input_delay": { "histogram": [ { "start": 0, "end": 100, "density": 0.69926014797040625 }, { "start": 100, "end": 300, "density": 0.285642871425715 }, { "start": 300, "density": 0.015096980603879248 } ], "percentiles": { "p75": 285 } } } } }
JavaScript
To try out the CrUX API on the web:
Insert Your API key.
var apiKey = "API_KEY";
Open the code in JS Fiddle and run! The code uses the CrUX API to get the performance data for https://example.com, and then displays the results.
JavaScript
/** * @url https://developers.google.com/web/tools/chrome-user-experience-report/api/guides/getting-started */ const CrUXApiUtil = { /** * Query the CrUX API for metric records * @param {{origin?: string, url?: string, formFactor?: string, metrics?: Array<string>}} requestBody * @param {string} apiKey * @return {{record: {key: Object, metrics: Map<string, {histogram: Array<{ start: number, end?: number, density: number}>}>}, urlNormalizationDetails: Object}} */ query: async function (requestBody, apiKey) { const endpointUrl = 'https://chromeuxreport.googleapis.com/v1/records:queryRecord'; const resp = await fetch(`${endpointUrl}?key=${apiKey}`, { method: 'POST', body: JSON.stringify(requestBody), }); const json = await resp.json(); if (!resp.ok) throw new Error(json.error.message); return json; } }; // Gather the data for example.com and display it (async function () { const json = await CrUXApiUtil.query({origin: 'https://example.com/'}, apiKey); console.log('CrUX API response:', json); const labeledMetrics = labelMetricData(json.record.metrics); // Display metric results for (const metric of labeledMetrics) { const metricEl = document.createElement('section'); const titleEl = document.createElement('h2'); titleEl.textContent = metric.acronym; const [descEl, barsEl] = createDescriptionAndBars(metric.labeledBins); metricEl.append(titleEl, descEl, barsEl); document.getElementById('wrapper').append(metricEl); } })(); /** * Utility method to transform the response's metric data into an array of usable metric objects * Example return value: [ { "acronym": "FCP", "name": "first_contentful_paint", "labeledBins": [{ "label": "good", "percentage": 43.51, "start": 0, "end": 1000, "density": 0.4351 }, // ... (other bins) ] }, // ... (other metrics) ] * * @return {{acronym: string, name: string, labelsBins: Array<{label: 'good'|'needs improvement'|'poor', percentage: number, start: number, end?: number, density: number}>}} */ function labelMetricData(metrics) { const nameToAcronymMap = { first_contentful_paint: 'FCP', largest_contentful_paint: 'LCP', first_input_delay: 'FID', cumulative_layout_shift: 'CLS', }; return Object.entries(metrics).map(([metricName, metricData]) => { const standardBinLabels = ['good', 'needs improvement', 'poor']; const metricBins = metricData.histogram; // We assume there are 3 histogram bins and they're in order of: good => poor const labeledBins = metricBins.map((bin, i) => { // Assign a good/poor label, calculate a percentage, and add retain all existing bin properties return { label: standardBinLabels[i], percentage: bin.density * 100, ...bin, }; }); return { acronym: nameToAcronymMap[metricName], name: metricName, labeledBins, }; }); } // Create the three bars w/ a 3-column grid // This consumes the output from labelMetricData, not a raw API response. function createDescriptionAndBars(labeledBins) { const descEl = document.createElement('p'); // Example: 'good: 43.63%, needs improvement: 42.10%, poor: 14.27%' descEl.textContent = labeledBins .map(bin => `${bin.label}: ${bin.percentage.toFixed(2)}%`) .join(', '); let barsEl = document.createElement('div'); for (const bin of labeledBins) { const barEl = document.createElement('div'); // Reuse the label for the styling class, changing any spaces: `needs improvement` => `needs-improvement` barEl.classList.add(`box-${bin.label.replace(' ', '-')}`); // Add tooltip to share the size of each bin barEl.title = `bin start: ${bin.start}, bin end: ${bin.end}`; barsEl.append(barEl); } // Set the width of the bar columns based on metric bins // Ex: `grid-template-columns: 43.51% 42.26% 14.23%`; barsEl.style.gridTemplateColumns = labeledBins.map(bin => `${bin.percentage}%`).join(' '); barsEl.classList.add(`grid-container`); return [descEl, barsEl]; }
HTML
<div id="wrapper"> <h1>Chrome User Experience Report API demo</h1> <p>The field data collected over the last 28 days.</p> </div>
CSS
#wrapper { margin: auto; width: 70%; font-family: sans-serif; } .grid-container { display: grid; grid-template-rows: 50px; grid-template-areas: '. . .'; padding-bottom: 10px; } .box-good { background-color: hsl(118, 41%, 49%); } .box-needs-improvement { background-color: hsl(31, 78%, 53%); } .box-poor { background-color: hsl(359, 80%, 50%); }
Upon successful run, your page will look like Figure 1.
Figure 1. The JavaScript demo