Browser RUM
Introduction
Browser RUM (Real User Monitoring) delivers full visibility into the user experience across every digital transaction in web applications. It captures real user performance data directly from the browser, offering deep insights into page load times, user interactions, and frontend issues to optimize performance in real time.
Getting Started
Compatibility
Browser RUM is supported for the following browsers/runtime:
- Google Chrome (Version 131.0.6778.85 and above)
Data Collection Method
GSH Overview
Browser RUM collects real user monitoring data using VuNet’s JavaScript RUM Agent.
The recommended approach is to deploy a proxy server in the DMZ to receive telemetry from users' browsers running the web application. This proxy serves as a secure intermediary between the end-user browsers (where the RUM JavaScript agent executes) and the RUM data collector of the observability platform hosted within the internal network.
Prerequisites
Inputs for Configuring Data Source
To configure this data source, you will require the following parameters:
Key
Help Text
Application Name
Name of the monitored application.
SSL
Select Yes
if you want to require TLS (SSL) for secure communication. Select
No
if TLS is not required.
Traces Sampling Percentage
Specify the sampling percentage for trace data collected by browser RUM agent. A percentage number between 0 and 100 is to be provided. If 0% is used, RUM agent will not collect any traces. If 100% is used, RUM agent will collect and send all traces. When a number between 0 and 100 is used, the RUM agent will send the specified percentage of traces using a random sampling policy.
Session Replay Sampling Percentage
Specify the sampling percentage for session replay data collected by the browser RUM agent. A value between 0 and 100 must be provided.
- If set to 0%, the RUM agent will not collect any session replay data.
- If set to 100%, session replay data will be captured and sent for all user sessions.
- For values between 0 and 100, the RUM agent uses a normalized percentage function to decide whether a session is selected for replay. The decision is based on the following logic:
percentage(base + replayPercentage * RandomJitter) < replayPercentage
base: A numeric value generated by hashing the session ID (originally a string).
RandomJitter: A randomness factor that can vary by ±25% to ensure better distribution across sessions.
percentage: A function that normalizes the result to always fall within the range of 0 to 100.
- Values above 100 (e.g., 105) are capped at 100.
- Values below 0 (e.g., -5) are raised to 0.
If the normalized value is less than the configured replayPercentage, the session is selected for replay. This mechanism helps control the volume of session replay data while maintaining fair and balanced sampling across sessions.
NOTE:
To disable trace collection, set Traces Sampling Percentage to 0.
To disable session replay collection, set Session Replay Sampling Percentage to 0.
To disable both trace and session replay data, set both values to 0.
Certificate:
Browser-to-Proxy SSL Certificate: Used to establish secure connections between the JavaScript running in the browser and the proxy server.
OTEL Collector Certificate: Required for secure communication between the proxy server and the OpenTelemetry (OTEL) collector.
CORS
To ensure successful communication between the application and the proxy server, the following CORS-related requirements must be met:
Restrict Origins: Only trusted application domains should be allowed to send data. The proxy server must be configured to whitelist specific origins using the following headers:
Access-Control-Allow-Origin: https://<appname.com>
Replace https://<appname.com> with the actual domain(s) of your frontend application.
Security Mechanism Compatibility: If the application uses security mechanisms such as CSP (Content Security Policy) or firewalls, they must be configured to allow communication with the proxy.
CSP headers must permit connect-src access to the proxy domain:
Content-Security-Policy: script-src 'self'; connect-src 'self' https://<proxy_address>;
Ensure the proxy's hostname (e.g., https://otelproxy.com) is included in the connect-src directive.
Preflight Request Support: The proxy must correctly handle preflight OPTIONS requests. These requests are automatically issued by browsers before a POST request to verify CORS permissions.
Ensure your NGINX or proxy server returns the appropriate CORS headers for OPTIONS requests.
The Role of the Proxy Server in Browser RUM
The proxy server is a critical component in a Real User Monitoring (RUM) deployment. It acts as a secure intermediary between end-user browsers (where the RUM JavaScript agent runs) and the backend RUM data collector. Integrating a proxy server provides the following technical benefits:
SSL/TLS Termination: The proxy server terminates HTTPS connections, ensuring encrypted and trusted transmission of RUM data from browsers.
CORS Enforcement: It manages Cross-Origin Resource Sharing (CORS) headers, allowing only requests from approved frontend domains to be processed, which protects against cross-site data leaks.
API Key and Authorization Validation: Incoming requests are checked for valid API keys or authorization tokens. Unauthorized requests are rejected, ensuring only trusted clients can send monitoring data.
Request Routing and Load Balancing: The proxy server forwards accepted telemetry data to the correct backend RUM collector endpoint and can distribute load across multiple backend instances for high availability.
Network Security: Only the proxy is exposed to the internet. The backend RUM collector stays protected within a private network, and firewall rules only need to allow access to the proxy.
Client IP Forwarding: To enable accurate user attribution, the proxy passes the original client IP address to the backend using headers such as X-Forwarded-For.
Preflight and OPTIONS Handling: The proxy handles browser CORS preflight (OPTIONS) requests, which is essential for seamless communication from modern browsers.
Security Headers Management: Additional security headers (like Strict-Transport-Security and X-Frame-Options) can be injected to enhance security.
Prerequisites
Inputs for Configuring Data Source
-
Application: Enter the name of the application you want to monitor
-
SSL Required: Enable TLS communication for Browser RUM ingestion. Once enabled, browser RUM data sent from the application to the vuSmartMaps ingestion endpoint will be securely encrypted. After enabling this feature, follow the additional instrumentation configuration steps provided in the 'TLS Configuration' section of the instrumentation guide.
-
Traces Sampling Percentage: Specify the sampling percentage for trace data collected by browser RUM agent. A percentage number between 0 and 100 is to be provided. If 0% is used, RUM agent will not collect any traces. If 100% is used, RUM agent will collect and send all traces. When a number between 0 and 100 is used, the RUM agent will send the specified percentage of traces using a random sampling policy.
-
Session Replay Sampling Percentage: Specify the sampling percentage for session replay data collected by the browser RUM agent. A value between 0 and 100 must be provided.
-
If set to 0% , the RUM agent will not collect any session replay data.
-
If set to 100% , session replay data will be captured and sent for all user sessions.
-
For values between 0 and 100, the RUM agent uses a normalized percentage function to decide whether a session is selected for replay. The decision is based on the following logic: percentage(base + replayPercentage * RandomJitter) < replayPercentage
base : A numeric value generated by hashing the session ID (originally a string). RandomJitter : A randomness factor that can vary by ±25% to ensure better distribution across sessions. percentage : A function that normalizes the result to always fall within the range of 0 to 100.
- Values above 100 (e.g., 105) are capped at 100.
- Values below 0 (e.g., -5) are raised to 0. If the normalized value is less than the configured replayPercentage , the session is selected for replay. This mechanism helps control the volume of session replay data while maintaining fair and balanced sampling across sessions.
- Allowed Origins: Allowed Origins: Comma-separated list of origins permitted to access the OpentTelemetry Collector. Example: "http://example.com,https://app.example.com,http://localhost:3000" If not specified, defaults to "*" (allow all origins)
- Allowed Headers: Allowed Headers: Comma-separated list of HTTP headers permitted in CORS requests Example: "Content-Type,Authorization,X-Requested-With" If not specified, defaults to "*" (allow all headers)
Firewall Requirement
To collect data from this O11ySource, ensure the following ports are opened:
| Source IP | Destination IP | Destination Port | Protocol | Direction |
|---|---|---|---|---|
| Browser | Proxy Server | 443 | TCP | Inbound |
| Proxy Server | vuSmartMaps Web Services | 443 | TCP | Outbound |
| Proxy Server | vuSmartMaps OTEL Collector | 4319* | TCP | Outbound |
*Before providing the firewall requirements, please update the port based on the customer environment.
Configuring the Target
Modify the application's front end code to include Vunet's JavaScript RUM Agent using CDN or NPM based on your environment. The complete instructions for instrumentation can be downloaded as a package from the Browser RUM O11ySource.
Configuration Steps
GSH Overview
- *``
Enable
``**
the Browser RUM O11ySource.
Select the sources tab and press the
- *``
+
``**
button to add a new application that has to be monitored.
Provide the required configurations:
Application Name
SSL
Trace Sampling %
Session Replay %
Afterwards, select
- *``
Save and Continue
``**
to proceed with downloading the java script instrumentation package
Then click
- *``
Finish
``**
to close the data source window.
Client Side Browser RUM Instrumentation
Instrumenting JavaScript Applications
This section guides you through tracing JavaScript applications using Browser RUM.
Before you begin, ensure the following:
Configure your web server as a reverse proxy to serve the RUM script and forward trace data, or use a dedicated proxy server for receiving RUM traces.
The RUM script should send data to the proxy at the following endpoint:
https://<proxy_address>/rum/v1/traces,
which forwards it to the OpenTelemetry Collector:
https://<RUM-collector-host>:4319/v1/traces
The instrumentation would require the JavaScript to be added to html pages by editing/updating the html pages and adding the <script> tag.
The method of editing/updating HTML files depends on the technology used for the web application:
JavaScript-based applications (JS, Angular, React):
For Single Page Applications (SPA): edit the main HTML file (typically index.html) to include the <script> tag.
For Multi Page Applications: update all main HTML pages to include the <script> tag.
Server-side rendered applications (PHP, JSP, ASP.NET): the HTML files are generated dynamically by the server. Insert the <script> tag via server-side code (e.g., in header.php, _Layout.cshtml, etc.).
Ensure that the application and environment allow externally loaded or inline scripts to be executed, since the RUM SDK is loaded as a script.
Host / Virtual Machine (VM)
Copy the RUM Script: Add /public/js/vunet-rum.js (absolute path) to your application’s codebase, preferably in the js folder.
Add the RUM Script to the Page Header: Insert the following code snippet in your HTML file's <head> section:
<script>
(function (w, s, d, r, e, n) {
(w[s] = w[s] || {
readyListeners: [],
onReady: function (e) {
w[s].readyListeners.push(e);
},
}),
((e = d.createElement('script')).async = 1),
(e.src = r),(n = d.getElementsByTagName('script')[0]).parentNode.insertBefore(e, n);
})( window, 'vunetRum', document, '/public/js/rum.vunet.js');
window.vunetRum.onReady(function () {
window.vunetRum.initialize({
collectionSourceUrl: "<VUNET_TELEMETRY_RECEIVER_URL>", //mention the urlwhere the otel collector is running
serviceName: '<SERVICE_NAME>',// mention the service name of the application
applicationName: '<APPLICATION_NAME>', // mention the name of the application
decideApiEndpoint: "/vuSmartMaps/api/rum/",
collectErrors: true,
dropShortTracesMs: 100,//drop traces shorter than 100 milliseconds
authorizationToken: "ef7ae8b1fa097092a66a56882fd8366cfbdb1b6848ae0d529a21a68a94e245020"
});
});
</script>
Update the Variables
VUNET_TELEMETRY_RECEIVER_URL: URL of the reverse proxy
Example: http://10.1.1.1/rum/v1/traces
SERVICE_NAME: Service name for the application
Example: 'vubank-frontend'
APPLICATION_NAME: Name of the application
Example: 'IBMB'
authorizationToken:
Generate a token and include it in the RUM script on the application side.
The same token must also be configured on the proxy server to validate incoming requests.
On a Linux host, you can use the following command to generate the token:
openssl rand -hex 32
dropShortTracesMs:
Filters out short, low-value traces based on total trace duration.
If the total duration of a trace (from its root span’s start to its end) is less than the specified value, the entire trace is discarded.
All spans within such short traces will also be excluded.
This helps eliminate fast, low-impact user interactions.
Value is specified in milliseconds (e.g., 100).
Rebuild and deploy the updated application to your hosting environment to apply changes.
Cloud Machine Setup (Using CDN)
For cloud environments, use the CDN-hosted script below:
<script>
(function (w, s, d, r, e, n) {
(w[s] = w[s] || {
readyListeners: [],
onReady: function (e) {
w[s].readyListeners.push(e);
},
}),
((e = d.createElement('script')).async = 1),
(e.src = r),(n = d.getElementsByTagName('script')[0]).parentNode.insertBefore(e, n);
})( window, 'vunetRum', document, 'https://cdn.vunet.ai/rum/vunet-rum.js');
window.vunetRum.onReady(function () {
window.vunetRum.initialize({
collectionSourceUrl: "<VUNET_TELEMETRY_RECEIVER_URL>", //mention the urlwhere the otel collector is running
serviceName: '<SERVICE_NAME>',// mention the service name of the application
applicationName: '<APPLICATION_NAME>', // mention the name of the application
decideApiEndpoint: "/vuSmartMaps/api/rum/",
collectErrors: true,
dropShortTracesMs: 100,//drop traces shorter than 100 milliseconds
authorizationToken: "ef7ae8b1fa097092a66a56882fd8366cfbdb1b6848ae0d529a21a68a94e245020"
});
});
</script>
NOTE: Ensure that the CSP is configured to allow loading files from our CDN https://cdn.vunet.ai/rum/vunet-rum.js.
If the JS file is loaded correctly, then it should function as expected. If there are difficulties in receiving data, verify that the JS file is properly loaded and that the collectionSourceUrl is correct and accessible.
Update the Variables
VUNET_TELEMETRY_RECEIVER_URL: URL of the reverse proxy
Example: http://10.1.1.1/rum/v1/traces
SERVICE_NAME: Service name for the application
Example: 'vubank-frontend'
APPLICATION_NAME: Name of the application
Example: 'IBMB'
Container
For containerized environments, follow these steps:
Add the RUM script to your page header as shown above.
Rebuild the Docker container with the updated codebase.
Kubernetes
For Kubernetes environments, follow these steps:
Add the RUM script to your page header as shown above.
Rebuild and redeploy the Docker container in your Kubernetes environment.
Metrics Collected
| Name | Description | Data Type |
|---|---|---|
| timestamp | The timestamp when the span or event occurred. | DateTime64(6) |
| traceId | Unique identifier for a distributed trace that includes multiple spans. | String |
| spanId | Identifier for a specific span within a trace. | String |
| span_parentSpanId | Identifier linking this span to its parent span, indicating the hierarchical relationship. | String |
| span_name | Name or label for the span, typically indicating the operation or activity being traced. | LowCardinality(String) |
| span_kind | Indicates client/server/internal span categorization. | LowCardinality(String) |
| span_start_time | Timestamp marking the start time of the span. | DateTime64(6) |
| span_end_time | Timestamp marking the end time of the span. | DateTime64(6) |
| span_durationNano | Duration of the span in nanoseconds. | UInt64 |
| status_code | Status code indicating the result of the span (e.g., success, error). | UInt8 |
| is_root_span | Boolean indicating if the span is the root of the trace. | Bool |
| resource_attributes_application | Application from which the span originated. | LowCardinality(String) |
| resource_attributes_service_name | Service name from which the span originated. | LowCardinality(String) |
| span_attributes_browser_name | Browser name of the end user. | LowCardinality(String) |
| span_attributes_os_name | Operating system name of the end user. | LowCardinality(String) |
| span_attributes_component | Component associated with the span. | String |
| span_attributes_http_url | Full HTTP URL involved in the span. | String |
| span_attributes_instrumentation_library_name | Name of the instrumentation library used. | String |
| span_attributes_location_href | Location (href) of the span source. | String |
| span_attributes_rum_session_id | Browser RUM session identifier. | String |
| span_attributes_dns_lookup_time | Time spent on DNS lookup (ns). | UInt64 |
| span_attributes_tcp_connect_time | TCP connection time (ns). | UInt64 |
| span_attributes_secure_connect_time | TLS handshake time (ns). | UInt64 |
| span_attributes_request_time | Request time (ns). | UInt64 |
| span_attributes_response_time | Response time (ns). | UInt64 |
| span_attributes_server_time | Time spent on server processing (ns). | UInt64 |
| span_attributes_network_time | Total network time (ns). | UInt64 |
| span_attributes_frontend_time | Frontend processing time (ns). | UInt64 |
| span_attributes_load_time | Total page load time (ns). | UInt64 |
| span_attributes_processing_time | Application processing time (ns). | UInt64 |
| span_attributes_http_action_type | HTTP action performed (e.g., GET, POST). | String |
| span_attributes_longtask_name | Name of the long task. | String |
| span_attributes_longtask_duration | Duration of the long task (ns). | UInt64 |
| span_attributes_root_span_http_url | Root span's HTTP URL. | String |
| span_attributes_root_span_operation | Operation type of the root span. | String |
| span_attributes_event_type | Type of event (e.g., navigation, click). | String |
| span_attributes_http_longtasks_sum | Sum duration of long tasks in the span (ns). | UInt64 |
| span_attributes_new_location_href | Updated URL after navigation. | String |
| span_attributes_target_element | Target HTML element interacted with. | String |
| span_attributes_http_host | Host part of the HTTP URL. | String |
| span_attributes_http_method | HTTP method used in the request. | String |
| span_attributes_http_status_code | HTTP response status code. | UInt32 |
| span_attributes_http_time_in_xhr_calls | Time spent in XHR calls (ns). | UInt64 |
| span_attributes_http_time_to_first_xhr | Time until first XHR (ns). | UInt64 |
| span_attributes_http_time_to_last_xhr | Time until last XHR (ns). | UInt64 |
| span_attributes_http_time_to_xhr_processing_end | Time until end of XHR processing (ns). | UInt64 |
| span_attributes_cls | Cumulative Layout Shift score. | UInt64 |
| span_attributes_fp | First Paint timing (ns). | UInt64 |
| span_attributes_fcp | First Contentful Paint timing (ns). | UInt64 |
| span_attributes_ttfb | Time to First Byte (ns). | UInt64 |
| span_attributes_fid | First Input Delay (ns). | UInt64 |
| span_attributes_lcp | Largest Contentful Paint timing (ns). | UInt64 |
| span_attributes_http_client_ip | IP address of the client making the HTTP request. | String |
| country_name | Country of the client. | String |
| region_name | Region of the client. | String |
| city_name | City of the client. | String |
| timezone | Timezone of the client. | String |
| latitude | Latitude of the client’s location. | Float64 |
| longitude | Longitude of the client’s location. | Float64 |
| logs_attributes_error_message | A descriptive message of the error that occurred, typically from the client-side JavaScript runtime. This field contains the human-readable explanation of what went wrong. | String |
| logs_attributes_error_name | Represents the type or name of the error encountered on the client, such as TypeError, ReferenceError, SyntaxError, etc. | String |
| logs_attributes_error_stack | Contains the full stack trace associated with the error message, including function names, line numbers, and file locations. | String |
| message | General message field from logs, which may overlap with logs_attributes_error_message but could also contain other structured log messages. | String |
