Skip to content
Last9 named a Gartner Cool Vendor in AI for SRE Observability for 2025! Read more →
Last9

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

  1. 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/traces

Authentication

Create a client token for browser applications:

  1. Navigate to Ingestion Tokens in Last9 dashboard
  2. Create separate client tokens for development and production environments
    • Development token: restricted to localhost origins (e.g., localhost:3000)
    • Production token: restricted to your production domain(s)

Environment Variables

Set the environment variables:

REACT_APP_OTEL_SERVICE_NAME=your-app-name
REACT_APP_OTEL_ENDPOINT={{ .Traces.WriteExternalURL }}/v1/otlp/organizations/{{ .Org.Slug }}/telemetry/client_monitoring/v1/traces
REACT_APP_OTEL_API_TOKEN=your-client-token-here
REACT_APP_OTEL_ORIGIN=your-otel-token-origin
REACT_APP_OTEL_ENVIRONMENT=development

Implementation

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 variables
const 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;

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 React
import { setupTelemetry } from './telemetry';
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
// Setup telemetry
setupTelemetry();
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);

What Gets Instrumented

The setup automatically captures:

  1. Document Load Performance - Page load times and resource timings
  2. Fetch Requests - HTTP requests made by your application
  3. User Interactions - Click and submit events
  4. 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.