Browse documentation

Instrument

Python

Instrument Python services and add request-safe customer identity.

The Python SDK supports plain Python plus Django, Flask, FastAPI, Celery, standard-library logging, and opt-in HTTP client and LLM integrations.

Install and start

After the registry release:

pip install teml
# Or include a framework extra: teml[django], teml[flask], teml[fastapi], teml[celery]

During early access, use the wheel supplied during onboarding or install the source package:

pip install "teml @ git+https://github.com/getteml/teml.git@main#subdirectory=sdks/python"
import os
import teml

client = teml.TemlClient(
    api_key=os.environ['TEML_API_KEY'],
    service_name='orders-api',
)
client.start()

try:
    process_order()
except Exception as exc:
    client.capture_error(exc, tags={'component': 'checkout'})
    raise

Keep one client for the process and call client.stop() during graceful shutdown. A context manager can start and stop the client for scripts.

Use a project-scoped key with ingest:write. Add analytics:write when calling identify, group, or diagnostic-event methods, as this guide does. Do not give an application key read or management scopes.

Add framework middleware

FastAPI:

from fastapi import FastAPI
from teml import TemlClient
from teml.integrations.fastapi import TemlFastAPIMiddleware

app = FastAPI()
client = TemlClient(api_key=os.environ['TEML_API_KEY'], service_name='orders-api')
client.start()
app.add_middleware(TemlFastAPIMiddleware, client=client)

Flask uses TemlFlaskMiddleware(app, client). Django uses teml.integrations.django.TemlDjangoMiddleware in MIDDLEWARE plus a TEML settings object. Celery workers use TemlCeleryIntegration(app, client).

Framework middleware scopes identity and trace context to each request. Incoming identity baggage is ignored by default. Enable trust_incoming_identity=True only behind a gateway that strips and recreates untrusted baggage.

Scope identity safely

For a single-user process or an explicit login merge:

client.identify('user_8842', properties={'email': 'buyer@acme.example'})
client.group('company', 'acme', {'plan': 'enterprise'})
# On logout:
client.reset()

Do not switch process-wide identity per request in a concurrent server. Use middleware, or the async-safe shared identity context:

from teml import reset_context_distinct_id, set_context_distinct_id

token = set_context_distinct_id(user_id)
try:
    handle_request()
finally:
    reset_context_distinct_id(token)

Propagate only to trusted services

Install teml[http] and, when needed, teml[httpx]. Then explicitly allow the internal URL prefixes that may receive W3C trace context and customer identity:

client = TemlClient(
    api_key=os.environ['TEML_API_KEY'],
    service_name='orders-api',
    instrument_http_clients=True,
    propagate_trace_header_urls=['https://billing.internal.example'],
)

The default allowlist is empty. Calls from uninstrumented clients remain unlinked.

Logs and AI calls

Starting the client bridges standard-library logging at INFO and above by default, preserving the active trace and customer context:

import logging
logging.getLogger('orders').error('payment failed')

Use teml[openai] or teml[anthropic] for non-streaming model-call wrappers. Prompt and completion capture is opt-in.

Verify and recover

Generate one framework request for a known test customer. In Customers, confirm its trace, log, and test error appear together. If they do not, enable TEML_DEBUG=true, verify the key and project, and make sure client.stop() runs.