
This guide helps you set up and send OpenTelemetry telemetry to Statsig so you can use Infra Analytics (Logs Explorer, Metrics Explorer, Alerts).

There are two common paths:

* Kubernetes/OpenTelemetry Collector: scrape logs and metrics from your cluster and export to Statsig. Go to [Open Telemetry Logs and Metrics](/server/concepts/open_telemetry) for a more complete guide.
* Applications: export traces, metrics, and logs to your OpenTelemetry Collector (or traces directly from TypeScript/Node). Go to the quick starts below.

{% callout type="info" %}
**Endpoint & Auth**

* Endpoint: `https://api.statsig.com/otlp`
* Auth header: `statsig-api-key: <your Server SDK Secret key>`
{% /callout %}

{% callout type="info" %}
Direct trace export to the Statsig OTLP endpoint is only available for TypeScript/Node. For all other languages, send traces to your OpenTelemetry Collector and forward from the Collector to Statsig over OTLP/HTTP.
{% /callout %}

{% callout type="info" %}
Need a deeper setup guide? Go to [Open Telemetry Logs and Metrics](/server/concepts/open_telemetry) for collector installation and configuration, and the [Traces Explorer quick start](/infra-analytics/send-traces) for language-specific trace examples.
{% /callout %}

***

## Application Telemetry quick starts

{% tabs %}
{% tab title="Node.js" %}
Install dependencies:

```bash
npm install --save \
  @opentelemetry/sdk-node \
  @opentelemetry/auto-instrumentations-node \
  @opentelemetry/exporter-trace-otlp-http \
  @opentelemetry/exporter-metrics-otlp-http \
  @opentelemetry/api-logs \
  @opentelemetry/sdk-logs \
  @opentelemetry/exporter-logs-otlp-http \
  @opentelemetry/resources \
  @opentelemetry/semantic-conventions
```

Initialize OpenTelemetry (e.g., `instrumentation.js`):

```js
// instrumentation.js
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { resourceFromAttributes } = require('@opentelemetry/resources');
const { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } = require('@opentelemetry/semantic-conventions');

// import if you want to enable traces
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');
const { OTLPMetricExporter } = require('@opentelemetry/exporter-metrics-otlp-http');
const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');

// For troubleshooting, set the log level to DiagLogLevel.DEBUG
// const { diag, DiagConsoleLogger, DiagLogLevel } = require('@opentelemetry/api');
// diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG);

const statsigKey = process.env.STATSIG_SERVER_SDK_SECRET;
const headers = { 'statsig-api-key': statsigKey ?? '' };

const sdk = new NodeSDK({
  resource: resourceFromAttributes({
    [ATTR_SERVICE_NAME]: process.env.OTEL_SERVICE_NAME || 'statsig-node-service',
    [ATTR_SERVICE_VERSION]: process.env.VERSION || '1',
    env: process.env.NODE_ENV || 'development',
  }),
  traceExporter: new OTLPTraceExporter({
   url: 'https://api.statsig.com/otlp/v1/traces',
   // or
   // url: <your-collector-endpoint>/v1/traces
   headers,
  }),
  metricReader: new PeriodicExportingMetricReader({
    exporter: new OTLPMetricExporter({
      url: 'https://api.statsig.com/otlp/v1/metrics',
      // or
      // url: <your-collector-endpoint>/v1/metrics
      headers,
    }),
    exportIntervalMillis: 60000,
  }),
  instrumentations: [getNodeAutoInstrumentations()],
});

sdk.start();

```

