or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

additional-web-vitals.mdattribution.mdcore-web-vitals.mdindex.mdthresholds.md

core-web-vitals.mddocs/

0

# Core Web Vitals

1

2

Measurement functions for the three Core Web Vitals metrics that are part of Google's page experience signals: Cumulative Layout Shift (CLS), Interaction to Next Paint (INP), and Largest Contentful Paint (LCP).

3

4

## Capabilities

5

6

### Cumulative Layout Shift (CLS)

7

8

Measures the [CLS](https://web.dev/articles/cls) value for the current page and calls the callback function once the value is ready to be reported. CLS measures the visual stability of a page by quantifying how much visible content shifts unexpectedly.

9

10

```typescript { .api }

11

/**

12

* Calculates the CLS value and calls callback with layout shift data

13

* @param callback - Function to receive CLS metric data

14

* @param opts - Optional configuration for reporting behavior

15

*/

16

function onCLS(callback: (metric: CLSMetric) => void, opts?: ReportOpts): void;

17

18

interface CLSMetric extends Metric {

19

name: 'CLS';

20

entries: LayoutShift[];

21

}

22

```

23

24

**Usage Examples:**

25

26

```typescript

27

import { onCLS } from "web-vitals";

28

29

// Track CLS throughout page lifecycle

30

onCLS((metric) => {

31

console.log('CLS score:', metric.value);

32

console.log('Rating:', metric.rating); // 'good', 'needs-improvement', or 'poor'

33

console.log('Layout shifts:', metric.entries.length);

34

});

35

36

// Report all changes during page lifecycle

37

onCLS((metric) => {

38

if (metric.delta > 0) {

39

console.log('New layout shift detected:', metric.delta);

40

}

41

}, { reportAllChanges: true });

42

```

43

44

**Important Notes:**

45

- CLS should be continually monitored throughout the entire page lifespan

46

- The callback may be called multiple times as new layout shifts occur

47

- Always reports when page visibility changes to hidden

48

- Threshold: ≤0.1 (good), 0.1-0.25 (needs improvement), >0.25 (poor)

49

50

### Interaction to Next Paint (INP)

51

52

Measures the [INP](https://web.dev/articles/inp) value for the current page and calls the callback function with interaction timing data. INP measures responsiveness by tracking the worst interaction latency on the page.

53

54

```typescript { .api }

55

/**

56

* Calculates the INP value and calls callback with interaction data

57

* @param callback - Function to receive INP metric data

58

* @param opts - Optional configuration including duration threshold

59

*/

60

function onINP(callback: (metric: INPMetric) => void, opts?: INPReportOpts): void;

61

62

interface INPMetric extends Metric {

63

name: 'INP';

64

entries: PerformanceEventTiming[];

65

}

66

67

interface INPReportOpts extends ReportOpts {

68

/** Minimum duration threshold for interactions (default: 40ms) */

69

durationThreshold?: number;

70

}

71

```

72

73

**Usage Examples:**

74

75

```typescript

76

import { onINP } from "web-vitals";

77

78

// Track INP with default threshold

79

onINP((metric) => {

80

console.log('INP value:', metric.value + 'ms');

81

console.log('Rating:', metric.rating);

82

console.log('Interaction entries:', metric.entries.length);

83

});

84

85

// Custom duration threshold for filtering fast interactions

86

onINP((metric) => {

87

console.log('Slow interactions only:', metric.value + 'ms');

88

}, {

89

durationThreshold: 100, // Only track interactions >100ms

90

reportAllChanges: true

91

});

92

```

93

94

**Important Notes:**

95

- Requires PerformanceEventTiming API support

96

- Default threshold is 40ms (filters out very fast interactions)

97

- First input is always observed regardless of duration

98

- Callback may be called multiple times as worse interactions occur

99

- Threshold: ≤200ms (good), 200-500ms (needs improvement), >500ms (poor)

100

101

### Largest Contentful Paint (LCP)

102

103

Measures the [LCP](https://web.dev/articles/lcp) value for the current page and calls the callback function with the largest contentful paint timing data. LCP measures loading performance by identifying when the largest content element becomes visible.

104

105

```typescript { .api }

106

/**

107

* Calculates the LCP value and calls callback with LCP data

108

* @param callback - Function to receive LCP metric data

109

* @param opts - Optional configuration for reporting behavior

110

*/

111

function onLCP(callback: (metric: LCPMetric) => void, opts?: ReportOpts): void;

112

113

interface LCPMetric extends Metric {

114

name: 'LCP';

115

entries: LargestContentfulPaint[];

116

}

117

```

118

119

**Usage Examples:**

120

121

```typescript

122

import { onLCP } from "web-vitals";

123

124

// Track LCP timing

125

onLCP((metric) => {

126

console.log('LCP time:', metric.value + 'ms');

127

console.log('Rating:', metric.rating);

128

129

const lcpEntry = metric.entries[metric.entries.length - 1];

130

console.log('LCP element:', lcpEntry.element);

131

console.log('LCP size:', lcpEntry.size);

132

});

133

134

// Report on every LCP candidate change

135

onLCP((metric) => {

136

console.log('New LCP candidate:', metric.value + 'ms');

137

}, { reportAllChanges: true });

138

```

139

140

**Important Notes:**

141

- Stops observing once user interacts with the page or page becomes hidden

142

- Multiple candidates may be reported before final LCP is determined

143

- With `reportAllChanges: true`, reports every new LCP candidate

144

- Threshold: ≤2.5s (good), 2.5-4s (needs improvement), >4s (poor)

145

146

## Performance Entry Types

147

148

The Core Web Vitals metrics use specific performance entry types:

149

150

```typescript { .api }

151

/** Layout shift entries for CLS measurement */

152

interface LayoutShift extends PerformanceEntry {

153

value: number;

154

sources: LayoutShiftAttribution[];

155

hadRecentInput: boolean;

156

}

157

158

/** Event timing entries for INP measurement */

159

interface PerformanceEventTiming extends PerformanceEntry {

160

duration: DOMHighResTimeStamp;

161

interactionId: number;

162

}

163

164

/** Largest contentful paint entries for LCP measurement */

165

interface LargestContentfulPaint extends PerformanceEntry {

166

readonly renderTime: DOMHighResTimeStamp;

167

readonly loadTime: DOMHighResTimeStamp;

168

readonly size: number;

169

readonly id: string;

170

readonly url: string;

171

readonly element: Element | null;

172

}

173

```