GithubHelp home page GithubHelp logo

googlechrome / web-vitals Goto Github PK

View Code? Open in Web Editor NEW
7.3K 117.0 399.0 2.75 MB

Essential metrics for a healthy site.

Home Page: https://web.dev/vitals

License: Apache License 2.0

JavaScript 50.93% TypeScript 41.71% Nunjucks 7.25% CSS 0.01% Shell 0.09%

web-vitals's People

Contributors

andersdjohnson avatar ben-larson avatar brendankenny avatar dependabot[bot] avatar devjiwonchoi avatar jayhori avatar jodydonetti avatar jschulte avatar justin-john avatar malchata avatar manantank avatar mmocny avatar monis0395 avatar nicholasray avatar omrilotan avatar philipwalton avatar robatron avatar roderickhsiao avatar rviscomi avatar simenhansen avatar skychx avatar stephenyu avatar theneekz avatar tomayac avatar tunetheweb avatar vanderhoop avatar yuangwei avatar zizzamia avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

web-vitals's Issues

CLS & Lazy Loading Images with CSS Animations

Thanks for this Chrome extension.

I noticed that CLS correlates when lazy loading images with CSS fade-in animation.

Will this going to have negative effect? Should we not use this kind of animations for lazy loading images?

Here is the code that I use for WP Rocket Lazy Load:

`/* WP-ROCKET Lazy Load */
img[data-lazy-src] {
opacity: 0;
}

/* WP-ROCKET - Upon Lazy Load */
img.lazyloaded {
-webkit-transition: opacity .25s ease-out 0.2s;
-moz-transition: opacity .25s ease-out 0.2s;
transition: opacity .25s ease-out 0.2s;
opacity: 1;
}`

LCP on user interaction?

Why is LCP reported on user interaction?

I can load my page and sit on it for minutes before clicking, then LCP is reported for those minutes instead of when the actual content is shown.

Option to batch reporting callbacks

I'm looking at setting up a simple standalone backend for collecting and visualizing web-vitals metrics. Being able to report all vitals in one go would in theory simplify that quite a lot. Unfortunately the custom analytics endpoint example in the readme will send a request for each tracked metric, which obviously results in a lot of requests if you track all the available metrics.

After reading though the source, it seems to me that the reporting callbacks will only trigger when there is data and otherwise do nothing. In theory this prevents a naive attempt at batching using Promise.all from working reliably.

Is there a better way of getting the all the tracked vitals in one go? Or is batching them somehow a bad idea?

Next.js: SyntaxError: Unexpected token 'export'

Following the installation in readme with Next.js v9.3.6 (latest) has led to the following issue. SyntaxError: Unexpected token 'export' Looks like a cjs module not working in React. ๐Ÿค”

ERROR (CLICK TO EXPAND!)

SyntaxError: Unexpected token 'export'
(anonymous function)
/Users/ahmadawais/โ€ฆ/node_modules/web-vitals/dist/web-vitals.min.js:1
Module._compile
internal/modules/cjs/loader.js:892:18
Module._extensions..js
internal/modules/cjs/loader.js:973:10
Module.load
internal/modules/cjs/loader.js:812:32
Function.Module._load
internal/modules/cjs/loader.js:724:14
Module.require
internal/modules/cjs/loader.js:849:19
require
internal/modules/cjs/helpers.js:74:18
web-vitals
webpack:/external "web-vitals":1

