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.