or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

aws-lambda.mdbrowser-monitoring.mdcustom-attributes.mdcustom-instrumentation.mddistributed-tracing.mderror-handling.mdindex.mdllm-monitoring.mdmetrics-events.mdsegments-timing.mdtransaction-management.mdurl-naming-rules.mdutilities.md

browser-monitoring.mddocs/

0

# Browser Monitoring

1

2

Generate Real User Monitoring (RUM) scripts for correlating server-side performance with client-side metrics.

3

4

## Capabilities

5

6

### Get Browser Timing Header

7

8

Generate the browser monitoring script tag for injection into HTML pages.

9

10

```javascript { .api }

11

/**

12

* Generate browser monitoring script for Real User Monitoring injection.

13

* Must be called for each page request - do not reuse between users or requests.

14

* @param {object} [options] - Configuration options

15

* @param {string} [options.nonce] - CSP nonce for script tag

16

* @param {boolean} [options.hasToRemoveScriptWrapper] - Return script content without <script> tags

17

* @param {boolean} [options.allowTransactionlessInjection] - Allow injection without active transaction

18

* @returns {string} HTML script tag or script content, empty string or HTML comment on error

19

*/

20

function getBrowserTimingHeader(options);

21

```

22

23

**Usage Examples:**

24

25

```javascript

26

const newrelic = require('newrelic');

27

28

// Basic usage in Express templates

29

app.get('/', (req, res) => {

30

const browserScript = newrelic.getBrowserTimingHeader();

31

res.render('index', { browserScript });

32

});

33

34

// Template usage (EJS example)

35

// In your HTML head section:

36

// <%- browserScript %>

37

38

// With CSP nonce

39

app.get('/secure-page', (req, res) => {

40

const nonce = generateNonce();

41

const browserScript = newrelic.getBrowserTimingHeader({ nonce });

42

43

res.set('Content-Security-Policy', `script-src 'nonce-${nonce}' 'self'`);

44

res.render('secure-page', { browserScript });

45

});

46

47

// For React/SPA applications (script content only)

48

app.get('/api/browser-script', (req, res) => {

49

const scriptContent = newrelic.getBrowserTimingHeader({

50

hasToRemoveScriptWrapper: true

51

});

52

53

res.json({ scriptContent });

54

});

55

56

// Allow injection without active transaction

57

app.get('/static-page', (req, res) => {

58

const browserScript = newrelic.getBrowserTimingHeader({

59

allowTransactionlessInjection: true

60

});

61

res.render('static-page', { browserScript });

62

});

63

```

64

65

## Browser Timing Options

66

67

```javascript { .api }

68

interface BrowserTimingOptions {

69

/** CSP nonce to inject into the script tag for security */

70

nonce?: string;

71

/** Return script content without <script> wrapper tags */

72

hasToRemoveScriptWrapper?: boolean;

73

/** Allow browser agent injection when no active transaction exists */

74

allowTransactionlessInjection?: boolean;

75

}

76

```

77

78

## Script Output Formats

79

80

### Default Output (with script tags)

81

```html

82

<script type='text/javascript'>

83

window.NREUM||(NREUM={});NREUM.info = {"beacon":"bam.nr-data.net","errorBeacon":"bam.nr-data.net","licenseKey":"abc123","applicationID":"12345","transactionName":"xyz","queueTime":0,"applicationTime":123,"ttGuid":"def456","agent":"js-agent.newrelic.com/nr-spa-1234.min.js"};

84

// ... agent loader script

85

</script>

86

```

87

88

### With CSP Nonce

89

```html

90

<script type='text/javascript' nonce="abc123xyz">

91

// ... same content as above

92

</script>

93

```

94

95

### Without Script Wrapper

96

```javascript

97

window.NREUM||(NREUM={});NREUM.info = {"beacon":"bam.nr-data.net",...};

98

// ... agent loader script (content only)

99

```

100

101

## Error Conditions

102

103

The function returns HTML comments with error codes when browser monitoring cannot be generated:

104

105

- `<!-- NREUM: (0) -->` - Browser monitoring disabled in configuration

106

- `<!-- NREUM: (1) -->` - No active transaction or transaction ignored

107

- `<!-- NREUM: (2) -->` - Browser monitoring configuration missing

108

- `<!-- NREUM: (3) -->` - Transaction name missing

109

- `<!-- NREUM: (4) -->` - Application ID missing (agent not connected)

110

- `<!-- NREUM: (5) -->` - Browser key missing (server disabled monitoring)

111

- `<!-- NREUM: (6) -->` - Agent loader script missing

112

- `<!-- NREUM: (7) -->` - Browser monitoring disabled by server

113

114

## Configuration Requirements

115

116

Browser monitoring requires:

117

118

1. **Agent Connection**: Agent must have successfully connected to New Relic servers

119

2. **Browser Monitoring Enabled**: `browser_monitoring.enable: true` in configuration

120

3. **Server Configuration**: New Relic servers must provide browser monitoring settings

121