1 | module.exports = require("web-vitals");
View compiled
webpack_require
./webpack/bootstrap:21
18 | // Execute the module function
19 | var threw = true;
20 | try {
21 | modules[moduleId].call(module.exports, module, module.exports, webpack_require);
| ^ 22 | threw = false;
23 | } finally {
24 | if(threw) delete installedModules[moduleId];
View compiled
Module../pages/index.js
/_next/development/server/static/development/pages/index.js:4450:69
webpack_require
./webpack/bootstrap:21
18 | // Execute the module function
19 | var threw = true;
20 | try {
21 | modules[moduleId].call(module.exports, module, module.exports, webpack_require);
| ^ 22 | threw = false;
23 | } finally {
24 | if(threw) delete installedModules[moduleId];
View compiled
3
/_next/development/server/static/development/pages/index.js:4996:18
webpack_require
./webpack/bootstrap:21
18 | // Execute the module function
19 | var threw = true;
20 | try {
21 | modules[moduleId].call(module.exports, module, module.exports, webpack_require);
| ^ 22 | threw = false;
23 | } finally {
24 | if(threw) delete installedModules[moduleId];
View compiled
โ–ถ 10 stack frames were collapsed.
This screen is visible only in development. It will not appear if the app crashes in production.
Open your browserโ€™s developer console to further inspect this error.

Data Visualization - Can you provide examples/instructions?

Hello,

I started collecting Web Vitals in my Google Analytics account (using this library).
But, I have no idea how to visualize the data in order to achive a similar report as in 'Google Search Console', 'Chrome UX Dashboard' or anything basic.

It would be great if you could provide some examples/instructions.

It would be really great if you could create a DataStudio template to visualize the web vitals events in Google Analytics.
I guess this is the most common use-case and will make the many users' life easier.

Thanks!

CLS - strange behavior?

Hello,

We noticed that getCLS(onReport) is only firing when the user changes to another tab.

We tried to use getCLS(onReport, true) and this also led us to find some strange behavior -

An animation triggered by a hover event is reporting as hadRecentInput: false, these seem to be related to different children elements having "transform: " properties.

We also noticed that a child element of hover animated element has backface-visilbity: unset, our hero carousel image (a sibling element of a higher parent container element) then triggers CLS entries (with reportAllChanges = true), however with backface-visiblity: hidden the hero carousel no longer triggers CLS, but hovering in and out from the animated element does trigger CLS again.

I have recorded a video of the steps above, please let me know if you would like to see it.

Cannot find CLS in Performance Tab

When I load the devtools on Chrome 86 when navigating to CLS demo on JSBin I can see the Layout Shift events under the Experience section but when I navigate to my site to find out what is causing it for me, I have no "Experience" section but the CLS icon constantly changes/flickers between red and green (Addy Osmani's web vitals extension).

Sorry if this is the wrong place for the issue.

Visually Complete

Many developers and SREs use custom versions of "visually complete", but every implementation has problems. For example, client side javascript is limited and often inaccurate, extension-based screenshots are inefficient, etc.

It is a challenging problem to solve since sites vary with dynamic content such as carousels, moving ads, and user interaction, but it would help a lot to have some measurement indicating most above the fold rendering has finished. Any dynamic content after that could be ignored and any user interaction could null the measurement.

Please consider adding this as a standard measurement to web vitals. Ideally a version of this can become a standard available in the performance api.

Functions as promises

Would it be possible to also support the async/await syntax if no callback is provided?

const data = await getCLS();

Measure relative to fetchStart?

My application is behind authentication which is handled via redirects to another domain outside my control. I've implemented logging of navigation and paint timing metrics recently and noticed the redirect time introduces significant variance in the data (depending on if a redirect for auth was needed or not).

Looking at the Navigation timing model, it also seems inappropriate to include unload time from the previous site because that is out of my app's control.

Based on this I adjusted our perf measurements to be relative to the fetchStart instead of startTime.

I wanted to get your team's input - does this seem like a reasonable thing to do for performance metrics? or am I missing some value here?

Maybe this could be added as an option to this lib.

Google Ads report into Analytics impacted by Web Vitals

Hi all, we added web-vitals project in our web side to keep track of new measures. We are used to use Google Analytics as well to follow lot of metrics and during our checks we discovered a strange and huge increments on Users (and a lot less on Sessions) in Google Ads reports on GA. We found that the increment is due to a series of hits without a campaignId. The increments are started when we published web vitals tag through Tag Manager.
Some considerations we did (hope to be correct on that):

  • GA Google Ads report is based on Source (google) and medium (cpc)
  • the (huge) difference between users and sessions in report is due to the fact web vitals are NON interactive events, instead the session exposed in the report are the interactive one.
  • source and medium are correct, they are set in the session, simply, it seems to me that every web vitals hits impact the Google Ads report as well.

Any idea on how to prevent this behaviour?

Event not being fired or fired with no value

Hey all! I know you have this note:

Note: some of these metrics will not report until the user has interacted with the page, switched tabs, or the page starts to unload. If you don't see the values logged to the console immediately, try switching tabs and then switching back.

But I realized that a few times the events are not being fired at all or with no value attached. This is the implementation based on the console.log example that you have it.

import { getCLS, getFID, getLCP } from "web-vitals";

const sendToNR = (event, value) => {
  if (window.newrelic) {
    window.newrelic.setCustomAttribute(event, value);
  }
};

const startSiteSpeed = () => {
  getCLS(metric => sendToNR("CLS", metric.value));
  getFID(metric => sendToNR("FID", metric.value));
  getLCP(metric => sendToNR("LCP", metric.value));
};

Is there anything wrong here? Also, is there an accurate way to test these metrics? The Google Chrome extension shows really different numbers for the same page.

Add isSupported metric property

I'm currently trying to wrap the web vitals lib into a custom <web-vitals /> element.

It would be great if there would be a way to get information about the support of a particular metric. E.g. in Firefox the reporters are just not called. I could imagine to include an isSupported property or similar in the metric object that is passed to the particular reporter. Could this be a valuable addition?

Thanks a bunch for this project, it's great!

Type declaration not found

Importing this package in a typescript project results in the error:

Could not find a declaration file for module 'web-vitals'. '/node_modules/web-vitals/dist/web-vitals.min.js' implicitly has an 'any' type.
Try npm install @types/web-vitals if it exists or add a new declaration (.d.ts) file containing declare module 'web-vitals';ts(7016)

I see the lib is written in typescript so I'm assuming this is a misconfiguration of the build, not that types are hosted in an types package

The isFinal flag is confusing

The initial intent of the isFinal flag was allow consumers of this library to know when LCP was finalized (since the Largest Contentful Paint API does not currently expose this information). However, given #75, the heuristics will become significantly less accurate if we're not tracking scrolls.

The isFinal flag was also a bit weird because it only really applied to LCP. CLS is not final until the page has unloaded, and FCP, FID, and TTFB are always final after the first entry is dispatched.

I've also seen examples in the wild where developers were misunderstanding isFinal and waiting until it was true before sending the data to their analytics provider. That is definitely not what isFinal is for, and something needs to be done to avoid that confusion.

CLS is not reporting often

First: I'd like to thank you all for the time you put into this library!

I have a small issue with how often CLS is reporting:

On a highly trafficked site that I'm working on, we found that CLS is captured very infrequently in our analytics. In fact, only ~31% of pageviews on Chrome report a CLS metric; whereas FID is captured on ~43% (not great either) and LCP is captured on ~80% of page views.

It sounds like the implementation waits for visibility to be hidden before reporting. Is it possible that a lot of page loads are not triggering the hidden event before navigation to a new page? Any other ideas?

Feature Request: Add `removeEventListener`/`unobserve` equivalent

Currently every invocation creates a new PerformanceObserver that never unobserves so there's no way to remove a handler. It'd be nice to be able to remove old listeners.

EDIT: This affects the web vitals extension which leaks listeners on every activation of tab. I'm fixing over there, but this seems generally useful too ๐Ÿ˜ƒ

Is TTFB being properly calculated?

Hello I'm probably wrong but according to this article from web dev TTFB can be calculated doing the next:

// Time to First Byte (TTFB)
var pageNav = performance.getEntriesByType("navigation")[0];
var ttfb = pageNav.responseStart - pageNav.requestStart;

But on the web-vitals implementation of TTFB we are doing the next:

      const navigationEntry = performance.getEntriesByType('navigation')[0] ||
          getNavigationEntryFromPerformanceTiming();

      metric.value = metric.delta =
          (navigationEntry as PerformanceNavigationTiming).responseStart;

I'm a bit confused of which should be the metric calculated.

Link to the file:

metric.value = metric.delta =

Thank you in advance

CLS is not reported on first hidden if the value is still zero

Pages with a CLS value of 0 still need to report that value when the page is first hidden. However, the current callback logic won't fire a callback if the delta is 0 and the metric is not final.

This logic should be updated to also check if no previous value exists (to allow for first-time reporting of 0-delta metrics).

Usage on Angular routed applications?

Hello,
First of all, great work!

I am wondering: Is it possible to use this tool on Angular routed applications?

I can definitely see the usage on the very first page of my application, since it's like any other web application. My question is more related to subsequent pages in my application flow.

Can this be able to understand that there is a route change and, therefore, restart the metric?
I haven't checked the code, but if there is nothing browser API related, but couldn't the application itself tells the tool that there is a route change? In case, of course, you can't directly detect it.

Cheers!

GA spike of users with not set landing page after install the script

Hi !
thanks for sharing this useful piece of code :)

I've tried to install the web vitals monitoring code using GTM. Data seems to be collected correctly, but then I noted a spike of user with location (not set) in GA data (see the screenshot below). After stopping the web vitals tag the data came back to normal. It's seems like a bot it's activated via this code, as you can see in the second screenshot the bad traffic is coming from USA with Linux OS and null session duration. Can you help me with this issue please? Do you know another cdn for getting the code?

spike data
2020-07-24_16h32_59

details
2020-07-24_16h33_46

Many thanks,
Daniela

FCP is larger than LCP

Thanks for this awesome library.

I am using GA for collecting the web vitals data. From GA dashboard, I can see FCP value is larger than LCP at some date, which is beyond our expectation(FCP should be less than LCP). Seems there is something wrong.

image

I am using web-vitals v0.2.2.

The following is my data reporting code (pls let me know if I am using it incorrectly):

import {getFCP, getLCP} from 'web-vitals';

function sendToGoogleAnalytics({name, delta, id}) {
  // Assumes the global `gtag()` function exists, see:
  // https://developers.google.com/analytics/devguides/collection/gtagjs
  gtag('event', name, {
    event_category: 'Web Vitals',
    // Google Analytics metrics must be integers, so the value is rounded.
    // For CLS the value is first multiplied by 1000 for greater precision
    // (note: increase the multiplier for greater precision if needed).
    value: Math.round(name === 'CLS' ? delta * 1000 : delta),
    // The `id` value will be unique to the current page load. When sending
    // multiple values from the same page (e.g. for CLS), Google Analytics can
    // compute a total by grouping on this ID (note: requires `eventLabel` to
    // be a dimension in your report).
    event_label: id,
    // Use a non-interaction event to avoid affecting bounce rate.
    non_interaction: true,
  });
}

getFCP(sendToGoogleAnalytics);
getLCP(sendToGoogleAnalytics);

Why use Google Analytics Event tracking for reporting web vitals?

https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics

IMHO User Timing Tracking should be used. Google Analytics has been using User Time Tracking for TTFB, DIT (DOM Interactive), DNS (DNS Resolve Time) time. It supports non-integer value as well.

Example code:

import {getCLS, getFID, getLCP} from 'web-vitals';

function sendToGoogleAnalytics({name, delta, id}) {
  // https://developers.google.com/analytics/devguides/collection/analyticsjs
  ga('send', 'event', {
  hitType: 'timing',
  timingCategory: 'Web Vitals',
  timingVar: name,
  timingValue: Math.round(name === 'CLS' ? delta * 1000 : delta)
});

getCLS(sendToGoogleAnalytics);
getFID(sendToGoogleAnalytics);
getLCP(sendToGoogleAnalytics);

Questions about manually takeRecords

Hello, maintainers. I have a question about this line.

when I start test server and navigate to http://localhost:9090/test/lcp, and then add some log to print records return by po.takeRecords(), I find it's length always be 0.

So, I don't know in which condition, we need to manually get records and its length will not be 0.

Please help me to understand this line, thanks.

Correct location to call webVitals in a React SPA

I have a React based SPA where I am wanting to use the web-vitals library. I have it working by calling the webVitals methods within a useEffect().

The reason for the useEffect is an easy way to ensure the vitals are only recored when on a a client side renderer (the App is isomorphic)

Is this the correct way to call these methods? The component this is in is called in the main layout container that is used to wrap each page.

e.g.

import { useEffect } from "react";
import { getCLS, getFID, getLCP, getTTFB } from "web-vitals";

const WebVitals = () => {
  useEffect(() => {
    getTTFB(console.log);
    getCLS(console.log);
    getFID(console.log);
    getLCP(console.log);
  }, []);

  return null;
};

export default WebVitals;

usage

import WebVitals from './webVitals'

<WebVitals />

Is CLS actually DCLS?

Judging by the implementation, it looks like the "CLS" that web-vitals reports is actually DCLS. Is that right?

Browser Support

My team is unsure about tracking the metrics provided by this library. Rationale being that if we use these metrics then we'll be optimizing for Chromium-only browsers.

What is your team's take on the value of tracking these metrics today given the level of browser support?

Is there support or commitment from other browser vendors to implement the APIs used to gather these metrics? Might be worth mentioning this in the docs.

Best way to detect browser support

๐Ÿ‘‹ I saw #36 and had my own guestion about browser support. How do you currently recommend checking if this library is supported by the user agent?

From my reading, the recommended way to approach browser support differences is to detect the existence of an API as opposed to a particular user agent, according to this article?

Here are two snippets we're debating using, each with their own trade-offs:

Approach 1: Detect Chromium browsers

Challenges: This is error prone and will need to be updated as support changes.

function trackWebVitals() {
  const isChromiumBrowser = !!navigator.userAgent.match(/Chrome|Chromium/)
  if (!isChromiumBrowser) return
  
  ...
}

Approach 2: Check if some API exists

Is there one particular API that we could check for? Internally we were considering looking at PerformanceObserver for that.

function trackWebVitals() {
  const hasPerformanceObserver = 'PerformanceObserver' in window
  if (!hasPerformanceObserver) return

  ...
}

But the question here is โ€“ย would that be enough? Browser support seems to be different for each function:

  • getCLS(): Chromium
  • getFCP(): Chromium
  • getFID(): Chromium, Firefox, Safari, Internet Explorer (with polyfill, see below)
  • getLCP(): Chromium
  • getTTFB(): Chromium, Firefox, Safari, Internet Explorer

Anyway wondering what your thoughts were. I think that ultimately it would be best if the library just abstracted away the browser support question ๐Ÿ˜„

function trackWebVitals() {
  const hasBrowserSupport = webVitals.hasFullBrowserSupport()
  if (!hasBrowserSupport) return
}

Thank you! We're excited about this ๐Ÿ˜„

Capture all metrics contributing to the Lighthouse performance score

Web vitals and especially this library is a great step towards consistent metrics across a variety of tools. Thank you for this!

I am wondering whether this library could be extended to capture all the metrics contributing to the Lighthouse performance score? This would help establish a consistent experience/measurements across the whole tooling landscape. Consistent experiences/measurements could improve adoption and this in turn could improve the experience on the web. WDYT?

I realize that these metrics may not fit under the web vitals umbrella, but they do fall into a similar category.

btw.: Thank you for building this library in such a way that it is closure compiler advanced mode compatible :)

SPA impact

I'm concerned that the CLS will not trigger by default until a user has navigated a few times in a SPA... wouldn't that throw off the value significantly?

The main reason for incorporating this into our application is to track user experience on first load. So in that sense I feel like I'd prefer CLS to have a way of returning the current shift value when called (after DOM load in our case) which obviously hopefully would be a value of 0

Utility for checking a metric passes the threshold?

When I first started using the library, I was a little surprised to see it didn't implement a canonical helper for determining if a metric passed the Core Web Vitals thresholds.

While our documentation on web.dev captures what the thresholds are, I can imagine there is value to a developer not needing to hardcode threshold values themselves (e.g imagine if they got this subtly wrong).

I currently implement custom scoring logic in the WIP web vitals extension, but thought I'd throw this idea over the fence to see what you thought.

I'll defer on the API shape if you think this would be helpful, but you could loosely imagine...

getCLS((result) => logCurrentValue('cls', result.value, result.passesThreshold, result.isFinal));

LCP is not friendly with 'carousel' hero image

This is a follow up to #60

On our website (https://www.pogo.com) we have an auto-scrolling hero image, also referred to as a 'carousel' spotlight image. The behavior of this seems to cause a new entry into LCP each time it is changed out before any user interaction. This can lead to a confusing or erroneous LCP response if the page is not interacted with by the user before the first swap occurs.
Screen Shot 2020-07-07 at 12 54 31 PM

Is there any guidance into using LCP with such behavior, or an alternative implementation?

Firefox old versions - throw an empty/unknown list of entryTypes

There is this old issue related to using PerformanceObserver with entryTypes 'paint' in Firefox v58: https://bugzilla.mozilla.org/show_bug.cgi?id=1403027 .

It is not a problem anymore, I think was fixed with v63. In case the library is looking to support older versions of Firefox, I found it could be convenient to wrap the PerformanceObserver in a try/catch for getFCP.

I can open a PR for it, but I thought to double-check first if you were interested in such a fix.

Unload event listeners should not be used

Given the new no-unload-listeners audit that's been added to Lighthouse, we should remove any use of the unload event. Even though the use in this library is to fix a bug and doesn't apply to the issues described in the audit, we still don't want sites to fail the audit because of this library.

CLS is reported in browsers that don't support it

Currently, the logic for when to report CLS happens outside of the check for a successfully created PerformanceObserver that can observe layout-shift entries. And since 0 values are acceptable to report for CLS, the result is other browsers will report CLS (always with the initial value of 0) even though they do not track layout shifts.

How should be implemented CLS ideal carousel ?

Hello,

I want to ask you how to implement ideal carousel and achieve good CLS score.

Example problem:
Carousel example using glide.js: http://jsfiddle.net/4tsf5gum/

As you can see initial HTML markup contain all visible slides. This is necessary to have a good LCP if carousel is first element on page with images. In initialization phase, library create clone slides before first and last slide and change translate3d property as explained in image.

carousel

Is it somehow possible to insert clone slides and at the same time change transform property and do not trigger layout shift ?

Thank you.

getFCP not firing

Hey

I am currently playing round with this and wrote the following code

<script
  defer
  src="https://unpkg.com/[email protected]/dist/web-vitals.es5.umd.min.js"
></script>
<script>
  const $log = document.querySelector('#log');
  const log = (newLog) => {
    $log.innerHTML += `<pre>${JSON.stringify(newLog, null, 4)}</pre>`;
  };

  addEventListener('DOMContentLoaded', function () {
    webVitals.getFCP(log);
    webVitals.getTTFB(log);
  });
</script>

However while I get a result for getTTFP I get nothing for getFCP

Is this because the page is to simple?

Following the instructions on how to send results to an analytics endpoint gives an error

In the README.md the example on how to send the results to an analytics endpoint gives TypeError: Converting circular structure to JSON. The problem is in the PerformanceEntries which cannot be converted to JSON, since they include DOM Elements. I found in the typescript definition that the PerformanceEntries have a toJSON() function (which actually has any type definition), but it doesn't help.

Please provide usable examples on how to correctly handle and send all the data to an analytics endpoint or remove the broken example and provide detailed information about what data should and could be sent to an analytics endpoint.

The problematic example I'm referring to in the README.md:

import {getCLS, getFID, getLCP} from 'web-vitals';

function sendToAnalytics(metric) {
  const body = JSON.stringify(metric);
  // Use `navigator.sendBeacon()` if available, falling back to `fetch()`.
  (navigator.sendBeacon && navigator.sendBeacon('/analytics', body)) ||
      fetch('/analytics', {body, method: 'POST', keepalive: true});
}

getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getLCP(sendToAnalytics);

Do I need to wait for DOMContentLoaded?

Hi there,

I'm unsure from your docs about whether or not it's necessary to wait for DOMContentLoaded, or some other pageload event?

In most of your examples you don't seem to wait:

import {getCLS, getFID, getLCP} from 'web-vitals';

function sendToAnalytics(metric) {
  const body = JSON.stringify(metric);
  // Use `navigator.sendBeacon()` if available, falling back to `fetch()`.
  (navigator.sendBeacon && navigator.sendBeacon('/analytics', body)) ||
      fetch('/analytics', {body, method: 'POST', keepalive: true});
}

getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getLCP(sendToAnalytics);

But then further down you do:

<!-- Load `web-vitals` using a classic script that sets the global `webVitals` object. -->
<script defer src="https://unpkg.com/[email protected]/dist/web-vitals.es5.umd.min.js"></script>
<script>
addEventListener('DOMContentLoaded', function() {
  webVitals.getCLS(console.log);
  webVitals.getFID(console.log);
  webVitals.getLCP(console.log);
});
</script>

I couldn't figure this out on my own, since I feel like there's a chance we wouldn't want to wait for the content load, because that would affect the timing?

Also, would be great to have the library do this automatically ๐Ÿ˜Š

webVitals.ready(function() {
  webVitals.getCLS(console.log);
  webVitals.getFID(console.log);
  webVitals.getLCP(console.log);
})

Document metric units

It would be great if the README could document what units (seconds, ms, shifts etc) each metric is being reported back with. When I began using the library, I assumed it was just passing raw values back (where possible) from the WebPerf APIs but it would help to make this explicit. Perhaps include some examples of the values you'll likely get reported back and units?

Allow installation as simple <script> tag

I want to install this by just doing something like <script src="web-vitals.js"></script> and then call the functions from the documentation to track the metrics, but it seems that's not a supported way of using this? I'm not really that familiar with JavaScript modules. It would be nice if there was a simple, "old school" way to install this.

Watching for 'scroll' event may end LCP before a valid browser entry is created

TLDR; I believe web-vitals marks isFinal on all types of scroll events when only some scroll events stop largest-contentful-paint browser entries.

Background

Thanks for open sourcing this!

When we started trying to use getLCP in our code at page start, the reporter would never fire. We noticed that our component library's positioning changes caused a scroll event before any meaningful render, that the web-vitals' input handler would catch. The page hadn't rendered anything, so there weren't any LCP entries for web-vitals to report to our callback. All well and fine, we were causing a scroll event, and the docs describe marking isFinal on scroll.

However, in our case, the Web Chrome Vitals Extension later displayed an LCP value. The extension would call getLCP on tab-complete, well after the scroll that stopped our web-vitals instance and read LCP entries just fine.

Let me know if you want a repro. The code is still internal, so it may take some time to get a fiddle up.

I get the impression this library watches for scroll because it reads entries created by the browser, and the browser stops recording on scroll. Through my use case, though, I think I've found that this library stops on any scroll event when the browser only stops creating the largest-contentful-paint entries on some scroll events.

LCP logic in Chromium

Searching for LCP and scroll logic in Chromium, I think I might have found the corresponding files.

Many types of scrolls I think all create `Event.type = 'scroll':
https://github.com/chromium/chromium/blob/a4f27fdc4913d800752bd1cb9533d31357163d65/third_party/blink/renderer/core/scroll/scroll_types.h#L58

But LCP only stops recording on two types of scroll events:
https://github.com/chromium/chromium/blob/55f44515cd0b9e7739b434d1c62f4b7e321cd530/third_party/blink/renderer/core/paint/paint_timing_detector.cc#L188

Remediation?

I admittedly don't understand what kCompositorScroll is, but the library could listen to key up, key down, and wheel device events instead of scroll as a proxy for 'kUserScroll'.

If this is a valid bug and has a straightforward fix, let me know, I'm happy to open contribute.

Implementation problems

Hello - We are implementing Web Vitals via GTM following the documentation here, but it does not seem to be working as expected. The tag fires on gtm.js and loads the library, but the actual metrics don't seem to be set on DOM ready. When we call them, some are defined, some are undefined. Does this in fact need to be hard-coded for the timing to work correctly? Are we missing something? Thanks in advance! ~Natty C.

Any plans to capture TTI?

@philipwalton I notice that slowly the meaningful web metrics to collect have moved away from TTI to LCP these days. Can you shed some light on why that is the case after promoting TTI for the last couple of years by the webdev community?

I also noticed a TTI measuring lib and have been using it for a few weeks now. Would you suggest me to stop using it and if not then any plans of integrating that into web-vitals?

~Nish

Question - differences between web-vitals library, web-vitals extension, and CrUX report

Hello again,

I'd like to explain that we are trying to use web-vitals library in a way so that we can get daily reports of metrics in our GA, in a similar way we see Monthly reports in our CrUX Dashboard v2.
Screen Shot 2020-07-14 at 12 27 24 PM

We're confused about how CrUX/Page Speed Insights and the web-vitals extension (https://github.com/GoogleChrome/web-vitals-extension) report metrics, because it doesn't seem to be the same way as the web-vitals library. Are there differences in how these tools report metrics vs the library?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.