Browse documentation

Instrument

Identify customers

Use one stable customer identity across errors, traces, logs, replay, events, and AI calls.

Identity is what turns separate telemetry into a customer story. Teml attaches a distinct_id to each relevant signal and resolves aliases to one canonical customer at query time.

Choose a stable ID

Use an application-owned identifier that does not change when someone updates their email or display name. A database user ID is usually the right choice.

good: user_8842
avoid: buyer@acme.example

Email and name belong in customer properties. They remain searchable without becoming the primary identity key.

Identify after authentication

Call the SDK’s identify method after your application knows who the customer is.

The API key needs analytics:write for identify and group calls. If the same SDK also sends traces, logs, metrics, or errors, it needs ingest:write as well.

JavaScript / TypeScript

teml.identify('user_8842', {
  email: 'buyer@acme.example',
  plan: 'pro',
});

Python

client.identify('user_8842', properties={
    'email': 'buyer@acme.example',
    'plan': 'pro',
})

Go

if err := client.Identify(ctx, "user_8842", map[string]any{
	"email": "buyer@acme.example",
	"plan":  "pro",
}); err != nil {
	return err
}

Swift (iOS)

Teml.identify("user_8842", set: [
    "email": "buyer@acme.example",
    "plan": "pro",
])

Kotlin (Android)

Teml.identify(
    "user_8842",
    mapOf("email" to "buyer@acme.example", "plan" to "pro"),
)

React Native

await Teml.identify('user_8842', {
  email: 'buyer@acme.example',
  plan: 'pro',
});

Flutter

await Teml.identify('user_8842', set: {
  'email': 'buyer@acme.example',
  'plan': 'pro',
});

The browser and mobile SDKs keep an anonymous ID before login. Identifying a customer carries that prior ID so Teml can attach the pre-login activity to the known customer.

Reset on logout

Always reset identity when a user logs out or when a shared device changes users.

JavaScript / TypeScript

teml.reset();

Python

client.reset()

Go

if err := client.Reset(ctx); err != nil {
	return err
}

Swift (iOS)

Teml.reset()

Kotlin (Android)

Teml.reset()

React Native

await Teml.reset();

Flutter

await Teml.reset();

Resetting rotates the anonymous ID and session and clears group membership. Without it, later activity can be attributed to the previous user.

Scope identity per request on servers

A backend handles many customers concurrently. Do not switch a process-wide identity for every request. Use request context or framework middleware instead.

JavaScript / TypeScript

import { context } from '@opentelemetry/api';
import { contextWithDistinctId } from '@teml/sdk';

const requestContext = contextWithDistinctId(context.active(), user.id);
await context.with(requestContext, () => handleRequest());

Python

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)

Go

requestContext := teml.ContextWithDistinctID(r.Context(), user.ID)

The request-scoped identity should be active before creating spans, capturing errors, or writing logs.

Propagate only across trusted boundaries

Teml uses W3C traceparent and baggage to continue a trace and customer identity across services. Treat incoming baggage from the public internet as untrusted. Enable identity extraction only behind a gateway that removes client-supplied baggage and recreates it from the authenticated session.

Allow outbound propagation only to services you control. Do not send customer identity baggage to arbitrary third-party URLs.

Associate customers with accounts

For B2B applications, add group membership after identifying the customer:

JavaScript / TypeScript

teml.group('company', 'acme', { name: 'Acme Inc' });

Python

client.group('company', 'acme', {'name': 'Acme Inc'})

Go

if err := client.Group(ctx, "company", "acme", map[string]any{
	"name": "Acme Inc",
}); err != nil {
	return err
}

Swift (iOS)

Teml.group(type: "company", key: "acme", set: ["name": "Acme Inc"])

Kotlin (Android)

Teml.group("company", "acme", mapOf("name" to "Acme Inc"))

React Native

await Teml.group('company', 'acme', { name: 'Acme Inc' });

Flutter

await Teml.group('company', 'acme', set: {'name': 'Acme Inc'});

This records that the current customer belongs to the account. Use an immutable account ID for the group key and a human-readable name as a property.

Verify identity

Open Customers, search by ID or email, and confirm that the timeline contains activity from the expected browser, mobile application, and backend services. If signals are present elsewhere but missing from the timeline, follow Customer activity is not connecting.