Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add web-vitals measuring and event tracking #2619

Merged
merged 1 commit into from
Feb 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@
"styled-components": "^5.0.1",
"tar": "^6.0.1",
"topojson-client": "^3.1.0",
"uuid": "^8.3.0"
"uuid": "^8.3.0",
"web-vitals": "^1.1.0"
},
"scripts": {
"start": "cross-env TSC_COMPILE_ON_ERROR=false react-scripts -r @cypress/instrument-cra start",
Expand Down
2 changes: 2 additions & 0 deletions src/components/Analytics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
trackCopyLink,
trackShare,
trackVoteClick,
trackWebVitals,
} from './utils';

export default PageviewTracker;
Expand All @@ -19,4 +20,5 @@ export {
trackCopyLink,
trackShare,
trackVoteClick,
trackWebVitals,
};
47 changes: 46 additions & 1 deletion src/components/Analytics/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export enum EventCategory {
EXPOSURE_NOTIFICATIONS = 'exposure notifications',
SEARCH = 'search',
VACCINATION = 'vaccination',
WEB_VITALS = 'web vitals',
NONE = 'none', // use NONE for development
}

Expand All @@ -65,6 +66,11 @@ export enum EventAction {
REDIRECT = 'redirect',
FOCUS = 'focus',
NAVIGATE = 'navigate',
CLS = 'Cumulative Layout Shift (*1000)',
FCP = 'First Contentful Paint (ms)',
FID = 'First Input Delay (ms)',
LCP = 'Largest Contentful Paint (ms)',
TTFB = 'Time to First Byte',
}

/**
Expand All @@ -77,9 +83,17 @@ export function trackEvent(
label?: string,
value?: number,
nonInteraction?: boolean,
transport: 'beacon' | 'xhr' | 'image' = 'beacon',
) {
if (category !== EventCategory.NONE) {
ReactGA.event({ category, action, label, value, nonInteraction });
ReactGA.event({
category,
action,
label,
value,
nonInteraction,
transport,
});
}
}

Expand All @@ -106,3 +120,34 @@ export function trackShare(label: string) {
export function trackVoteClick(label: string) {
trackEvent(EventCategory.VOTE_2020, EventAction.CLICK_LINK, label);
}

/**
* Callback passed to web-vitals to report important performance events
*/
export function trackWebVitals({
name,
delta,
id,
}: {
name: 'CLS' | 'FID' | 'LCP' | 'FCP' | 'TTFB';
delta: number;
id: string;
}) {
trackEvent(
EventCategory.WEB_VITALS,
EventAction[name],
// 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).
id,
// 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).
Math.round(name === 'CLS' ? delta * 1000 : delta),
// Use a non-interaction event to avoid affecting bounce rate.
true,
// Use `sendBeacon()` if the browser supports it.
'beacon',
);
}
4 changes: 4 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import reportWebVitals from './reportWebVitals';
import { trackWebVitals } from './components/Analytics';
import * as Sentry from '@sentry/react';
import { initFullStory } from 'common/fullstory';

Expand Down Expand Up @@ -30,3 +32,5 @@ ReactDOM.render(<App />, document.getElementById('root'));
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

reportWebVitals(trackWebVitals);
19 changes: 19 additions & 0 deletions src/reportWebVitals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// implementation comes from a later version of create-react-app that this app was created from,
// but the implementation seems worth reusing.
// copied from https://github.com/facebook/create-react-app/blob/4e97dc75ad0c859fde7e2ffdaf9d5bd7d107b21a/packages/cra-template-typescript/template/src/reportWebVitals.ts

import { ReportHandler } from 'web-vitals';

const reportWebVitals = (onPerfEntry?: ReportHandler) => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};

export default reportWebVitals;
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -20417,6 +20417,11 @@ web-namespaces@^1.0.0:
resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.4.tgz#bc98a3de60dadd7faefc403d1076d529f5e030ec"
integrity sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==

web-vitals@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-1.1.0.tgz#7f410d9a1f7a1cd5d952806b45776204b47dc274"
integrity sha512-1cx54eRxY/+M0KNKdNpNnuXAXG+vJEvwScV4DiV9rOYDguHoeDIzm09ghBohOPtkqPO5OtPC14FWkNva3SDisg==

webidl-conversions@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
Expand Down