Skip to main content

OpenTelemetry

Fact0 is OpenTelemetry native. Any application that exports OTLP traces can send them to Fact0 with zero code changes - just set two environment variables.
Fact0 accepts both OTLP/gRPC (port 4317) and OTLP/HTTP. GenAI semantic conventions are automatically enriched into structured model invocation details.

Quick start

1. Configure your OTel SDK

Set the OTLP exporter to point at your Fact0 API:
# OTLP/gRPC (default for most SDKs)
export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.fact0.io:4317
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer f0_live_xxxx"

# Or OTLP/HTTP
export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.fact0.io/v1/otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer f0_live_xxxx"
That’s it. Your existing OTel instrumentation starts flowing into Fact0 immediately.

2. Python example

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanExporter
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter

# Standard OTel setup - no Fact0-specific code
provider = TracerProvider()
exporter = OTLPSpanExporter(
    endpoint="https://api.fact0.io:4317",
    headers={"authorization": "Bearer f0_live_xxxx"},
)
provider.add_span_processor(BatchSpanExporter(exporter))
trace.set_tracer_provider(provider)

tracer = trace.get_tracer("my-agent")

with tracer.start_as_current_span("process-request") as span:
    span.set_attribute("gen_ai.system", "openai")
    span.set_attribute("gen_ai.request.model", "gpt-4")
    # ... your agent logic ...
    span.set_attribute("gen_ai.usage.prompt_tokens", 150)
    span.set_attribute("gen_ai.usage.completion_tokens", 200)

3. OTel Collector config

If you run an OTel Collector, add Fact0 as an exporter:
exporters:
  otlp/fact0:
    endpoint: "api.fact0.io:4317"
    headers:
      authorization: "Bearer f0_live_xxxx"

service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [otlp/fact0]

How it works

Automatic translation

Fact0 translates OTel traces into its native domain model:
OTel conceptFact0 concept
Trace (traceId)Execution
SpanSpan
service.name resource attributeAgent ID
Span statusExecution / span status

Smart span classification

Fact0 automatically classifies spans based on OTel semantic conventions:
OTel attributesFact0 span type
gen_ai.system, gen_ai.request.modelMODEL_INVOCATION
tool.nameTOOL_CALL
db.system, db.statementTOOL_CALL (database)
http.request.method, url.fullTOOL_CALL (HTTP)
fact0.span_type (explicit)Whatever you set

GenAI enrichment

When GenAI semantic conventions are present, Fact0 extracts structured details:
  • Model info: gen_ai.system, gen_ai.request.model
  • Token usage: gen_ai.usage.prompt_tokens, gen_ai.usage.completion_tokens
  • Parameters: gen_ai.request.temperature, gen_ai.request.max_tokens
  • Prompts/completions: Extracted from gen_ai.content.prompt and gen_ai.content.completion span events

Exception enrichment

OTel exception events (exception.type, exception.message, exception.stacktrace) are automatically extracted into Fact0’s error detail panel with full stack traces.

Custom span types

You can explicitly set the Fact0 span type using a custom attribute:
span.set_attribute("fact0.span_type", "HUMAN_APPROVAL")
Supported values: TOOL_CALL, MODEL_INVOCATION, STATE_MUTATION, HUMAN_APPROVAL, POLICY_EVALUATION.

OTel vs Fact0 SDK

CapabilityOTelFact0 SDK
Basic trace ingestion
GenAI enrichment
Universal fact layer · tamper-evident hash chains
Human-in-the-loop approvals
Policy evaluation results
Security evidence export
Execution replay
Start with OTel in 30 seconds. Graduate to the Fact0 SDK when you need governance-grade audit trails that OTel can’t express.