OpenTelemetry
ScryWatch supports the OpenTelemetry standard for distributed traces. You can send OTLP/HTTP trace data directly from your services or route it through an OpenTelemetry Collector.
What’s supported today
| Signal | OTLP Support | Alternative |
|---|---|---|
| Traces | ✅ POST /api/traces/otlp | POST /api/traces (native format) |
| Logs | ❌ Not yet | POST /v1/ingest (HTTP JSON) |
| Metrics | ❌ Not yet | POST /api/metrics (HTTP JSON) |
Why be explicit? OTLP Logs is still maturing in the OpenTelemetry ecosystem — the Go SDK logs bridge is experimental as of early 2026, and the spec has seen breaking changes. We’ll add OTLP log and metric ingestion when the implementations are stable.
OTLP Traces endpoint
POST https://api.scrywatch.com/api/traces/otlp
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Accepts the OTLP/HTTP protobuf-JSON format.
Option 1: Direct OTLP exporter (no Collector)
Instrument each service and point the exporter at ScryWatch.
Node.js / TypeScript
npm install @opentelemetry/sdk-node \
@opentelemetry/exporter-trace-otlp-http \
@opentelemetry/resources \
@opentelemetry/semantic-conventions
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { Resource } from '@opentelemetry/resources';
import { SEMRESATTRS_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
const sdk = new NodeSDK({
resource: new Resource({
[SEMRESATTRS_SERVICE_NAME]: 'my-service',
}),
traceExporter: new OTLPTraceExporter({
url: 'https://api.scrywatch.com/api/traces/otlp',
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
}),
});
sdk.start();
Python
pip install opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
exporter = OTLPSpanExporter(
endpoint="https://api.scrywatch.com/api/traces/otlp",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)
Go
See the full Go integration guide for setup. The OTLP exporter config is:
otlptracehttp.WithEndpoint("api.scrywatch.com"),
otlptracehttp.WithURLPath("/api/traces/otlp"),
otlptracehttp.WithHeaders(map[string]string{
"Authorization": "Bearer YOUR_API_KEY",
}),
Option 2: OpenTelemetry Collector (recommended for production)
Route all telemetry through a Collector. Your services export to localhost; the Collector forwards to ScryWatch. When you change observability backends, only the Collector config changes — not every service.
Collector config — traces only
# otel-collector-config.yaml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
timeout: 5s
send_batch_size: 100
memory_limiter:
check_interval: 1s
limit_mib: 256
exporters:
otlphttp/scrywatch:
endpoint: https://api.scrywatch.com
headers:
Authorization: "Bearer ${env:SCRYWATCH_API_KEY}"
sending_queue:
enabled: true
retry_on_failure:
enabled: true
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlphttp/scrywatch]
# Logs pipeline omitted — OTLP log ingestion is not yet supported.
# Use the ScryWatch SDK or POST /v1/ingest directly for logs.
Pointing services at the Collector
# Environment variables — most OTel SDKs pick these up automatically
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
OTEL_SERVICE_NAME=my-service
OTEL_TRACES_EXPORTER=otlp
OTLP data model mapping
| OTLP field | ScryWatch field |
|---|---|
resource.attributes["service.name"] | service |
span.traceId | trace_id |
span.spanId | span_id |
span.parentSpanId | parent_span_id |
span.name | name |
span.startTimeUnixNano | start_time (converted to ms) |
span.endTimeUnixNano | end_time (converted to ms) |
span.status.code == 2 | status: "error" |
span.attributes["http.method"] | stored in attributes JSON |
span.attributes["http.url"] | stored in attributes JSON |
span.events | stored as events JSON array |
Test your setup
Send a minimal test trace to verify connectivity:
curl -X POST https://api.scrywatch.com/api/traces/otlp \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"resourceSpans": [{
"resource": {
"attributes": [{"key": "service.name", "value": {"stringValue": "test"}}]
},
"scopeSpans": [{
"spans": [{
"traceId": "aabbccdd00112233aabbccdd00112233",
"spanId": "1122334455667788",
"name": "test-span",
"startTimeUnixNano": "1741200000000000000",
"endTimeUnixNano": "1741200000250000000",
"status": {"code": 1}
}]
}]
}]
}'
# Expected: {"inserted":1}
Then check the Distributed Tracing view in ScryWatch.
See also
- Distributed Tracing guide — native ScryWatch trace format
- Kubernetes guide — deploying Collector in Kubernetes
- Go integration — Go OTel SDK setup
- PHP integration — PHP logs via HTTP ingest