RawTree is OTel Native
by Jorge Sancha
RawTree is an analytical database for semi-structured data. Agent traces, webhook payloads, product events, IoT streams, application logs: if the data is messy or evolving, RawTree is built for it. You send data, you query with SQL, and you skip the upfront schema work.
OpenTelemetry is a very natural fit for that model.
It does not make much sense, in 2026, to build an analytical database for modern application data and not support OTel directly. OTel is no longer a niche instrumentation project. It is the default way many teams collect traces, logs, and metrics, and a growing number of platforms already emit OTLP for you: Vercel, Cloudflare Workers, Modal, Daytona, Supabase, Google Cloud, AWS, and many others.
That adoption matters because standards only become useful at scale once you can assume they are already in the path.
The practical implication is simple: your stack may already be producing OTel data. The question is not whether that data exists. The question is where it goes, how much of it survives, and whether and how humans and agents can use it.
That is why RawTree is OTel native from day one.
What OTel native means
RawTree exposes native OTLP endpoints under /otlp/v1/* for HTTP and the standard gRPC collector services.
| Signal | OTLP/HTTP endpoint | Default table |
|---|---|---|
| Traces | POST /otlp/v1/traces | traces |
| Logs | POST /otlp/v1/logs | logs |
| Metrics | POST /otlp/v1/metrics | metrics |
Point your SDK's OTLP exporter at https://api.rawtree.com/otlp with your RawTree API key as the bearer token. Or point an OpenTelemetry Collector there if you already run one.
Data lands in the default signal tables (traces, logs, metrics), or you can route it to custom tables with signal-specific headers (x-rawtree-traces-table, x-rawtree-logs-table, x-rawtree-metrics-table).
RawTree supports the OTLP protocols you already use:
http/protobuf, OTLP over HTTP with protobuf payloadshttp/json, OTLP over HTTP with JSON payloadsgrpc, OTLP over gRPC with protobuf payloads
Compression is separate. Set OTEL_EXPORTER_OTLP_COMPRESSION=gzip and RawTree accepts gzip-compressed requests on any of the three.
This matters more than it sounds. Different SDKs and platforms do not all send telemetry the same way. Some send protobuf over HTTP. Some use gRPC. Some let you configure everything. Some barely let you configure anything. RawTree accepts the data in the shape it arrives.
Here is the smallest possible trace insert:
curl -X POST "https://api.rawtree.com/otlp/v1/traces" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"resourceSpans":[{"resource":{"attributes":[{"key":"service.name","value":{"stringValue":"api"}}]},"scopeSpans":[{"spans":[{"name":"GET /health","spanId":"abc"}]}]}]}'Why this matters now
Charts have been central to observability for a good reason: humans understand quantitative information faster when they can see it.
That is why SREs and platform engineers have traditionally used dashboards during incidents. You scan latency, error rate, saturation, queue depth, deployment markers, and whatever else your team thought to chart ahead of time. When something looks wrong, you drill in.
That workflow is not going away. But it is changing.
Lately, during incidents or when investigating behavior we did not expect, we increasingly find ourselves asking the same agent we code with to inspect telemetry through Grafana's MCP, run queries, compare services, generate a hypothesis, and validate it. If a chart would help the human at the keyboard understand the problem at hand, the agent can build the chart on the spot.
Once an agent can fire 20 queries in parallel, interpret the results, form a hypothesis and share it, the value of a large prebuilt dashboard does not disappear. But it does diminish.
The dashboard used to be the starting point. In an agent-assisted workflow, raw data is the starting point and charts can help explain or validate findings.
That shift changes what the storage layer needs to do.
Adaptable, self-improving data stores
Observability workloads evolve at the same pace application and systems change. The shape of the telemetry can shift quickly, and values that did not exist yesterday become the central point of interest or drive the key aggregations to track. New services can introduce attributes to rely on during investigations, cost reduction exercises or performance improvements.
In this context, the ideal data store would:
- accept rich telemetry data without forcing a schema decision upfront
- let the shape of that data evolve as instrumentation or systems evolve
- expose a query surface that agents and humans can easily use and learn
- answer ad hoc questions with low latency
- learn from common query patterns and improve performance over time, to adapt to the varying needs of development / infrastructure teams
The agent you use to change code should also be able to ask what happened in production, query raw events to determine the best course of action or potential improvements.
We think this is the path to self-correcting infrastructure that can be operated at scale by teams of any size, by enabling agents to observe state, compare it to intent, propose or apply a fix, and then verify the result.
And that is the reason RawTree has native OpenTelemetry support out of the gate. We are not building an observability product. We are building a database that makes observability data a first class citizen, useful to agents and humans.
The storage problem OpenTelemetry does not solve
OpenTelemetry solves collection. It standardizes SDKs, context propagation, signal formats, and transport. That is a huge deal.
It does not solve storage.
The spec defines how telemetry is produced and moved. It does not define how it should be stored, flattened, queried, retained, joined with product data, or exposed to agents.
And OTLP data is not a convenient analytical shape on the wire. A trace export is deeply nested:
{
"resourceSpans": [{
"resource": {
"attributes": [
{"key": "service.name", "value": {"stringValue": "checkout-service"}},
{"key": "deployment.environment", "value": {"stringValue": "production"}}
]
},
"scopeSpans": [{
"scope": {"name": "checkout-service", "version": "1.2.0"},
"spans": [{
"traceId": "a1b2c3d4e5f6...",
"spanId": "1a2b3c4d...",
"parentSpanId": "9z8y7x6w...",
"name": "checkout.process",
"kind": 1,
"startTimeUnixNano": "1717200000000000000",
"endTimeUnixNano": "1717200000842000000",
"attributes": [
{"key": "http.method", "value": {"stringValue": "POST"}},
{"key": "http.status_code", "value": {"intValue": "200"}},
{"key": "user.id", "value": {"stringValue": "u_7829"}}
],
"status": {"code": 1}
}]
}]
}]
}The useful fields are in there, but they are buried under resource spans, scopes, spans, and attribute arrays.
If you store that document as-is, every useful question becomes an extraction problem. What was the p95 checkout latency in the last hour? Which users were affected between 2:12 and 2:17? Which deploy introduced the error? Which sandbox executions are slowest?
General-purpose JSON storage can work at low volume. It becomes painful when the data grows and the questions get more specific. Traditional analytical databases can be very fast, but often ask you to decide the schema, sort keys, projections, and materialized views before you know which questions matter.
That is the gap OTel leaves open.
What RawTree does with OTel data
RawTree's OTLP endpoints do not just accept the data. They flatten it on insert using built-in transforms, so the nested OTLP hierarchy becomes flat, queryable rows.
Before: what the OTel SDK emits.
{
"resourceSpans": [{
"resource": {
"attributes": [
{"key": "service.name", "value": {"stringValue": "checkout-service"}}
]
},
"scopeSpans": [{
"scope": {"name": "checkout-service"},
"spans": [{
"traceId": "a1b2c3d4e5f6...",
"spanId": "1a2b3c4d...",
"name": "checkout.process",
"startTimeUnixNano": "1717200000000000000",
"endTimeUnixNano": "1717200000842000000",
"attributes": [
{"key": "http.method", "value": {"stringValue": "POST"}},
{"key": "http.status_code", "value": {"intValue": "200"}}
]
}]
}]
}]
}After: what RawTree stores, one row per span.
| name | traceId | spanId | service.name | scope.name | startTimeUnixNano | endTimeUnixNano | attributes |
|---|---|---|---|---|---|---|---|
| checkout.process | a1b2c3d4e5f6... | 1a2b3c4d... | checkout-service | checkout-service | 1717200000000000000 | 1717200000842000000 | [{"key":"http.method","value":{"stringValue":"POST"}}, ...] |
The field names stay close to the raw OTLP names. Resource attributes (service.name, host.*, process.*) and scope.name are promoted and unwrapped to top-level fields, so the context you filter and group by is flat. Timestamps stay as the original nanosecond strings. Span-level attributes stay as their original OTLP array, ready to unnest when you need a specific one.
No Collector processors are required. No ETL pipeline. No table definition step. The transform happens on insert, once, and resource context is merged into every span row so you do not re-walk the OTLP hierarchy on every query.
The p95 latency question becomes:
SELECT quantile(0.95)((toUInt64(endTimeUnixNano) - toUInt64(startTimeUnixNano)) / 1e6) AS p95_ms
FROM traces
WHERE name = 'checkout.process'
AND fromUnixTimestamp64Nano(toInt64(startTimeUnixNano)) > now() - INTERVAL 1 HOUROne table. SQL. No three-level array walk.
Reading a span attribute still means touching the OTLP attribute array:
SELECT arrayFirst(
x -> x.1 = 'http.status_code',
arrayMap(a -> (a.key::String, a.value.intValue), attributes::Array(JSON))
).2 AS status
FROM traces
WHERE name = 'POST /api/submit'That is intentional. Resource context is flat because it is used constantly for filtering and grouping. Per-span attributes are preserved in their original shape because instrumentation changes and you should not have to remodel the table every time a new attribute appears.
The same pattern applies to all three OTel signal types:
/otlp/v1/tracesapplies theotlp-tracestransform and writes to thetracestable/otlp/v1/logsapplies theotlp-logstransform and writes to thelogstable/otlp/v1/metricsapplies theotlp-metricstransform and writes to themetricstable
Works with the OTel already in your stack
Some teams will instrument their application directly. Some will run a Collector. Some will get OTel from the platforms they already use.
Sandbox providers are a good example. Daytona emits traces, logs, and metrics from sandbox execution. You can point that telemetry straight at RawTree.
Here is the Daytona example in the RawTree docs:
import { Daytona } from "@daytona/sdk";
const daytonaApiKey = process.env.DAYTONA_API_KEY;
const rawtreeApiKey = process.env.RAWTREE_API_KEY;
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://api.rawtree.com/otlp";
process.env.OTEL_EXPORTER_OTLP_HEADERS = `Authorization=Bearer ${rawtreeApiKey}`;
const daytona = new Daytona({
apiKey: daytonaApiKey,
otelEnabled: true,
});
const sandbox = await daytona.create({ language: "typescript" });
try {
const response = await sandbox.process.codeRun(
'console.log("Hello World from Daytona!")',
);
console.log(response.result);
} finally {
await daytona.delete(sandbox);
await daytona[Symbol.asyncDispose]();
}Set the two environment variables, enable otelEnabled, and sandbox operations start flowing into RawTree's traces table.
The same pattern applies to any platform that emits OTLP: Vercel, Cloudflare Workers, Modal, Supabase, or your own services running an OTel SDK.
Once the data lands in RawTree, you query it with SQL:
SELECT "service.name", name,
avg((toUInt64(endTimeUnixNano) - toUInt64(startTimeUnixNano)) / 1e6) AS avg_ms,
count()
FROM traces
WHERE fromUnixTimestamp64Nano(toInt64(startTimeUnixNano)) > now() - INTERVAL 1 HOUR
GROUP BY "service.name", name
ORDER BY avg_ms DESCGetting data in
For SDKs that use environment variables, direct export is three lines:
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.rawtree.com/otlp
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer%20$API_KEY"For gRPC:
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.rawtree.com
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer%20$API_KEY"You do not need a Collector to get started.
A Collector is worth adding when you want batching, sampling, filtering, retries, enrichment, or fan-out to multiple backends. If you already run one, RawTree is just another OTLP exporter:
exporters:
otlphttp:
endpoint: https://api.rawtree.com/otlp
headers:
Authorization: "Bearer $API_KEY"
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlphttp]
logs:
receivers: [otlp]
processors: [batch]
exporters: [otlphttp]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [otlphttp]You can also send OTLP data directly from the RawTree CLI for testing or ad hoc loads:
rtree insert --table traces --transform otlp-traces --file ./traces.json
rtree query "SELECT name, count() FROM traces GROUP BY name"What you are not locked into
RawTree is OTel native, but it is not an observability platform.
It does not come with dashboards, alerting rules, or an incident workflow. We are the database underneath, and the fastest way to build around that data without worrying about schema changes or performance optimization at scale: Logs, traces, and telemetry are a workload RawTree is great at.
You can definitely hook Grafana or other BI tools to RawTree if that's what you need, but we remain the database, not the observability platform. That distinction matters.
OTel unbundled instrumentation and collection. RawTree keeps the storage layer open too. Your telemetry is queryable with SQL, available through an API, accessible to agents through MCP, and usable next to the rest of your analytical data.
Ask your agent what changed. Let it run the queries. Let it build the chart if a chart helps. Or build a custom trace explorer, connect a dashboard, write alerting on top, or join your telemetry with product data.
The point is not that charts disappear. The point is that charts are no longer the only interface to operational data.
Send OpenTelemetry to RawTree. Ask your agent to interpret it. Build the best tool for the job with a few prompts.
Sign up to RawTree's private beta.