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

additional-web-vitals.mddocs/

0

# Additional Web Vitals

1

2

Measurement functions for additional Web Vitals metrics that are useful for performance monitoring and debugging: First Contentful Paint (FCP) and Time to First Byte (TTFB).

3

4

## Capabilities

5

6

### First Contentful Paint (FCP)

7

8

Measures the [FCP](https://web.dev/articles/fcp) value for the current page and calls the callback function once the value is ready. FCP measures loading performance by identifying when the first text or image content becomes visible to users.

9

10

```typescript { .api }

11

/**

12

* Calculates the FCP value and calls callback with paint timing data

13

* @param callback - Function to receive FCP metric data

14

* @param opts - Optional configuration for reporting behavior

15

*/

16

function onFCP(callback: (metric: FCPMetric) => void, opts?: ReportOpts): void;

17

18

interface FCPMetric extends Metric {

19

name: 'FCP';

20

entries: PerformancePaintTiming[];

21

}

22

```

23

24

**Usage Examples:**

25

26

```typescript

27

import { onFCP } from "web-vitals";

28

29

// Track FCP timing

30

onFCP((metric) => {

31

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

32

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

33

34

const paintEntry = metric.entries[0];

35

console.log('Paint entry name:', paintEntry.name); // 'first-contentful-paint'

36

console.log('Start time:', paintEntry.startTime);

37

});

38

39

// Send FCP data to analytics

40

onFCP((metric) => {

41

gtag('event', 'web_vitals', {

42

event_category: 'Performance',

43

event_label: 'FCP',

44

value: Math.round(metric.value),

45

custom_map: { metric_rating: metric.rating }

46

});

47

});

48

```

49

50

**Important Notes:**

51

- Reports once when first contentful paint occurs

52

- Uses Paint Timing API with `first-contentful-paint` entry

53

- Represents when users see first meaningful content

54

- Threshold: ≤1.8s (good), 1.8-3s (needs improvement), >3s (poor)

55

56

### Time to First Byte (TTFB)

57

58

Measures the [TTFB](https://web.dev/articles/ttfb) value for the current page and calls the callback function once the page has loaded. TTFB measures the time from navigation start to when the first byte of the response is received.

59

60

```typescript { .api }

61

/**

62

* Calculates the TTFB value and calls callback with navigation timing data

63

* @param callback - Function to receive TTFB metric data

64

* @param opts - Optional configuration for reporting behavior

65

*/

66

function onTTFB(callback: (metric: TTFBMetric) => void, opts?: ReportOpts): void;

67

68

interface TTFBMetric extends Metric {

69

name: 'TTFB';

70

entries: PerformanceNavigationTiming[];

71

}

72

```

73

74

**Usage Examples:**

75

76

```typescript

77

import { onTTFB } from "web-vitals";

78

79

// Track TTFB timing

80

onTTFB((metric) => {

81

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

82

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

83

84

const navEntry = metric.entries[0];

85

console.log('DNS lookup time:', navEntry.domainLookupEnd - navEntry.domainLookupStart);

86

console.log('Connection time:', navEntry.connectEnd - navEntry.connectStart);

87

console.log('Request time:', metric.value - navEntry.requestStart);

88

});

89

90

// Break down server response time components

91

onTTFB((metric) => {

92

const navEntry = metric.entries[0];

93

94

// Calculate sub-timings

95

const dnsTime = navEntry.domainLookupEnd - navEntry.domainLookupStart;

96

const connectionTime = navEntry.connectEnd - navEntry.connectStart;

97

const requestTime = metric.value - navEntry.requestStart;

98

99

console.log('Network breakdown:', {

100

dns: dnsTime,

101

connection: connectionTime,

102

serverResponse: requestTime,

103

total: metric.value

104

});

105

});

106

```

107

108

**Important Notes:**

109

- Waits until page load to ensure all navigation timing properties are available

110

- Includes time from navigation start to first response byte

111

- Encompasses DNS lookup, connection, and server processing time

112

- Fallback to `performance.timing` for older browsers

113

- Threshold: ≤800ms (good), 800-1800ms (needs improvement), >1800ms (poor)

114

115

## Performance Entry Types

116

117

The Additional Web Vitals metrics use specific performance entry types:

118

119

```typescript { .api }

120

/** Paint timing entries for FCP measurement */

121

interface PerformancePaintTiming extends PerformanceEntry {

122

/** For FCP, this will be 'first-contentful-paint' */

123

name: string;

124

/** Timestamp when the paint occurred */

125

startTime: DOMHighResTimeStamp;

126

}

127

128

/** Navigation timing entries for TTFB measurement */

129

interface PerformanceNavigationTiming extends PerformanceEntry {

130

/** Start of DNS lookup */

131

domainLookupStart: DOMHighResTimeStamp;

132

/** End of DNS lookup */

133

domainLookupEnd: DOMHighResTimeStamp;

134

/** Start of TCP connection */

135

connectStart: DOMHighResTimeStamp;

136

/** End of TCP connection */

137

connectEnd: DOMHighResTimeStamp;

138

/** Start of request */

139

requestStart: DOMHighResTimeStamp;

140

/** Start of response (TTFB) */

141

responseStart: DOMHighResTimeStamp;

142

/** End of response */

143

responseEnd: DOMHighResTimeStamp;

144

/** Activation start for prerendered pages */

145

activationStart?: DOMHighResTimeStamp;

146

}

147

```

148

149

## Usage Patterns

150

151

### Combining with Core Web Vitals

152

153

```typescript

154

import { onFCP, onLCP, onCLS, onINP, onTTFB } from "web-vitals";

155

156

// Comprehensive performance monitoring

157

const performanceData = {

158

fcp: null,

159

lcp: null,

160

cls: null,

161

inp: null,

162

ttfb: null

163

};

164

165

onFCP((metric) => performanceData.fcp = metric);

166

onLCP((metric) => performanceData.lcp = metric);

167

onCLS((metric) => performanceData.cls = metric);

168

onINP((metric) => performanceData.inp = metric);

169

onTTFB((metric) => performanceData.ttfb = metric);

170

171

// Send comprehensive report when page becomes hidden

172

document.addEventListener('visibilitychange', () => {

173

if (document.visibilityState === 'hidden') {

174

sendAnalytics(performanceData);

175

}

176

});

177

```

178

179

### Loading Performance Analysis

180

181

```typescript

182

import { onFCP, onLCP, onTTFB } from "web-vitals";

183

184

// Analyze loading performance stages

185

onTTFB((metric) => {

186

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

187

});

188

189

onFCP((metric) => {

190

console.log('First content visible:', metric.value + 'ms');

191

});

192

193

onLCP((metric) => {

194

console.log('Main content loaded:', metric.value + 'ms');

195

});

196

```