> ## Documentation Index
> Fetch the complete documentation index at: https://docs.squasher.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenTelemetry

> Send traces, logs, and metrics from any OpenTelemetry SDK to Squasher via OTLP/HTTP.

Squasher natively accepts [OpenTelemetry](https://opentelemetry.io/) data via the OTLP/HTTP protocol. This means you can send traces, logs, and metrics from **any language** that OTel supports — Node.js, Python, Go, Java, Ruby, .NET, Rust, PHP, Elixir, and more — without installing a Squasher-specific SDK.

Squasher automatically extracts error events from your telemetry, so you get full error monitoring with zero custom instrumentation.

If you use the Log Connectors screen in Squasher, create the OTLP HTTP connector first and copy the managed endpoint and ingest key from there. The endpoints below map to the same OTLP entry points.

For AI workflows, spans with `gen_ai.*` attributes can be classified into AI observations. Use the [Agent telemetry SDK](/sdks/agent) when you want richer session, generation, cost, and tool-call capture without manually shaping OTel attributes.

## AI span conventions

Squasher routes AI spans from `/v1/traces` into the AI observability dataset when they include one of these markers:

* OpenTelemetry GenAI attributes such as `gen_ai.operation.name`, `gen_ai.request.model`, `gen_ai.provider.name`, `gen_ai.system`, and `gen_ai.usage.*`
* Vercel AI SDK telemetry attributes such as `operation.name=ai.streamText.doStream`, `ai.model.id`, `ai.model.provider`, and `ai.usage.*`
* Langfuse-compatible attributes such as `langfuse.observation.type=generation`, `langfuse.observation.model.name`, `langfuse.observation.usage_details`, and `langfuse.observation.cost_details`
* OpenInference markers such as `openinference.span.kind=LLM` or `openinference.span.kind=TOOL`

For token and cost accuracy, send provider-reported usage when available. Squasher reads prompt/input tokens, completion/output tokens, total tokens, cached input tokens, and explicit USD cost from these conventions before falling back to model-rate cost calculation.

## How It Works

Squasher's OTLP endpoints accept standard trace, log, and metric payloads. From these, Squasher extracts:

* **Exception events** from trace spans (the `exception` span event with `exception.type`, `exception.message`, and `exception.stacktrace` attributes)
* **Error spans** — any span with `status.code = ERROR`
* **Error/fatal log records** — log records with severity `ERROR` or higher
* **Metric points** — gauges, sums, histograms, and exponential histograms sent to `/v1/metrics`

Error telemetry creates error groups. Non-error OTLP logs are still stored as log context and counted against your log quota, so you can keep the surrounding trail that explains what happened before and after an error.

## Endpoint Configuration

| Setting            | Value                                              |
| ------------------ | -------------------------------------------------- |
| **Endpoint**       | `https://ingest.squasher.ai`                       |
| **Traces**         | `POST /v1/traces`                                  |
| **Logs**           | `POST /v1/logs`                                    |
| **Metrics**        | `POST /v1/metrics`                                 |
| **Protocol**       | OTLP/HTTP (protobuf and JSON)                      |
| **Authentication** | `x-squasher-key` header or `Authorization: Bearer` |

## Authentication

Pass your Squasher API key using either method:

* **Custom header:** `x-squasher-key: sq_pk_your_api_key`
* **Standard auth:** `Authorization: Bearer sq_pk_your_api_key`

Both are supported. Use whichever your OTel SDK makes easier.

<Note>
  Your API key is available in the [Dashboard](https://app.squasher.ai/dashboard/settings) under **Settings > API Keys**.
</Note>

## Quick Start with Environment Variables

Most OTel SDKs support configuration via environment variables. Set these and your SDK will send data to Squasher automatically:

```bash theme={null}
export OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.squasher.ai
export OTEL_EXPORTER_OTLP_HEADERS="x-squasher-key=sq_pk_your_api_key"
export OTEL_SERVICE_NAME=your-service-name
```

## Language-Specific Setup

<Tabs>
  <Tab title="Node.js">
    **Install packages:**

    ```bash theme={null}
    npm install @opentelemetry/sdk-node \
      @opentelemetry/auto-instrumentations-node \
      @opentelemetry/exporter-metrics-otlp-http \
      @opentelemetry/exporter-trace-otlp-http \
      @opentelemetry/exporter-logs-otlp-http \
      @opentelemetry/sdk-metrics
    ```

    **Create `tracing.ts`:**

    ```typescript tracing.ts theme={null}
    import { NodeSDK } from "@opentelemetry/sdk-node";
    import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
    import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
    import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
    import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
    import { SimpleLogRecordProcessor } from "@opentelemetry/sdk-logs";
    import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";

    const sdk = new NodeSDK({
      traceExporter: new OTLPTraceExporter({
        url: "https://ingest.squasher.ai/v1/traces",
        headers: { "x-squasher-key": process.env.SQUASHER_API_KEY },
      }),
      logRecordProcessor: new SimpleLogRecordProcessor(
        new OTLPLogExporter({
          url: "https://ingest.squasher.ai/v1/logs",
          headers: { "x-squasher-key": process.env.SQUASHER_API_KEY },
        })
      ),
      metricReader: new PeriodicExportingMetricReader({
        exporter: new OTLPMetricExporter({
          url: "https://ingest.squasher.ai/v1/metrics",
          headers: { "x-squasher-key": process.env.SQUASHER_API_KEY },
        }),
      }),
      instrumentations: [getNodeAutoInstrumentations()],
    });

    sdk.start();
    ```

    **Run your app:**

    ```bash theme={null}
    node --require ./tracing.js your-app.js
    ```
  </Tab>

  <Tab title="Python">
    **Install packages:**

    ```bash theme={null}
    pip install opentelemetry-sdk \
      opentelemetry-exporter-otlp-proto-http \
      opentelemetry-instrumentation
    ```

    **Set environment variables and run:**

    ```bash theme={null}
    export OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.squasher.ai
    export OTEL_EXPORTER_OTLP_HEADERS="x-squasher-key=sq_pk_your_api_key"
    export OTEL_SERVICE_NAME=your-service

    opentelemetry-instrument python your-app.py
    ```
  </Tab>

  <Tab title="Go">
    **Install packages:**

    ```bash theme={null}
    go get go.opentelemetry.io/otel \
      go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp \
      go.opentelemetry.io/otel/sdk/trace
    ```

    **Set environment variables:**

    ```bash theme={null}
    export OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.squasher.ai
    export OTEL_EXPORTER_OTLP_HEADERS="x-squasher-key=sq_pk_your_api_key"
    export OTEL_SERVICE_NAME=your-service
    ```
  </Tab>

  <Tab title="Java">
    **Download the OTel Java agent:**

    ```bash theme={null}
    curl -L -o opentelemetry-javaagent.jar \
      https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
    ```

    **Run with the agent:**

    ```bash theme={null}
    java -javaagent:opentelemetry-javaagent.jar \
      -Dotel.exporter.otlp.endpoint=https://ingest.squasher.ai \
      -Dotel.exporter.otlp.headers="x-squasher-key=sq_pk_your_api_key" \
      -Dotel.service.name=your-service \
      -jar your-app.jar
    ```
  </Tab>

  <Tab title="OTel Collector">
    Add Squasher as an OTLP/HTTP exporter in your collector config:

    ```yaml otel-collector-config.yaml theme={null}
    exporters:
      otlphttp/squasher:
        endpoint: https://ingest.squasher.ai
        headers:
          x-squasher-key: "sq_pk_your_api_key"

    service:
      pipelines:
        traces:
          exporters: [otlphttp/squasher]
        logs:
          exporters: [otlphttp/squasher]
        metrics:
          exporters: [otlphttp/squasher]
    ```

    This lets you fan out your existing OTel data to Squasher alongside your current observability backend.
  </Tab>
</Tabs>

## Resource Attributes

Squasher extracts these standard OTel resource attributes automatically:

| Resource Attribute       | Maps To                                                         |
| ------------------------ | --------------------------------------------------------------- |
| `service.name`           | Stored as a tag; used for grouping                              |
| `deployment.environment` | Environment field (production, staging, etc.)                   |
| `service.version`        | Release/version field                                           |
| `service.namespace`      | Fallback for environment if `deployment.environment` is not set |

All other resource and span attributes are preserved as tags on the error event.

## Supported Formats

| Content-Type             | Format                                   |
| ------------------------ | ---------------------------------------- |
| `application/x-protobuf` | Protocol Buffers (default for most SDKs) |
| `application/json`       | JSON encoding                            |

Both are fully supported. Most OTel SDKs default to protobuf — no configuration needed.

## Delivery behavior

A successful OTLP response means Squasher has stored the batch in the active telemetry store or in durable regional recovery storage. If the active store is unavailable, Squasher accepts the batch into recovery storage and replays it without placing the backlog ahead of new telemetry. Replayed data can appear later than live data.

The recovery path provides at-least-once delivery. A failure near the storage boundary can produce a duplicate row. Keep stable trace IDs, span IDs, timestamps, and other OpenTelemetry identities so repeated data remains identifiable.

Retry `5xx` and `429` responses with bounded exponential backoff. Do not retry other `4xx` responses without correcting the request.

## Combining with Squasher SDKs

You can use OpenTelemetry alongside Squasher's native SDKs. For example, use the Squasher Next.js SDK for your frontend and OpenTelemetry for your backend microservices in Go or Python. All errors appear in the same dashboard.

## Collector deployment guides

* [Prometheus metrics](/integrations/prometheus-metrics) — translate Prometheus scrapes or Remote Write 2.0 to OTLP.
* [Jaeger traces](/integrations/jaeger-traces) — dual-ship OTLP or translate legacy Jaeger protocols.
* [Tail sampling](/integrations/tail-sampling) — keep error and slow traces while reducing routine trace volume.
* [Durable workflow traces](/integrations/durable-workflows) — connect retries and resumed work with finite spans and links.

## Agent handoff

```text theme={null}
Configure OpenTelemetry for Squasher only when the app already emits OTLP or needs vendor-neutral traces/logs/metrics. Set OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS, and OTEL_SERVICE_NAME from env, verify one error span or error log, and use @squasher-ai/agent instead for first-class AI workflow telemetry.
```

## Limitations

* **Error-focused grouping:** Only error-level telemetry creates error groups, but non-error OTLP logs can still be stored as context.
* **Metric read paths:** General OTLP metrics are queryable through the [Metrics API](/api-reference/metrics). Browser vitals continue to have their own dedicated dashboards and APIs.
* **Trace workflows:** Distributed traces and waterfalls are available through the [Traces API](/api-reference/traces) and trace views in the dashboard.
