OTLP-native trace ingest
Send traces from any OpenTelemetry exporter without the Frametail SDK.
Frametail accepts traces via the OpenTelemetry Protocol (OTLP), enabling any standard exporter — OpenLLMetry, OpenInference, Vercel AI SDK's experimental_telemetry, LangChain, or your own instrumentation — to send traces without installing the Frametail SDK.
Sending traces
Send an OTLP trace export to:
POST https://api.frametail.io/v1/traces/otlp
Authorization: Bearer <API_KEY>
Content-Type: application/jsonThe request body is an OTLP ExportTraceServiceRequest in JSON format. Frametail parses the trace, extracts Gen AI semantics from span attributes, and stores it exactly as if you'd sent it via the SDK.
Example: OpenLLMetry with Frametail exporter
If you're using OpenLLMetry (Node.js), configure the Frametail OTLP collector:
import { NodeSDK } from '@opentelemetry/sdk-node'
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
const sdk = new NodeSDK({
instrumentations: [getNodeAutoInstrumentations()],
traceExporter: new OTLPTraceExporter({
url: 'https://api.frametail.io/v1/traces/otlp',
headers: {
authorization: `Bearer ${process.env.FRAMETAIL_API_KEY}`,
},
}),
})
sdk.start()
console.log('OpenTelemetry traces configured → Frametail')
// Your app now auto-exports tracesExample: Vercel AI SDK with OTEL telemetry
If you're using the Vercel AI SDK's built-in OpenTelemetry, point it at Frametail:
import { generateText } from 'ai'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { BasicTracerProvider, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'
const exporter = new OTLPTraceExporter({
url: 'https://api.frametail.io/v1/traces/otlp',
headers: {
authorization: `Bearer ${process.env.FRAMETAIL_API_KEY}`,
},
})
const tracerProvider = new BasicTracerProvider()
tracerProvider.addSpanProcessor(new SimpleSpanProcessor(exporter))
const tracer = tracerProvider.getTracer('my-app')
const { text } = await generateText({
model: 'openai/gpt-4o-mini',
prompt: 'Summarize: ...',
experimental_telemetry: {
isEnabled: true,
tracer,
},
})Span & attribute mapping
Frametail automatically extracts:
- Span type — Derived from
gen_ai.operation.name(e.g.,chat→llm,generate_content→compose). - Model — From
gen_ai.request.model. - Tokens — From
gen_ai.usage.input_tokensandgen_ai.usage.output_tokens. - Input/output — From
gen_ai.input.messagesandgen_ai.output.messages(JSON arrays). - Status — OTLP
status.code(0 = UNSET, 1 = OK, 2 = ERROR).
All other span attributes are preserved and available for filtering, searching, and rule-matching.
Project routing
Just as with the SDK, traces are routed to your project via your API key. Set the project in your dashboard under Settings → API Keys.
Rate limits & quotas
OTLP ingest follows the same rate limits as the JSON API:
- Standard tier: 1,000 spans/minute
- Pro tier: 10,000 spans/minute
- Enterprise: Custom
Exceeding the limit returns a 429 Too Many Requests response.
Debugging
If traces don't appear:
- Check your API key — The Authorization header must be a valid Frametail API key.
- Verify JSON validity — OTLP requests must be valid JSON with
resourceSpansandscopeSpansarrays. - Inspect the response — Frametail returns
{ traceIds: [...], spanCount: N }on success, or an error message on failure. - Check project routing — Traces go to the project associated with your API key.
Example curl to test:
curl -X POST https://api.frametail.io/v1/traces/otlp \
-H "Authorization: Bearer $FRAMETAIL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"resourceSpans": [{
"scopeSpans": [{
"spans": [{
"traceId": "abc123",
"spanId": "def456",
"name": "generate",
"startTimeUnixNano": "1718731200000000000",
"endTimeUnixNano": "1718731201000000000",
"attributes": [
{"key": "gen_ai.operation.name", "value": {"stringValue": "chat"}},
{"key": "gen_ai.request.model", "value": {"stringValue": "openai/gpt-4o"}},
{"key": "gen_ai.input.messages", "value": {"stringValue": "[{\"role\":\"user\",\"content\":\"hi\"}]"}},
{"key": "gen_ai.output.messages", "value": {"stringValue": "[{\"role\":\"assistant\",\"content\":\"hello\"}]"}}
],
"status": {"code": 1}
}]
}]
}]
}'