React
Instrument your React application with OpenTelemetry to send traces, metrics, and logs to Last9
Use OpenTelemetry to instrument your React application and send telemetry data to Last9.
Installation
-
Install OpenTelemetry packages
Install the following packages:
npm install \@opentelemetry/api@1.9.0 \@opentelemetry/context-zone@2.1.0 \@opentelemetry/exporter-trace-otlp-http@0.205.0 \@opentelemetry/instrumentation@0.205.0 \@opentelemetry/instrumentation-document-load@0.51.2 \@opentelemetry/instrumentation-fetch@0.205.0 \@opentelemetry/instrumentation-user-interaction@0.51.2 \@opentelemetry/resources@2.1.0 \@opentelemetry/sdk-trace-base@2.1.0 \@opentelemetry/sdk-trace-web@2.1.0 \@opentelemetry/semantic-conventions@1.37.0
Setup
RUM Endpoint URL
The Last9 endpoint URL follows this format:
{{ .Traces.WriteExternalURL }}/v1/otlp/organizations/{{ .Org.Slug }}/telemetry/client_monitoring/v1/tracesAuthentication
Create a client token for browser applications:
- Navigate to Ingestion Tokens in Last9 dashboard
- Create separate client tokens for development and production environments
- Development token: restricted to
localhostorigins (e.g., localhost:3000) - Production token: restricted to your production domain(s)
- Development token: restricted to
Environment Variables
Set the environment variables:
REACT_APP_OTEL_SERVICE_NAME=your-app-nameREACT_APP_OTEL_ENDPOINT={{ .Traces.WriteExternalURL }}/v1/otlp/organizations/{{ .Org.Slug }}/telemetry/client_monitoring/v1/tracesREACT_APP_OTEL_API_TOKEN=your-client-token-hereREACT_APP_OTEL_ORIGIN=your-otel-token-originREACT_APP_OTEL_ENVIRONMENT=developmentImplementation
Create Telemetry Setup
Create a file named telemetry.ts:
import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";import { registerInstrumentations } from "@opentelemetry/instrumentation";import { ZoneContextManager } from "@opentelemetry/context-zone";import { FetchInstrumentation } from "@opentelemetry/instrumentation-fetch";import { DocumentLoadInstrumentation } from "@opentelemetry/instrumentation-document-load";import { UserInteractionInstrumentation } from "@opentelemetry/instrumentation-user-interaction";import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";import { resourceFromAttributes } from "@opentelemetry/resources";import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";
// Generate or retrieve browser fingerprint (Client-ID)const getClientId = (): string => { const STORAGE_KEY = "last9_client_id"; let clientId = localStorage.getItem(STORAGE_KEY);
if (!clientId) { // Generate a simple UUID-like identifier clientId = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { const r = (Math.random() * 16) | 0; const v = c === "x" ? r : (r & 0x3) | 0x8; return v.toString(16); }); localStorage.setItem(STORAGE_KEY, clientId); }
return clientId;};
// Configuration from environment variablesconst OTEL_CONFIG = { serviceName: process.env.REACT_APP_OTEL_SERVICE_NAME, endpoint: process.env.REACT_APP_OTEL_ENDPOINT, apiToken: process.env.REACT_APP_OTEL_API_TOKEN, origin: process.env.REACT_APP_OTEL_ORIGIN || window.location.origin, environment: process.env.REACT_APP_OTEL_ENVIRONMENT,};
export const setupTelemetry = () => { console.log("[OpenTelemetry] Initializing OpenTelemetry for React App...");
// Validate required configuration if ( !OTEL_CONFIG.serviceName || !OTEL_CONFIG.endpoint || !OTEL_CONFIG.apiToken ) { console.error( "[OpenTelemetry Error] Missing required OpenTelemetry configuration", ); console.error( " Required: REACT_APP_OTEL_SERVICE_NAME, REACT_APP_OTEL_ENDPOINT, REACT_APP_OTEL_API_TOKEN", ); return; }
// Create resource with service information const resource = resourceFromAttributes({ [SemanticResourceAttributes.SERVICE_NAME]: OTEL_CONFIG.serviceName, [SemanticResourceAttributes.SERVICE_VERSION]: "1.0.0", // change this as needed [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: OTEL_CONFIG.environment, });
// Get or generate Client-ID (browser fingerprint) const clientId = getClientId();
// Configure OTLP exporter with Last9 Client Monitoring headers const otlpExporter = new OTLPTraceExporter({ url: OTEL_CONFIG.endpoint, headers: { "X-LAST9-API-TOKEN": `Bearer ${OTEL_CONFIG.apiToken}`, "Client-ID": clientId, "X-LAST9-ORIGIN": OTEL_CONFIG.origin, }, });
// Add span processor const spanProcessor = new BatchSpanProcessor(otlpExporter, { maxExportBatchSize: 512, exportTimeoutMillis: 30000, scheduledDelayMillis: 5000, });
// Create tracer provider with span processor const provider = new WebTracerProvider({ resource, spanProcessors: [spanProcessor], });
// Register the provider with Zone context manager for async operations provider.register({ contextManager: new ZoneContextManager(), });
// Register auto-instrumentations registerInstrumentations({ instrumentations: [ new DocumentLoadInstrumentation({ enabled: true }), new FetchInstrumentation({ enabled: true, propagateTraceHeaderCorsUrls: [/.+/g], clearTimingResources: true, ignoreUrls: [/otlp.*\.last9\.io/], }), new UserInteractionInstrumentation({ enabled: true, eventNames: ["click", "submit"], }), ], });
console.log("[OpenTelemetry] OpenTelemetry initialized successfully"); console.log(`[OpenTelemetry] Service: ${OTEL_CONFIG.serviceName}`); console.log(`[OpenTelemetry] Environment: ${OTEL_CONFIG.environment}`);
return provider;};
export default setupTelemetry;Create a file named telemetry.js:
const { WebTracerProvider } = require("@opentelemetry/sdk-trace-web");const { registerInstrumentations } = require("@opentelemetry/instrumentation");const { ZoneContextManager } = require("@opentelemetry/context-zone");const { FetchInstrumentation,} = require("@opentelemetry/instrumentation-fetch");const { DocumentLoadInstrumentation,} = require("@opentelemetry/instrumentation-document-load");const { UserInteractionInstrumentation,} = require("@opentelemetry/instrumentation-user-interaction");const { BatchSpanProcessor } = require("@opentelemetry/sdk-trace-base");const { OTLPTraceExporter,} = require("@opentelemetry/exporter-trace-otlp-http");const { resourceFromAttributes } = require("@opentelemetry/resources");const { SemanticResourceAttributes,} = require("@opentelemetry/semantic-conventions");
// Generate or retrieve browser fingerprint (Client-ID)const getClientId = () => { const STORAGE_KEY = "last9_client_id"; let clientId = localStorage.getItem(STORAGE_KEY);
if (!clientId) { // Generate a simple UUID-like identifier clientId = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { const r = (Math.random() * 16) | 0; const v = c === "x" ? r : (r & 0x3) | 0x8; return v.toString(16); }); localStorage.setItem(STORAGE_KEY, clientId); }
return clientId;};
// Configuration from environment variablesconst OTEL_CONFIG = { serviceName: process.env.REACT_APP_OTEL_SERVICE_NAME, endpoint: process.env.REACT_APP_OTEL_ENDPOINT, apiToken: process.env.REACT_APP_OTEL_API_TOKEN, origin: process.env.REACT_APP_OTEL_ORIGIN || window.location.origin, environment: process.env.REACT_APP_OTEL_ENVIRONMENT,};
const setupTelemetry = () => { console.log("[OpenTelemetry] Initializing OpenTelemetry for React App...");
// Validate required configuration if ( !OTEL_CONFIG.serviceName || !OTEL_CONFIG.endpoint || !OTEL_CONFIG.apiToken ) { console.error( "[OpenTelemetry Error] Missing required OpenTelemetry configuration", ); console.error( " Required: REACT_APP_OTEL_SERVICE_NAME, REACT_APP_OTEL_ENDPOINT, REACT_APP_OTEL_API_TOKEN", ); return; }
// Create resource with service information const resource = resourceFromAttributes({ [SemanticResourceAttributes.SERVICE_NAME]: OTEL_CONFIG.serviceName, [SemanticResourceAttributes.SERVICE_VERSION]: "1.0.0", // change this as needed [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: OTEL_CONFIG.environment, });
// Get or generate Client-ID (browser fingerprint) const clientId = getClientId();
// Configure OTLP exporter with Last9 Client Monitoring headers const otlpExporter = new OTLPTraceExporter({ url: OTEL_CONFIG.endpoint, headers: { "X-LAST9-API-TOKEN": `Bearer ${OTEL_CONFIG.apiToken}`, "Client-ID": clientId, "X-LAST9-ORIGIN": OTEL_CONFIG.origin, }, });
// Add span processor const spanProcessor = new BatchSpanProcessor(otlpExporter, { maxExportBatchSize: 512, exportTimeoutMillis: 30000, scheduledDelayMillis: 5000, });
// Create tracer provider with span processor const provider = new WebTracerProvider({ resource, spanProcessors: [spanProcessor], });
// Register the provider with Zone context manager for async operations provider.register({ contextManager: new ZoneContextManager(), });
// Register auto-instrumentations registerInstrumentations({ instrumentations: [ new DocumentLoadInstrumentation({ enabled: true }), new FetchInstrumentation({ enabled: true, propagateTraceHeaderCorsUrls: [/.+/g], clearTimingResources: true, ignoreUrls: [/otlp.*\.last9\.io/], }), new UserInteractionInstrumentation({ enabled: true, eventNames: ["click", "submit"], }), ], });
console.log("[OpenTelemetry] OpenTelemetry initialized successfully"); console.log(`[OpenTelemetry] Service: ${OTEL_CONFIG.serviceName}`); console.log(`[OpenTelemetry] Environment: ${OTEL_CONFIG.environment}`);
return provider;};
module.exports = { setupTelemetry };Initialize in Your App
Import the telemetry setup at your application’s entry point before importing React:
In your index.tsx:
// Initialize OpenTelemetry BEFORE importing Reactimport { setupTelemetry } from './telemetry';import React from 'react';import ReactDOM from 'react-dom/client';import './index.css';import App from './App';
// Setup telemetrysetupTelemetry();
const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement);root.render( <React.StrictMode> <App /> </React.StrictMode>);In your index.js:
// Initialize OpenTelemetry BEFORE importing Reactconst { setupTelemetry } = require("./telemetry");const React = require("react");const ReactDOM = require("react-dom/client");
// Setup telemetrysetupTelemetry();
// Rest of your React app initializationWhat Gets Instrumented
The setup automatically captures:
- Document Load Performance - Page load times and resource timings
- Fetch Requests - HTTP requests made by your application
- User Interactions - Click and submit events
- Navigation - Route changes and page transitions
Features
- Automatic client ID generation - Unique browser fingerprint for session tracking
- Environment-based configuration - Different tokens for dev/prod environments
- CORS-enabled tracing - Propagates trace headers across domains
- Performance optimized - Batched exports and configurable timing
- Error handling - Graceful degradation if configuration is missing
Notes
Once you run the React application, it will start sending telemetry data to Last9.