Logit.io
Point OpenTelemetry at Logit.io
← Back to blog
10/8/2026 · 6 min read

Already on OpenTelemetry? Point it at Logit.io by changing three settings

Logit.io Team
Logit.io Team
Technical Content Team

Last updated 10/8/2026

How To GuidesResources

If your applications already emit OpenTelemetry, you've done the hard part. The instrumentation, the service names and the resource attributes stay exactly as they are. Sending that data to a Logit.io Logs stack comes down to three settings:

  1. the endpoint: https://your-stack-id-otel.logit.io
  2. the protocol: http/protobuf
  3. the auth header: Authorization=Basic%20 plus a base64 token

That's the whole change for most setups. Below is where each value comes from, and the details that trip people up.

Contents

Setting one: the endpoint

Every Logs stack can have a Hosted OpenTelemetry endpoint at https://{stackId}-otel.logit.io. New Logs stacks get it switched on, and it's on every plan. On an older stack, open the stack's Endpoints page. An account owner or administrator, or a stack administrator, presses Switch on on the Hosted OpenTelemetry card. Setup takes a few minutes, and then the connection details appear.

Use it as a base URL: HTTPS, port 443 implied, and no path. With the standard OTEL_EXPORTER_OTLP_ENDPOINT variable, SDKs append /v1/traces, /v1/metrics and /v1/logs themselves, so one value covers all three signals.

The exception catches a lot of people. The per-signal variables, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT and its metrics and logs siblings, are used exactly as written. Nothing is appended, as the OTLP exporter specification spells out. If you set one of those to the bare Logit.io host, requests go to / and fail. Either remove the per-signal variables and rely on the shared one, or give each the full URL, for example https://your-stack-id-otel.logit.io/v1/traces. The same rule applies to an endpoint you set in code: a bare host assigned in code generally isn't given the signal paths.

Setting two: the protocol

The Hosted endpoint takes OTLP over HTTP with protobuf encoding. gRPC isn't supported, and ports 4317 and 4318 aren't exposed. Set:

OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf

This matters more than it looks, because several SDKs default to gRPC, the .NET exporter among them. If your config never mentions a protocol, assume it's gRPC and set it explicitly. In code, that usually means switching from a gRPC exporter class to its HTTP counterpart: in Go, otlptracehttp instead of otlptracegrpc, and in .NET, OtlpExportProtocol.HttpProtobuf.

Zero-code agents follow the same rules. The Java agent takes the three values as otel.exporter.otlp.endpoint, otel.exporter.otlp.protocol and otel.exporter.otlp.headers, in a properties file or as system properties, and Python's opentelemetry-instrument reads the standard environment variables. In both cases the per-signal variants keep their paths as written, just like the environment variables above.

A Collector is the same story. An otlp exporter speaks gRPC, so the Logit.io exporter needs to be otlphttp.

Setting three: the auth header

Authentication is HTTP Basic. The username is your stack ID followed by -otel, and the password is the Hosted OpenTelemetry API key, both shown on the Endpoints card. For SDKs that read the standard variable, the value is:

OTEL_EXPORTER_OTLP_HEADERS=Authorization=Basic%20<base64 of username:api-key>

You don't have to build that by hand. Onboarding shows it ready-made as the Header credential, next to the endpoint, username and API key. If you'd rather keep the key in its own variable, these are the forms the onboarding prompts use. In bash:

export LOGIT_API_KEY='your-api-key'
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic%20$(printf '%s' 'your-stack-id-otel:'"$LOGIT_API_KEY" | base64 | tr -d '\n')"

And in PowerShell:

$pair = "your-stack-id-otel:$env:LOGIT_API_KEY"
$env:OTEL_EXPORTER_OTLP_HEADERS = "Authorization=Basic%20" + [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($pair))

Two things to know about that %20. First, it's how the OTLP exporter configuration expects header values to be encoded, and most SDKs decode it to a space. Second, not everything decodes it:

  • A Collector headers map, and logging sinks such as Serilog or NLog, take the header value literally. There the value is Basic, a real space, and the token.
  • The Swift and C++ SDKs don't percent-decode the environment variable, so a %20 header returns 401. Set the Authorization header in code instead.
  • Elixir and Erlang configure otlp_headers in their config files, again with a real space.

And an export in your terminal only applies to that terminal. Set the variables on the process that actually runs the app: the container environment, a systemd EnvironmentFile, or your platform's secret settings.

Start Free Trial

Unlock complete visibility with hosted ELK, Grafana, and Prometheus-backed Observability

Start Free Trial

If you already run a Collector

If your services send to a Collector, leave them alone. Point the Collector at Logit.io instead, and keep one exporter for all three pipelines rather than adding a second Collector. With the contrib distribution's basicauth extension, that's:

extensions:
  basicauth/logit:
    client_auth:
      username: "your-stack-id-otel"
      password: "${env:LOGIT_API_KEY}"

exporters:
  otlphttp/logit:
    endpoint: "https://your-stack-id-otel.logit.io"
    auth: { authenticator: basicauth/logit }

Add basicauth/logit to service.extensions and swap otlphttp/logit into the exporters list of your logs, traces and metrics pipelines. Make sure LOGIT_API_KEY is set in the Collector's own environment, not just your shell. The Collector appends the /v1 paths itself, so the endpoint stays a base URL. The I already run a Collector option in onboarding gives you this fragment with your stack's values filled in.

If you're moving from an older Logit.io setup with separate OpenSearch, OTLP and Prometheus remote write exporters, switch one pipeline at a time, confirm the data, then remove the old exporter. Expect duplicates while both are in the same pipeline.

Test the credentials before you touch production

A quick way to separate a credential problem from an app problem is to post one log with curl. This is the same shape as onboarding's Send a test signal option:

curl -s -o /dev/null -w "%{http_code}\n" \
  -u "your-stack-id-otel:$LOGIT_API_KEY" \
  -H "Content-Type: application/json" \
  -X POST https://your-stack-id-otel.logit.io/v1/logs \
  -d '{"resourceLogs":[{"resource":{"attributes":[{"key":"service.name","value":{"stringValue":"curl-test"}}]},"scopeLogs":[{"logRecords":[{"severityText":"INFO","body":{"stringValue":"hello from curl"}}]}]}]}'

A 200 means the endpoint and credentials are good, and anything still failing is in the app's config. A 401 means the route is there but the username or key is wrong, often because the key was rotated after you copied it.

Where each signal lands

Logs go to your Logs stack's OpenSearch. Traces go to your APM stack and metrics to your Metrics stack. If one of those stacks doesn't exist, the endpoint still accepts the signal with a 200 but has nowhere to store it, so it's dropped, and the dashboard shows how many arrived and offers to add the missing stack. Your exporters never see errors for it, which is why the same config can go to every environment on day one.

If you'd rather have an assistant make the change, onboarding's Applications option has a Copy AI prompt for each language. For an app that already exports OTLP, the prompt asks for exactly these three settings to change, keeps your SDK, exporter and service name, and leaves the API key out of the prompt. For the wider picture, see the OpenTelemetry getting started docs and the guides to OpenTelemetry for traces and OpenTelemetry for metrics.

Get the latest Elastic Stack & logging resources when you subscribe

Want to see this in action?
Start a free trial and connect logs to your alert workflows.