Download PDF
Download page Add Custom User Data to a Page Browser Snapshot.
Add Custom User Data to a Page Browser Snapshot
Related pages:
You can add user information that is specific to your application to a browser snapshot. The information is expressed as key-value pairs that are attached the JavaScript Agent configuration and later included in the beacons sent to the EUM Server.
The JavaScript Agent initializes user data differently depending on the page type (base, Ajax, virtual) and the method used (immediately invoked function expressions, function pointers, and literals). See Methods for Setting Custom User Data to learn when the JavaScript Agent initializes the user data for each page type and method.
The maximum size allowed for user data in a page is 2048 characters (CORS beacon) or 100 bytes (image beacon). The maximum size includes the keys-value pairs, syntax characters such as braces, and quotation marks.
View Custom User Data
Custom user data appears in Browser Analyze, Browser Snapshots, and Sessions. View the following tabs to learn more about how user data is viewed and used in the Controller UI.
In this Browser Analyze screenshot, the user data vehicleYear is used to sort the records. You can also select fields to view user data.
This Browser Snapshots tab screenshot shows you how to filter results with user data.
You view user data in the Session Summary of the Session Details dialog as shown in this screenshot. In sessions, the custom user data is only included when the base page with the custom user data is the first page of the session.
Methods for Setting Custom User Data
You can use several methods to set custom data for each page type (base, Ajax, virtual). Each method has its own syntax, execution time, and use case. This table outlines the execution time and potential use case for each method and page type.
Method Type | Page Type | Execution Time | Potential Use Cases |
---|---|---|---|
Immediately Invoked Function Expressions (IIFE) | Base | These are JavaScript functions that run as soon as they are defined. They're also known as self-executing anonymous functions. | If your base/virtual page or Ajax request depends on information from different resources, you can set static information for custom user data with IIFE. For example, if two different server scripts generate content for the base page, you could use the IIFE on the client to set the static user data. |
Ajax | |||
Virtual | |||
Function pointers | Base | The JavaScript Agent executes function pointers when the onload event is triggered. | Data extracted from cookies, the page, and meta data. |
Ajax | This event is triggered when an Ajax call is made. Custom user data for the Ajax events are attached to AJAX requests. | Meta data regarding the Ajax request such as the URL, HTTP method, or the request payload. | |
Virtual | This event is triggered when the virtual page is created. The virtual page is a dynamically recreated version of the base page, and custom user data set for VPageView events are attached to the virtual page records. | Use if the information is derived or found somewhere on the page because of the creation of the virtual page. User-specific fields or user data set based on the URL and DOM changes. | |
Literals | Base | You can simply use literal values to set custom data. The values, as with IIFE, are set as soon as the values are defined. | Constants, static data extracted and set on the server. |
Ajax | |||
Virtual |
User Data Types
For each event callback that is triggered, you can add user data by returning objects containing key-value pairs of different data types. Each user data type is an object containing properties of a specific data type.
Make sure the data type correctly matches the key-value pair. If you send the wrong key-value inside the userData object, such as adding a date key-value pair in a string data type, you will receive a generic error.
Data Type | Description | Example |
---|---|---|
| This data type is for setting one or more properties of type string . The value must be in a string, even if the value is set to a numeric value. |
JS
|
| This data type is for setting one or more properties of type long and must be a numeric value without decimals. |
JS
|
userDataDouble | This data type is for setting one or more properties of type double and must be a numeric value with decimals. |
JS
|
| This data type is for setting one or more properties of type boolean. |
JS
|
| This data type is for setting one or more properties of type date . The value must be the converted Epoch value of the date. |
JS
|
Syntax of User Data Objects
You add user data as objects for each page event to the JavaScript Agent configuration. The base page, Ajax, and virtual pages have the following corresponding user data objects:
PageView
Ajax
VPageView
The PageView
, Ajax
, and VPageView
objects have slightly different syntaxes. UserPageName
is only available for PageView
and VPageView
, and not for Ajax
and Error
.
userEventInfo: {
"PageView": function(context) {
return {
userPageName: "String"
userData: {
userDataOne: "String",
userDataTwo: "String",
someKey: "String"
},
userDataLong: {
longPropertyOne: Numeral,
longPropertyTwo: Numeral,
someKey: Numeral
},
userDataDouble: {
userDataDoubleOne: Decimal,
userDataDoubleTwo: Decimal,
someKey: Numeral
},
userDataBoolean: {
userDataBooleanOne: Boolean,
userDataBooleanTwo: Boolean,
someKey: Boolean
},
userDataDate: {
epoch1: Epoch numeral,
epoch2: Epoch numeral,
currentTime: ((new Date()).getTime()),
someKey: ((new Date()).getTime())
}
}
}
"Ajax" : function(context) {
if (context.method.toLowerCase() === 'post') {
var anyKey = "String";
} else {
variableName = "String";
}
return {
userData: {
userDataOne: "String",
userDataTwo: "String"
variableName: VariableName
},
userDataLong: {
longPropertyOne: Numeral,
longPropertyTwo: Numeral
},
userDataDouble: {
userDataDoubleOne: Decimal,
userDataDoubleTwo: Decimal
},
userDataBoolean: {
userDataBooleanOne: Boolean,
userDataBooleanTwo: Boolean
},
userDataDate: {
epoch1: Epoch numeral,
epoch2: Epoch numeral
}
}
},
"VPageView": function(context) {
return {
userPageName: "String",
userData: {
userDataOne: "String",
userDataTwo: "String"
},
userDataLong: {
longPropertyOne: Numeral,
longPropertyTwo: Numeral
},
userDataDouble: {
userDataDoubleOne: Decimal,
userDataDoubleTwo: Decimal
},
userDataBoolean: {
userDataBooleanOne: Boolean,
userDataBooleanTwo: Boolean
},
userDataDate: {
epoch1: Epoch numeral,
epoch2: Epoch numeral
}
}
},
"Error": function(context) {
return {
userPageName: "String",
userData: {
username: "String",
cart: "String"
},
userDataLong: {
longExample1: Numeral,
longExample2: Numeral
},
userDataDouble: {
doubleExample1: Decimal,
doubleExample2: Decimal
},
userDataBoolean: {
booleanExample1: Boolean,
booleanExample2: Boolean
},
userDataDate: {
epoch1: Epoch numeral,
epoch2: Epoch numeral
}
}
}
}
};
userEventInfo: {
"PageView": function(context) {
return {
userPageName: "UserEventInfoTestPage",
userData: {
username: "basepage_user",
cart: "100.00",
someKey: "111222333444555"
},
userDataLong: {
numberOfProducts: 17,
numberOfSales: 1213
someKey: 111222333444555
},
userDataDouble: {
monthlyVisitFrequency: 0.13333333,
avgCustomerConversion: 0.0361922
someKey: 111222333444555.666
},
userDataBoolean: {
returnCustomer: true,
subscriber: false
someKey: true
},
userDataDate: {
checkoutTime: 1441751614436,
currentTime: ((new Date()).getTime()),
someKey: ((new Date()).getTime())
}
}
"Ajax" : function(context) {
var property = '';
if (context.method.toLowerCase() === 'post') {
property = "Could be doing something";
}
else {
property = "Idempotent, hopefully";
}
return {
userData: {
username: "xhr_user",
cart: "218.50",
property: property
},
userDataLong: {
numberOfProducts: 17,
numberOfSales: 1213
},
userDataDouble: {
monthlyVisitFrequency: 0.13333333,
avgCustomerConversion: 0.0361922
},
userDataBoolean: {
returnCustomer: true,
subscriber: false
},
userDataDate: {
checkoutTime: 1441751614436,
currentTime: ((new Date()).getTime()),
}
}
},
"VPageView": function(context) {
return {
userData: {
username: "virtualpage_user",
cart: "200.00"
},
userDataLong: {
numberOfProducts: 17,
numberOfSales: 1213
},
userDataDouble: {
monthlyVisitFrequency: 0.13333333,
avgCustomerConversion: 0.0361922
},
userDataBoolean: {
returnCustomer: true,
subscriber: false
},
userDataDate: {
checkoutTime: 1441751614436,
currentTime: ((new Date()).getTime()),
}
}
},
"Error": function(context) {
return {
userPageName: "UserEventInfoTestPage",
userData: {
username: "automated_tester",
cart: "100.00"
},
userDataLong: {
longExample1: 129414,
longExample2: 524546
},
userDataDouble: {
doubleExample1: 5982.612575313542,
doubleExample2: 5084.016120518092
},
userDataBoolean: {
booleanExample1: true,
booleanExample2: false
},
userDataDate: {
epoch1: 1441751614436,
epoch2: 1441751614438
}
}
}
}
};
Capture Ajax Data for Setting User Data
When setting user data for the Ajax event, the JavaScript Agent configuration provides a context
object that has properties for the HTTP method, the request URL, and the request payload of the Ajax request. You can use this information to set values for the user data configuration object.
The JavaScript Agent does not intercept or expose the response from the Ajax request. Thus, you can only include the request information (HTTP method, request URL, and request payload) in the user data that you report.
Ajax Context Object
To access the URL and HTTP method of the Ajax request, you can simply access the method
and url
properties of the context
object. For the request payload of the Ajax request, you need to first match the payload parameters (HTTP method or Ajax URL) to access the data
property. See Match the Ajax Payload Parameters to learn how to define the filters to match the payload parameters.
The context
object has the following properties:
Property | Description | Data Type | Requirement to Access Property |
---|---|---|---|
method | The HTTP method used to make the Ajax request. | string | XHR call |
url | The URL used to make the Ajax request. | string | XHR call |
data | The request payload attached to the Ajax request. | Any data type that can be passed as the body to xhr.send. |
|
Match the Ajax Payload Parameters
To access the request payload, you need to use xhr.payloadParams
array to match the HTTP method and/or the Ajax URL. To match the Ajax URL, you can specify one or more patterns. To match the HTTP method, you include one or more objects specifying HTTP methods.
In the "Match HTTP Methods" example, the payloadParams
array is used to match the HTTP methods "POST" and "GET". In the "Matching URLs" example, the payloadParams
array is used to match URLs with the following string: '.*/xhr/uptime'
.
<script type = 'text/javascript' charset = 'UTF-8' >
window['adrum-config'] = {
xhr: {
payloadParams: [{
method: 'POST'
}, {
method: 'GET'
}]
},
...
}
window['adrum-config'] = {
xhr: {
payloadParams: [{urls: [{pattern: '.*/xhr/uptime'}]}]
},
...
}
Ajax Payload Filter Examples
Conventional Ajax Requests
In the following examples, the data from a conventional Ajax request payload is used to set custom user data. For capturing the request payload for Fetch API calls, see Ajax Requests Using the Fetch API.
This example only sets the user data configuration objects with data from the Ajax request payload if the HTTP method is POST
.
<script type='text/javascript' charset='UTF-8'>
window['adrum-config'] = {
xhr: {
payloadParams: [{method: 'POST'}]
},
userEventInfo: {
"Ajax" : function(context) {
if (context.data && context.data.indexOf("purchase") > -1) {
// The URLSearchParams API does not work on IE/Edge
var payload = new URLSearchParams(context.data);
return {
userData: {
username: payload.get("username"),
email: payload.get("email"),
phone: payload.get("phone")
},
userDataLong: {
customerId: Number(payload.get("customer_id"),
totalPurchases: Number(payload.get("total_purchases")
},
userDataDouble: {
purchaseTotal: Double(payload.get("total")
},
userDataBoolean: {
discounted: Boolean(payload.get("discounted"),
vipMember: Boolean(payload.get("member")
},
userDataDate: {
purchaseTime: Date.now()
}
}
}
}
};
</script>
<script src='//cdn.appdynamics.com/adrum/adrum-latest.js' type='text/javascript' charset='UTF-8'></script>
This example only sets the user data configuration objects with data from the Ajax request payload if the Ajax URL matches the pattern ".*/transaction"
. For example, the URL http://example.com/transaction
would match the pattern and cause the user data configuration to be set with data from the Ajax request payload.
<script type='text/javascript' charset='UTF-8'>
window['adrum-config'] = {
xhr: {
payloadParams: [{urls: [{pattern: '.*/transaction'}]}]
},
userEventInfo: {
"Ajax" : function(context) {
if (context.data && (context.data.indexOf("username") > -1) && (context.data.indexOf("customer_id") > -1) && (customer.data.indexOf("phone") > -1)) {
// The URLSearchParams API does not work on IE/Edge
var payload = new URLSearchParams(context.data);
return {
userData: {
username: payload.get("username"),
email: payload.get("email"),
phone: payload.get("phone")
},
userDataLong: {
customerId: Number(payload.get("customer_id")
totalPurchases: Number(payload.get("total_purchases") || 0
},
userDataDouble: {
purchaseTotal: Number(payload.get("total") || 0
},
userDataBoolean: {
discounted: Boolean(payload.get("discounted") || false,
vipMember: Boolean(payload.get("member") || false
},
userDataDate: {
purchaseTime: Date.now()
}
}
}
}
};
}
</script>
<script src='//cdn.appdynamics.com/adrum/adrum-latest.js' type='text/javascript' charset='UTF-8'></script>
Ajax Requests Using the Fetch API
The example below demonstrates how to use the JavaScript Agent configuration to match the HTTP method, the request URL, and the request body for Ajax calls using the Fetch API. The Fetch API call is also provided to add context. The JavaScript Agent cannot access the request body, however, if you supply your own Request object to the fetch
method.
This Fetch API example sets the from the Ajax request payload if the HTTP method is POST
.
<script type='text/javascript' charset='UTF-8'>
// Note: URLSearchParams() is not supported in IE/Edge
let queryParams = new URLSearchParams(window.location.search.substr(1));
fetch('https://my-json-server.typicode.com/typicode/demo/posts', {
method: 'post',
body: queryParams.toString()
}).then(function(response) {
return response.json();
}).then(function(data) {
console.log('Posted content:', data.request_url);
});
</script>
This example only sets the user data configuration objects with data from the Ajax request payload if the HTTP method is POST
and the Ajax URL matches the pattern ".*/posts"
.
<script type='text/javascript' charset='UTF-8'>
window['adrum-config'] = {
xhr: {
payloadParams: [{method: 'POST'}, {urls: [{pattern: '.*/posts'}]}]
},
userEventInfo: {
"Ajax": function (context) {
var payload = null;
if (context.data && (context.data.indexOf("id") > -1) && (context.data.indexOf("title") > -1)) {
// The URLSearchParams API does not work on IE/Edge
payload = new URLSearchParams(context.data).toString();
} else if (context.data && context.data.indexOf("id") > -1) {
// The URLSearchParams API does not work on IE/Edge
var params = new URLSearchParams(context.data);
params.set("title", "Post for " + params.get("id"));
payload = params.toString();
} else {
payload = "Payload is not available";
}
return {
userData: {
username: "xhr_user",
cart: "218.50",
payload: payload
}
}
}
}
};
</script>
<script src='//cdn.appdynamics.com/adrum/adrum-latest.js' type='text/javascript' charset='UTF-8'></script>
Custom User Data Examples
The following examples show you how to set custom data for different page types and using the different methods:
Setting User Data with Function Pointers
The example below assigns a value to the userPageName
property of the PageView
object by executing the function extractUserData
, which extracts data from the cookies.
< script type = 'text/javascript'
charset = 'UTF-8' >
(function (config) {
(function (info) {
info.PageView = extractUserData;
})(config.userEventInfo || (config.userEventInfo = {}))
})(window['adrum-config'] || (window['adrum-config'] = {}));
function extractUserData() {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
if (cookie.indexOf("role=") === 0) {
var role = cookie.substring(5);
}
}
return {
userPageName: role
};
} <
/script> <
script src = '//cdn.appdynamics.com/adrum/adrum-latest.js'
type = 'text/javascript'
charset = 'UTF-8' > < /script>
Setting User Data with an Anonymous Function
You can also use anonymous functions that return an object as shown in this example for setting user data for virtual pages.
< script type = 'text/javascript'
charset = 'UTF-8' >
(function (config) {
(function (info) {
info.VPageView = function () {
return {
userData: {
version: window.location.href.split("/")[4],
space: space(),
email: getEmail()
},
userPageName: $('title').get(0).text,
userDataDate: {
currentTime: ((new Date()).getTime())
},
userDataBoolean: {
watchingPage: watchingPage()
}
}
}
})(config.userEventInfo || (config.userEventInfo = {}))
})(window['adrum-config'] || (window['adrum-config'] = {})); <
/script> <
script src = '//cdn.appdynamics.com/adrum/adrum-latest.js'
type = 'text/javascript'
charset = 'UTF-8' > < /script>
Setting User Data with Multiple Methods
You might also want to use a combination of literal values, named and anonymous functions as this example does for setting user data for the Ajax
event. Note, the context
object is only available for Ajax
events, and this object has the properties data
(stores the request payload), method
(HTTP method used to make Ajax request), and url
(the Ajax request URL).
<script type='text/javascript' charset='UTF-8'>
(function(config){
(function(info) {
info.Ajax = function(context) {
return {
userPageName: $('title').get(0).text,
userData: extractUserData(context)
userDataBoolean: {
"visited": true
}
}
};
})(config.userEventInfo || (config.userEventInfo = {}))
})(window['adrum-config'] || (window['adrum-config'] = {}));
function extractUserData(context) {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
if (cookie.indexOf("email=") === 0) {
var role = cookie.substring(5);
}
}
return {
role: role,
url: context.url,
method: context.method
};
}
</script>
<script src='//cdn.appdynamics.com/adrum/adrum-latest.js' type='text/javascript' charset='UTF-8'></script>