4. **Active Transaction**: Usually requires an active transaction (unless `allowTransactionlessInjection: true`)

122

123

## Common Integration Patterns

124

125

### Express with Template Engines

126

127

```javascript

128

// EJS template

129

app.get('/', (req, res) => {

130

res.render('index', {

131

title: 'My App',

132

browserScript: newrelic.getBrowserTimingHeader()

133

});

134

});

135

136

// In views/index.ejs:

137

// <!DOCTYPE html>

138

// <html>

139

// <head>

140

// <title><%= title %></title>

141

// <%- browserScript %>

142

// </head>

143

// <body>...</body>

144

// </html>

145

```

146

147

### React/Next.js Applications

148

149

```javascript

150

// API route to get browser script

151

app.get('/api/newrelic-browser', (req, res) => {

152

const scriptContent = newrelic.getBrowserTimingHeader({

153

hasToRemoveScriptWrapper: true

154

});

155

156

res.json({

157

success: scriptContent.length > 0,

158

script: scriptContent

159

});

160

});

161

162

// In React component:

163

useEffect(() => {

164

fetch('/api/newrelic-browser')

165

.then(res => res.json())

166

.then(data => {

167

if (data.success && data.script) {

168

const script = document.createElement('script');

169

script.innerHTML = data.script;

170

document.head.appendChild(script);

171

}

172

});

173

}, []);

174

```

175

176

### Middleware for Automatic Injection

177

178

```javascript

179

// Middleware to automatically add browser script to all HTML responses

180

app.use((req, res, next) => {

181

const originalRender = res.render;

182

183

res.render = function(view, options = {}) {

184

// Add browser script to all template renders

185

options.browserScript = newrelic.getBrowserTimingHeader();

186

return originalRender.call(this, view, options);

187

};

188

189

next();

190

});

191

```

192

193

### CSP-Compliant Implementation

194

195

```javascript

196

// Generate nonce for each request

197

function generateNonce() {

198

return require('crypto').randomBytes(16).toString('base64');

199

}

200

201

app.use((req, res, next) => {

202

// Generate nonce for this request

203

const nonce = generateNonce();

204

res.locals.nonce = nonce;

205

206

// Set CSP header

207

res.set('Content-Security-Policy',

208

`script-src 'nonce-${nonce}' 'self' js-agent.newrelic.com bam.nr-data.net`

209

);

210

211

next();

212

});

213

214

app.get('/', (req, res) => {

215

const browserScript = newrelic.getBrowserTimingHeader({

216

nonce: res.locals.nonce

217

});

218

219

res.render('index', { browserScript });

220

});

221

```

222

223

### Error Handling and Fallbacks

224

225

```javascript

226

function getSafeBrowserScript(options = {}) {

227

try {

228

const script = newrelic.getBrowserTimingHeader(options);

229

230

// Check if script generation failed (returns HTML comment)

231

if (script.startsWith('<!-- NREUM:')) {

232

console.warn('Browser monitoring script generation failed:', script);

233

return ''; // Return empty string for failed generation

234

}

235

236

return script;

237

} catch (error) {

238

console.error('Error generating browser monitoring script:', error);

239

return ''; // Fail gracefully

240

}

241

}

242

243

// Usage with fallback

244

app.get('/', (req, res) => {

245

const browserScript = getSafeBrowserScript();

246

res.render('index', { browserScript });

247

});

248

```

249

250

### Single Page Application (SPA) Support

251

252

```javascript

253

// For SPAs, you might want to inject the script only on initial page load

254

app.get('/', (req, res) => {

255

const browserScript = newrelic.getBrowserTimingHeader();

256

res.render('spa-shell', { browserScript });

257

});

258

259

// API routes don't need browser monitoring

260

app.get('/api/*', (req, res, next) => {

261

// Skip browser monitoring for API calls

262

next();

263

});

264

```

265

266

### Development vs. Production

267

268

```javascript

269

// Only inject in production environment

270

function getBrowserScriptForEnvironment(options = {}) {

271

if (process.env.NODE_ENV !== 'production') {

272

return ''; // No browser monitoring in development

273

}

274

275

return newrelic.getBrowserTimingHeader(options);

276

}

277

278

app.get('/', (req, res) => {

279

const browserScript = getBrowserScriptForEnvironment();

280

res.render('index', { browserScript });

281

});

282

```

283

284

## Best Practices

285

286

1. **Placement**: Inject the script as high as possible in the `<head>` section, after any X-UA-Compatible meta tags

287

2. **Per-Request Generation**: Always generate fresh scripts for each request - never cache or reuse

288

3. **Error Handling**: Check for HTML comments indicating failed generation

289

4. **CSP Compliance**: Use nonce parameter when Content Security Policy is enabled

290

5. **Environment Control**: Consider disabling in development environments

291

6. **Performance**: The script is small but generated per-request, consider caching requirements if performance is critical

292

7. **HTTPS**: Browser monitoring works best with HTTPS applications

293

8. **Correlation**: Browser monitoring data correlates with server-side transaction data automatically when properly implemented