Enrich And Control Browser RUM Data With beforeSend
Overview
The RUM Browser SDK captures RUM events and populates their main attributes. The beforeSend
callback function gives you access to every event collected by the RUM SDK before they are sent to Datadog.
Intercepting the RUM events allows you to:
- Enrich your RUM events with additional context attributes
- Modify your RUM events to modify their content, or redact sensitive sequences (see the list of editable properties)
- Discard selected RUM events
Event and context structure
The beforeSend
callback function gives you access to two objects: event
and context
.
function beforeSend(event, context)
Event
The event is generated by the RUM Browser SDK. For more information about different event types and collected attributes, see the RUM data collected documentation.
The event.type
property lets you identify the type of the event:
{
...,
"event.type": "resource",
...
}
Context
The context is made of the Browser APIs that trigger the event creation. The context values depend on the event.type
:
For more information about the structure of context objects, see the Browser SDK repository.
Examples
Collect HTTP headers from a Fetch response with the following beforeSend
configuration. Additional context attributes must be stored in the event.context
object.
import { datadogRum } from '@datadog/browser-rum';
datadogRum.init({
...,
beforeSend: (event, context) => {
// collect a RUM resource's response headers
if (event.type === 'resource' && event.resource.type === 'fetch') {
event.context.responseHeaders = Object.fromEntries(context.response.headers)
}
return true
},
...
});
The following tabs show the information contained in the beforeSend
event and context objects for this example:
{
"application": {
"id": "<YOUR_APPLICATION_ID>"
},
"date": 1623933472075,
"service": "shopist-web-ui",
"session": {
"type": "user",
"id": "308f14ac-2a27-4b50-945c-be345778994f",
"has_replay": true
},
"view": {
"id": "768f0eb9-39c5-4a1f-9c13-476bd08166bb",
"referrer": "http://localhost:3000/",
"url": "http://localhost:3000/"
},
"resource": {
"id": "e5d1d3a4-7240-4910-bd0a-af253e06d301",
"type": "fetch",
"duration": 2577300000,
"method": "get",
"status_code": 200,
"url": "https://api.shopist.io/products.json",
"size": 10307,
"download": {
"duration": 1800000,
"start": 2575500000
},
"first_byte": {
"duration": 2574600000,
"start": 900000
}
},
"type": "resource",
"context": {
"browser_test": false,
"usr.email": "jane@doe.com",
"usr.id": "f57eg30cc9"
}
}
{
"performanceEntry": {
"name": "https://api.shopist.io/products.json",
"entryType": "resource",
"startTime": 230,
"duration": 2577.300000011921,
"initiatorType": "fetch",
"nextHopProtocol": "h2",
"workerStart": 0,
"redirectStart": 0,
"redirectEnd": 0,
"fetchStart": 230,
"domainLookupStart": 230,
"domainLookupEnd": 230,
"connectStart": 230,
"connectEnd": 230,
"secureConnectionStart": 230,
"requestStart": 230.90000000596046,
"responseStart": 2805.5,
"responseEnd": 2807.300000011921,
"transferSize": 10743,
"encodedBodySize": 10307,
"decodedBodySize": 10307,
"serverTiming": [],
"workerTiming": []
},
"response": {
"body": (...),
"bodyUsed": true,
"headers": Headers {},
"ok": true,
"redirected": false,
"status": 200,
"statusText": "",
"type": "basic",
"url": "https://api.shopist.io/products.json"
},
"requestInput": "https://api.shopist.io/products.json",
"requestInit": {
"headers": [
[
"Content-Type",
"application/json; charset=utf-8"
],
[
"x-datadog-origin",
"rum"
],
[
"x-datadog-parent-id",
"595857188965892467"
],
[
"x-datadog-sampled",
"1"
],
[
"x-datadog-sampling-priority",
"1"
],
[
"x-datadog-trace-id",
"796856647783126791"
]
],
"method": "get",
"cache": "no-cache"
}
}
Discard a frontend error
Discard frontend errors if their message includes “profile is not defined” with the following beforeSend
configuration:
import { datadogRum } from '@datadog/browser-rum';
datadogRum.init({
...,
beforeSend: (event, context) => {
// discard a RUM error if its message includes 'profile is not defined'
if (event.type === 'error' && event.error.message.includes('profile is not defined')) {
return false
}
},
...
});
The following tabs show the information contained in the beforeSend
event and context objects for this example:
{
"application": {
"id": "75d50c62-8b66-403c-a453-aaa1c44d64bd"
},
"date": 1623941859639,
"service": "shopist-web-ui",
"session": {
"type": "user",
"id": "4203a142-1e3c-41b0-822d-316705d98f19",
"has_replay": true
},
"view": {
"id": "0a771c95-9bc4-4640-978e-ad28da64da45",
"referrer": "http://localhost:3000/profile",
"url": "http://localhost:3000/profile-edit"
},
"action": {
"id": "7b30e681-ce5c-47a8-ac22-6aff8be59744"
},
"error": {
"id": "3c0295b1-da48-4827-93c9-ea06be4aafd9",
"message": "profile is not defined",
"source": "source",
"stack": "ReferenceError: profile is not defined\n at VueComponent.discardEdit @ http://localhost:3000/_nuxt/pages/profile-edit.js:911:41\n at invokeWithErrorHandling @ http://localhost:3000/_nuxt/commons.app.js:12167:26\n at VueComponent.invoker @ http://localhost:3000/_nuxt/commons.app.js:12492:14\n at invokeWithErrorHandling @ http://localhost:3000/_nuxt/commons.app.js:12167:26\n at VueComponent.Vue.$emit @ http://localhost:3000/_nuxt/commons.app.js:14196:9\n at VueComponent.cancelDraft @ http://localhost:3000/_nuxt/pages/profile-edit.js:828:12\n at invokeWithErrorHandling @ http://localhost:3000/_nuxt/commons.app.js:12167:26\n at HTMLButtonElement.invoker @ http://localhost:3000/_nuxt/commons.app.js:12492:14\n at HTMLButtonElement.original._wrapper @ http://localhost:3000/_nuxt/commons.app.js:17221:25",
"type": "ReferenceError",
"handling": "unhandled"
},
"type": "error",
"context": {
"browser_test": false,
"usr.email": "jane@doe.com",
"usr.id": "f57eg30cc9"
}
}
{
"error": {
"message": "profile is not defined",
"stack": "ReferenceError: profile is not defined\n at VueComponent.discardEdit @ http://localhost:3000/_nuxt/pages/profile-edit.js:911:41\n at invokeWithErrorHandling @ http://localhost:3000/_nuxt/commons.app.js:12167:26\n at VueComponent.invoker @ http://localhost:3000/_nuxt/commons.app.js:12492:14\n at invokeWithErrorHandling @ http://localhost:3000/_nuxt/commons.app.js:12167:26\n at VueComponent.Vue.$emit @ http://localhost:3000/_nuxt/commons.app.js:14196:9\n at VueComponent.cancelDraft @ http://localhost:3000/_nuxt/pages/profile-edit.js:828:12\n at invokeWithErrorHandling @ http://localhost:3000/_nuxt/commons.app.js:12167:26\n at HTMLButtonElement.invoker @ http://localhost:3000/_nuxt/commons.app.js:12492:14\n at HTMLButtonElement.original._wrapper @ http://localhost:3000/_nuxt/commons.app.js:17221:25"
}
}
Further Reading
Additional helpful documentation, links, and articles: