OpenTelemetry Browser SDK for Uptrace
This guide explains how to configure the OpenTelemetry JavaScript SDK for web browsers to export spans and metrics to Uptrace using OTLP/HTTP. You'll learn how to instrument your web applications for effective client-side monitoring and observability.
If you need to monitor JavaScript web applications, using Sentry SDK instead of OpenTelemetry JS might provide better results for error tracking and user experience monitoring.
To learn about the OpenTelemetry API, see OpenTelemetry JS Tracing API and OpenTelemetry JS Metrics API.
Prerequisites
Before you begin, ensure you have:
- A web application running in modern browsers (supporting ES2022)
- An Uptrace account with a valid DSN (Data Source Name)
- A build system that supports ES6 modules (Webpack, Vite, Rollup, etc.)
Uptrace Web SDK
uptrace-js is a lightweight wrapper around opentelemetry-js that pre-configures the OpenTelemetry SDK to export data to Uptrace. It doesn't add new functionality but simplifies the setup process for your convenience.
Installation
To install @uptrace/web:
# npm npm install @uptrace/web --save-dev # yarn yarn add @uptrace/web --dev Configuration
Configure the Uptrace client using a DSN (Data Source Name) from your project settings page. Replace <FIXME> with your actual Uptrace DSN.
You must call configureOpentelemetry as early as possible and before importing other packages, because the OpenTelemetry SDK must patch libraries before you import them.
import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web' import { configureOpentelemetry } from '@uptrace/web' // configureOpentelemetry automatically sets up window.onerror handler. const sdk = configureOpentelemetry({ // Set dsn or UPTRACE_DSN env var. dsn: '<FIXME>', serviceName: 'myservice', serviceVersion: '1.0.0', instrumentations: [getWebAutoInstrumentations({})], }) sdk.start() You can use the following options to configure Uptrace client.
| Option | Description |
|---|---|
dsn | A data source that is used to connect to uptrace.dev. For example, https://<token>@uptrace.dev/<project_id>. |
serviceName | service.name resource attribute. For example, myservice. |
serviceVersion | service.version resource attribute. For example, 1.0.0. |
deploymentEnvironment | deployment.environment resource attribute. For example, production. |
resourceAttributes | Any other resource attributes. |
resource | Resource contains attributes representing an entity that produces telemetry. Resource attributes are copied to all spans and events. |
Context Manager
ZoneContextManager is a context manager implementation based on the Zone.js library. It enables context propagation within the application using zones, which is particularly useful for tracking asynchronous operations in browsers.
Installation
To install the Zone.js context manager:
npm install --save @opentelemetry/context-zone Usage
To use the Zone.js context manager:
import { ZoneContextManager } from '@opentelemetry/context-zone' configureOpentelemetry({ contextManager: new ZoneContextManager(), }) Benefits of Zone.js context manager:
- Automatic context propagation across async operations
- Better trace correlation for setTimeout, Promise chains, and event handlers
- Improved debugging capabilities for complex web applications
Instrumentations
OpenTelemetry provides several instrumentations specifically designed for browser environments to automatically capture telemetry data from common web APIs and user interactions.
Available Instrumentations
- Fetch API: Automatically instruments
fetch()requests - XMLHttpRequest: Instruments traditional AJAX requests
- Document Load: Monitors page load performance
For additional instrumentations, see the OpenTelemetry JS web plugins documentation.
Basic Setup
You can use configureOpentelemetry to register individual instrumentations:
import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch' import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request' const sdk = configureOpentelemetry({ instrumentations: [ new FetchInstrumentation(), new XMLHttpRequestInstrumentation(), ], }) sdk.start() To automatically register all available web instrumentations:
import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web' const sdk = configureOpentelemetry({ instrumentations: [getWebAutoInstrumentations({})], }) sdk.start() Alternative Method
You can also use registerInstrumentations directly:
import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch' import { registerInstrumentations } from '@opentelemetry/instrumentation' registerInstrumentations({ instrumentations: [new FetchInstrumentation()], }) See the OpenTelemetry JS web plugins for the full list of available instrumentations.
Advanced Configuration
Configure instrumentations with custom options:
import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch' configureOpentelemetry({ instrumentations: [ new FetchInstrumentation({ // Ignore requests to specific URLs ignoreUrls: [/\/analytics/, /\/tracking/], // Add custom attributes requestHook: (span, request) => { span.setAttribute('custom.request.type', 'api') }, }), ], }) Framework Integrations
Instrumenting Vue.js 2.x
Integrate OpenTelemetry with Vue.js applications for comprehensive error tracking:
import Vue from 'vue' import { configureOpentelemetry } from '@uptrace/web' const sdk = configureOpentelemetry({ dsn: '<FIXME>', }) sdk.start() Vue.config.errorHandler = (err, vm, info) => { sdk.reportException(err, { vm: vm, info: info, }) } Instrumenting React
For React applications, you can set up error tracking with OpenTelemetry:
import React from 'react' import { configureOpentelemetry } from '@uptrace/web' import { trace } from '@opentelemetry/api' const sdk = configureOpentelemetry({ dsn: '<FIXME>', }) sdk.start() const tracer = trace.getTracer('react-app', '1.0.0') class ErrorBoundary extends React.Component { constructor(props) { super(props) this.state = { hasError: false } } static getDerivedStateFromError(error) { return { hasError: true } } componentDidCatch(error, errorInfo) { const span = tracer.startSpan('react.error') span.recordException(error) span.setAttributes({ 'error.component': errorInfo.componentStack, }) span.end() } render() { if (this.state.hasError) { return <h1>Something went wrong.</h1> } return this.props.children } } Manual Instrumentation
Create custom spans for specific user interactions or business logic:
import { trace } from '@opentelemetry/api' const tracer = trace.getTracer('web-app', '1.0.0') function trackUserAction(actionName) { const span = tracer.startSpan(`user.${actionName}`) span.setAttributes({ 'user.action': actionName, 'page.url': window.location.href, 'user.agent': navigator.userAgent, }) // Your business logic here span.end() } // Usage document.getElementById('submit-button').addEventListener('click', () => { trackUserAction('form_submit') }) Performance Monitoring
Monitor key performance metrics in your web application:
import { trace, metrics } from '@opentelemetry/api' const tracer = trace.getTracer('web-performance', '1.0.0') const meter = metrics.getMeter('web-performance', '1.0.0') // Create metrics const pageLoadTime = meter.createHistogram('page.load_time', { description: 'Page load time in milliseconds', }) // Measure page load time window.addEventListener('load', () => { const loadTime = performance.timing.loadEventEnd - performance.timing.navigationStart pageLoadTime.record(loadTime, { 'page.url': window.location.pathname, }) }) Querying Data
Once your browser application is instrumented and sending data to Uptrace, you can analyze user behavior and performance:
Browser-Specific Span Analysis
- Network requests: Monitor API calls, resource loading, and external service dependencies
- User interactions: Track clicks, form submissions, and navigation patterns
- Performance bottlenecks: Identify slow-loading resources and long-running JavaScript tasks
- Error tracking: Analyze client-side errors and their impact on user experience
Client-Side Metrics
- Page load metrics: Monitor loading performance and user experience
- User engagement: Track session duration, page views, and interaction patterns
- Resource performance: Analyze loading times for various assets
- Error rates: Monitor client-side error frequency and patterns
Cross-Platform Correlation
- Full-stack tracing: Correlate browser spans with backend API calls
- User journey tracking: Follow user interactions across multiple pages and services
- Error propagation: Track how client-side errors relate to server-side issues
Verifying Your Setup
After configuration, your browser application will start sending telemetry data to Uptrace. To verify the setup:
- Load your application in a browser with developer tools open
- Interact with your application by clicking buttons, making requests, or navigating between pages
- Check the Network tab for requests to
https://api.uptrace.dev/v1/traces - View traces in Uptrace within 1-2 minutes of generating activity
Troubleshooting
If OpenTelemetry is not working as expected, you can enable verbose logging to check for potential issues:
import { diag, DiagConsoleLogger, DiagLogLevel } from '@opentelemetry/api' diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG) Browser-Specific Issues
CORS errors:
- Ensure your Uptrace project allows requests from your domain
- Check that the browser is not blocking requests due to CORS policy
- Verify that your DSN is correctly configured
Bundle size concerns:
- Use tree-shaking to include only necessary OpenTelemetry packages
- Consider lazy-loading instrumentation for non-critical paths
- Monitor the impact on your application's bundle size
Performance impact:
- Configure appropriate sampling rates to reduce overhead
- Use batch processors to minimize network requests
- Test performance impact in production-like environments
Ad blockers:
- Some ad blockers may interfere with telemetry data collection
- Consider using a custom subdomain for telemetry endpoints
- Provide fallback mechanisms for when telemetry is blocked
What's Next?
Next, instrument more operations to get a more detailed picture. Try to prioritize network calls, disk operations, database queries, errors, and logs.