Skip to main content

JavaScript Browser

This guide provides instructions for setting up custom instrumentation for JavaScript browser applications using the OpenTelemetry JavaScript SDK.

Building with React or Next.js?

You do not need manual instrumentation. @base-14/scout-react ships zero-config browser RUM that captures clicks, route changes, fetch and XHR calls, errors, Core Web Vitals, and long tasks with a single Scout.initialize() call. See the React guide or the Next.js guide.

Use this guide for vanilla JavaScript, or when you need control over exactly which spans are produced.

Running this in production

Storing and querying these sessions at production volume is what base14 Scout does. Check out Scout RUM.

Overview

This guide demonstrates how to:

  • Set up OpenTelemetry custom instrumentation for JavaScript browser applications
  • Export telemetry data to Scout

Note: Auto instrumentation does not support metrics. To collect meaningful metrics, you need to implement them manually.

Prerequisites

  • Node.js 16+
  • JavaScript browser application setup
  • Scout Collector setup

Required Packages

Install the following packages:

npm install @opentelemetry/api
npm install @opentelemetry/sdk-trace-web
npm install @opentelemetry/sdk-metrics
npm install @opentelemetry/sdk-logs
npm install @opentelemetry/context-zone
npm install @opentelemetry/exporter-trace-otlp-http
npm install @opentelemetry/exporter-metrics-otlp-http
npm install @opentelemetry/resources

Custom Instrumentation Setup (telemetry.js)

// src/telemetry.js
import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { Resource } from "@opentelemetry/resources";
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";
import { ZoneContextManager } from "@opentelemetry/context-zone";
import {
MeterProvider,
PeriodicExportingMetricReader,
} from "@opentelemetry/sdk-metrics";
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
import {
LoggerProvider,
SimpleLogRecordProcessor,
} from "@opentelemetry/sdk-logs";
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
import * as logsAPI from "@opentelemetry/api-logs";
import * as api from "@opentelemetry/api";
import { ZoneContextManager } from "@opentelemetry/context-zone";

export const setupTelemetry = () => {
const resource = new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: "react-service",
[SemanticResourceAttributes.SERVICE_VERSION]: "1.0.0",
});

// Trace setup
const traceExporter = new OTLPTraceExporter({
url: "http://<scout-collector-endpoint>:4318/v1/traces",
});
const traceProvider = new WebTracerProvider({ resource });
traceProvider.addSpanProcessor(new BatchSpanProcessor(traceExporter));
traceProvider.register({ contextManager: new ZoneContextManager() });

// Metric setup
const metricExporter = new OTLPMetricExporter({
url: "http://<scout-collector-endpoint>:4318/v1/metrics",
});
const meterProvider = new MeterProvider({
resource,
readers: [
new PeriodicExportingMetricReader({
exporter: metricExporter,
exportIntervalMillis: 10000,
}),
],
});

api.metrics.setGlobalMeterProvider(meterProvider);

// Log setup
const logExporter = new OTLPLogExporter({
url: "http://<scout-collector-endpoint>:4318/v1/logs",
});
const loggerProvider = new LoggerProvider({
resource,
processors: [new SimpleLogRecordProcessor(logExporter)],
});
logsAPI.logs.setGlobalLoggerProvider(loggerProvider);
};

Initialize in index.js

// src/index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { setupTelemetry } from "./telemetry";

setupTelemetry();

ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root"),
);

Custom Tracing Example

import { trace } from "@opentelemetry/api";

async function checkServiceHealth() {
// Get the tracer from the global tracer provider set in the setupTelemetry function
const tracer = trace.getTracer("health-service");
const span = tracer.startSpan("checkServiceHealth");

try {
span.setAttribute("health.check", "ping");
const res = await fetch("/ping");
const data = await res.json();
return data;
} catch (error) {
// handle error
throw error;
} finally {
span.end();
}
}

Custom Metrics Example

import { metrics } from "@opentelemetry/api";
// Gets the meter from the global meter provider set in the setupTelemetry function
const meter = metrics.getMeter("react-app");
const renderCount = meter.createCounter("component.render.count");

function TrackedComponent() {
useEffect(() => {
renderCount.add(1, { component: "TrackedComponent" });
}, []);

return <div>Tracked!</div>;
}

Configuration

CORS Headers for Otel Collector

Add the following CORS headers to the Otel Collector configuration:

receivers:
otlp:
protocols:
http:
endpoint: 0.0.0.0:4318
cors:
allowed_origins:
- "https://example.com"

View these traces in Scout dashboards.

References

Sample react application with OTel instrumentation

Was this page helpful?