To set up application logs with OTel, use the pino or winston bridges. The example below uses [pino](https://getpino.io/#/) with
[pino auto instrumentation](https://www.npmjs.com/package/@opentelemetry/instrumentation-pino).

Install the pino instrumentation:

```bash
npm i pino @opentelemetry/instrumentation-pino
```

```js
// instrumentation.js (continued)
const { BatchLogRecordProcessor } = require('@opentelemetry/sdk-logs');

const statsigKey = process.env.STATSIG_SERVER_SDK_SECRET;
const headers = { 'statsig-api-key': statsigKey ?? '' };

const sdk = new NodeSDK({
  // ... other config ...
  logRecordProcessors: [
    new BatchLogRecordProcessor(
      new OTLPLogExporter({
        url: 'https://api.statsig.com/otlp/v1/logs',
        // or
        // url: <your-collector-endpoint>/v1/logs
        headers
      })
    ),
  ],
  instrumentations: [getNodeAutoInstrumentations(), new PinoInstrumentation()],
});


// in your application code, e.g., app.js
const pino = require('pino');

const logger = pino();

logger.info('OTel logs initialized');
```

The Statsig SDK also supports forwarding logs to Log Explorer. Go to the alternative logging example below.

```js
// Requires: npm i @statsig/statsig-node-core
const { Statsig, StatsigUser } = require('@statsig/statsig-node-core');

const s = new Statsig(process.env.STATSIG_SERVER_SDK_SECRET);
await s.initialize();

const user = new StatsigUser({
  userID: 'a-user',
  custom: { service: process.env.OTEL_SERVICE_NAME || 'my-node-service' },
});

// levels: trace, debug, info, log, warn, error
s.forwardLogLineEvent(user, 'info', 'service started', { version: process.env.npm_package_version });

 try {
   // your app code
 } catch (err) {
   s.forwardLogLineEvent(user, 'error', 'unhandled error', {
     message: String(err?.message || err),
     stack: err?.stack,
   });
 }

```

Run your service:

Require or import `instrumentation.js` before any other application code to ensure instrumentation sets up correctly.

```bash
STATSIG_SERVER_SDK_SECRET=YOUR_SECRET \
OTEL_SERVICE_NAME=my-node-service \
node -r ./instrumentation.js app.js
```

Tip: you can configure exporters through environment variables instead of code:

* `OTEL_EXPORTER_OTLP_ENDPOINT=https://api.statsig.com/otlp`
* `OTEL_EXPORTER_OTLP_HEADERS=statsig-api-key=${STATSIG_SERVER_SDK_SECRET}`
* `OTEL_EXPORTER_OTLP_PROTOCOL=http/json`
{% /tab %}

{% tab title="Next.js" %}
Go to the official Next.js OpenTelemetry instructions for [pages router](https://nextjs.org/docs/pages/guides/open-telemetry) and for [app router](https://nextjs.org/docs/app/guides/open-telemetry).

Install dependencies:

```bash
npm install @opentelemetry/sdk-node @opentelemetry/resources @opentelemetry/semantic-conventions @opentelemetry/sdk-trace-node @opentelemetry/exporter-trace-otlp-http @opentelemetry/auto-instrumentations-node
```

Add `instrumentation.ts` at the app root (Next 13+):

```ts
// instrumentation.ts
import { NodeSDK } from '@opentelemetry/sdk-node';
import { resourceFromAttributes } from '@opentelemetry/resources';
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';

// For troubleshooting, set the log level to DiagLogLevel.DEBUG
// const { diag, DiagConsoleLogger, DiagLogLevel } = require('@opentelemetry/api');
// diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG);

export async function register() {
  const headers = { 'statsig-api-key': process.env.STATSIG_SERVER_SDK_SECRET ?? '' };

  const sdk = new NodeSDK({
    resource: new Resource({
      [ATTR_SERVICE_NAME]: process.env.OTEL_SERVICE_NAME || 'statsig-node-service',
      [ATTR_SERVICE_VERSION]: process.env.VERSION || '1',
      env: process.env.NODE_ENV || 'development',
    }),
    traceExporter: new OTLPTraceExporter({
     url: 'https://api.statsig.com/otlp/v1/traces',
    // or
    // url: <your-collector-endpoint>/v1/traces
     headers,
    }),
    metricReader: new PeriodicExportingMetricReader({
      exporter: new OTLPMetricExporter({
        url: 'https://api.statsig.com/otlp/v1/metrics',
        // or
        // url: <your-collector-endpoint>/v1/metrics
        headers,
      }),
      exportIntervalMillis: 60000,
    }),
    instrumentations: [getNodeAutoInstrumentations()],
  });

  sdk.start();
}
```

To set up application logs with OTel, use the pino or winston bridges. The example below uses [Pino](https://getpino.io/#/) with
[Pino auto instrumentation](https://www.npmjs.com/package/@opentelemetry/instrumentation-pino).

Install the pino instrumentation:

```bash
npm i pino @opentelemetry/instrumentation-pino
```

```js
// instrumentation.ts (continued)
import { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';

const statsigKey = process.env.STATSIG_SERVER_SDK_SECRET;
const headers = { 'statsig-api-key': statsigKey ?? '' };

const sdk = new NodeSDK({
  // ... other config ...
  logRecordProcessors: [
    new BatchLogRecordProcessor(
      new OTLPLogExporter({
        url: 'https://api.statsig.com/otlp/v1/logs',
        // or
        // url: <your-collector-endpoint>/v1/logs
        headers
      })
    ),
  ],
  instrumentations: [getNodeAutoInstrumentations(), new PinoInstrumentation()],
});


// in your application code, e.g., app.ts
import pino from 'pino';

const logger = pino();

logger.info('OTel logs initialized');
```

The Statsig SDK also supports forwarding logs to Log Explorer. Go to the alternative logging example below.

```js
// Requires: npm i @statsig/statsig-node-core
import { Statsig, StatsigUser } from '@statsig/statsig-node-core';

const s = new Statsig(process.env.STATSIG_SERVER_SDK_SECRET);
await s.initialize();

const user = new StatsigUser({
  userID: 'a-user',
  custom: { service: process.env.OTEL_SERVICE_NAME || 'my-node-service' },
});

// levels: trace, debug, info, log, warn, error
s.forwardLogLineEvent(user, 'info', 'service started', { version: process.env.npm_package_version });

 try {
   // your app code
 } catch (err) {
   s.forwardLogLineEvent(user, 'error', 'unhandled error', {
     message: String(err?.message || err),
     stack: err?.stack,
   });
 }
```

{% callout type="note" %}
In Next.js, mark '@statsig/statsig-node-core' as a server external package in `next.config.js` to avoid bundling.
{% /callout %}

### Using the Statsig + Vercel integration

If you deploy to Vercel, use the [Statsig + Vercel integration](/integrations/vercel/) to forward logs to Statsig automatically.

{% callout type="note" %}
* Keep `STATSIG_SERVER_SDK_SECRET` out of client bundles (do not use `NEXT_PUBLIC_`).
* Client/browser tracing requires separate web tracer setup; do not send secrets client-side. Consider routing through a Collector.
{% /callout %}
{% /tab %}

{% tab title="Other Languages/Frameworks" %}
Sending OTLP data directly to Statsig without a collector is only supported for Node.js applications. For other languages and frameworks, send OTLP data to a collector and configure the collector to forward data to Statsig.

Go to the [Collector quick starts](#collector-quick-starts) below for example configurations. For installation and configuration instructions for other languages and frameworks, go to the [OpenTelemetry Language APIs & SDKs documentation](https://opentelemetry.io/docs/languages/).
{% /tab %}
{% /tabs %}

***

## Collector quick starts

Running a Collector is optional but recommended for production workloads.

Use the OpenTelemetry Collector as a gateway to receive OTLP from your applications and forward to Statsig. This is useful for centralizing telemetry collection, adding advanced sampling methods like tail-based sampling, or scraping logs and metrics from hosts or Kubernetes.

{% tabs %}
{% tab title="Kubernetes (Helm)" %}
Create a minimal `values.yaml` for the OpenTelemetry Collector that forwards all signals (traces, metrics, logs) to Statsig:

```yaml title="values.yaml"
config:
  receivers:
    otlp:
      protocols:
        http:
        grpc:

  processors:
    batch: {}

  exporters:
    otlphttp:
      endpoint: https://api.statsig.com/otlp
      encoding:  json
      headers:
        statsig-api-key: ${env:STATSIG_SERVER_SDK_SECRET}

  service:
    pipelines:
      traces:
        receivers: [otlp]
        processors: [batch]
        exporters: [otlphttp]
      metrics:
        receivers: [otlp]
        processors: [batch]
        exporters: [otlphttp]
      logs:
        receivers: [otlp]
        processors: [batch]
        exporters: [otlphttp]
```

Install the Collector with Helm:

```bash
helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts
helm repo update
helm install otel-gateway open-telemetry/opentelemetry-collector \
  -n otel --create-namespace \
  -f values.yaml
```

Provide the Statsig key as an environment variable to the Collector pods (for example, through a Secret and envFrom). Your applications then send OTLP to the in-cluster Collector endpoint (for example `http://otel-gateway-collector.otel.svc.cluster.local:4318`).

For a production setup that also scrapes Kubernetes logs and metrics, go to the full guide: [Open Telemetry Logs and Metrics](/server/concepts/open_telemetry).

{% callout type="note" %}
**Version requirement**

The `encoding: json` option in the OTLP HTTP exporter requires Collector v0.95.0 or newer. If you pin the image through Helm values, set `image.tag: "0.95.0"` (or newer).
{% /callout %}
{% /tab %}

{% tab title="Docker (Compose)" %}
Use Docker Compose to run a Collector gateway that accepts OTLP and forwards to Statsig.

```yaml title="docker-compose.yaml"
services:
  otel-collector:
    image: otel/opentelemetry-collector-contrib:latest
    command: ["--config=/etc/otel-collector-config.yaml"]
    environment:
      - STATSIG_SERVER_SDK_SECRET=${STATSIG_SERVER_SDK_SECRET}
    volumes:
      - ./otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml
    ports:
      - "4317:4317"   # OTLP gRPC
      - "4318:4318"   # OTLP HTTP
```

Create the Collector config referenced above:

```yaml title="otel-collector-config.yaml"
receivers:
  otlp:
    protocols:
      http:
      grpc:

processors:
  batch: {}

exporters:
  otlphttp:
    endpoint: https://api.statsig.com/otlp
    encoding:  json
    headers:
      statsig-api-key: ${env:STATSIG_SERVER_SDK_SECRET}

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlphttp]
    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlphttp]
    logs:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlphttp]
```

Start the Collector:

```bash
export STATSIG_SERVER_SDK_SECRET=YOUR_SECRET
docker compose up -d
```

Point your applications at the Collector: `http://localhost:4318` (or `http://otel-collector:4318` from other compose services). The Collector forwards telemetry to Statsig using your key.
{% /tab %}

{% tab title="Other" %}
You can run the Collector in other environments (VMs, bare metal) using the config below. Go to the [Collector documentation](https://opentelemetry.io/docs/collector/installation/) for other installation and deployment methods.

```yaml title="otel-collector-config.yaml"
exporters:
  otlphttp:
    endpoint: https://api.statsig.com/otlp
    encoding: json
    headers:
      statsig-api-key: ${env:STATSIG_SERVER_SDK_SECRET}
```
{% /tab %}
{% /tabs %}

***

## Common Collector configs (K8s & Docker)

The following examples show popular receivers and processors you can enable in your Collector and still export to Statsig through the same `otlphttp` exporter.

{% callout type="note" %}
These components live in the contrib distribution. Use an image that includes them:

* Docker: `otel/opentelemetry-collector-contrib` or newer
* Helm: set `image.repository: otel/opentelemetry-collector-contrib` (and a compatible `image.tag`)
{% /callout %}

Helm values (contrib image):

```yaml title="values.yaml"
image:
  repository: otel/opentelemetry-collector-contrib
  tag: "latest"
  pullPolicy: IfNotPresent
```

### A. File logs (filelog receiver)

Reads and parses logs from files on disk. This is useful for hosts, containers, or Kubernetes nodes.

Minimal example:

```yaml
receivers:
  filelog:
    include: [ /var/log/myservice/*.json ]
    start_at: beginning
    operators:
      - type: json_parser
        timestamp:
          parse_from: attributes.time
          layout: '%Y-%m-%dT%H:%M:%S%z'

processors:
  batch: {}

exporters:
  otlphttp:
    endpoint: https://api.statsig.com/otlp
    encoding: json
    headers:
      statsig-api-key: ${env:STATSIG_SERVER_SDK_SECRET}

service:
  pipelines:
    logs:
      receivers: [filelog]
      processors: [batch]
      exporters: [otlphttp]
```

Kubernetes tip: to tail container logs on nodes, mount host paths (for example, `/var/log/pods` and `/var/lib/docker/containers`) into the Collector DaemonSet and set `include` to those paths.

### B. EC2 resource detection (resourcedetection processor)

Automatically adds AWS EC2 metadata (cloud provider, region/zone, instance ID) to your telemetry.

```yaml
processors:
  resourcedetection/ec2:
    detectors: [env, ec2]
    timeout: 2s
    override: false

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [resourcedetection/ec2, batch]
      exporters: [otlphttp]
    metrics:
      receivers: [otlp]
      processors: [resourcedetection/ec2, batch]
      exporters: [otlphttp]
    logs:
      receivers: [otlp]
      processors: [resourcedetection/ec2, batch]
      exporters: [otlphttp]
```

The Collector must be able to reach the EC2 metadata service (IMDS). Ensure network access to `169.254.169.254` and IMDSv2 where required.

### C. Docker container metrics (docker\_stats receiver)

Emits container CPU, memory, network, and block I/O metrics by querying the Docker daemon.

```yaml
receivers:
  docker_stats:
    endpoint: unix:///var/run/docker.sock
    collection_interval: 15s

processors:
  batch: {}

exporters:
  otlphttp:
    endpoint: https://api.statsig.com/otlp
    encoding: json
    headers:
      statsig-api-key: ${env:STATSIG_SERVER_SDK_SECRET}

service:
  pipelines:
    metrics:
      receivers: [docker_stats]
      processors: [batch]
      exporters: [otlphttp]
```

Requirements:

* Linux only (not supported on macOS or Windows).
* Mount the Docker socket into the Collector container: `/var/run/docker.sock`.

***

## Related resources

* OpenTelemetry Collector: https://opentelemetry.io/docs/collector/
* Kubernetes Collector components: https://opentelemetry.io/docs/platforms/kubernetes/collector/components/
* Helm chart: https://github.com/open-telemetry/opentelemetry-helm-charts
* Collector configuration reference: https://opentelemetry.io/docs/collector/configuration
* OTLP protocol specification: https://opentelemetry.io/docs/specs/otlp/
* Filelog receiver (contrib): https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/filelogreceiver
* Resource detection processor (contrib): https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/resourcedetectionprocessor
* Docker stats receiver (contrib): https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/dockerstatsreceiver
* Collector contrib distribution: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib
