/

Feature

Opt-in traces for reliable Spectrum messaging

Ryan

No headings found on page

Start building
with Spectrum

Deploy AI agents
across every channel

Learn more about Spectrum

In the latest spectrum-ts release, we added opt-in OpenTelemetry tracing for Spectrum’s messaging layer. Developers can now enable telemetry: true to trace the receive and send path: provider initialization, inbound message receipt, space resolution, message lookup, outbound send operations, replies, edits, reactions, typing signals, attachments, voice messages, grouped messages, provider shutdown, and unsupported provider operations.

By default, those traces go to Photon’s telemetry endpoint so our developers can help debug messaging reliability issues when developer users report them. If a team wants traces in its own observability stack, it can redirect the same OpenTelemetry data to its own collector with standard OTEL_EXPORTER_OTLP_* environment variables.

This release is not about tracing the whole agent. It does not trace model execution, prompts, tool calls, reasoning, or application business logic. It is focused on the messaging infrastructure that Spectrum owns: did we receive the message, resolve the conversation, send the response, and keep that path stable?

Why we added messaging traces

Reliability is the most important part of messaging infrastructure. If a developer builds an agent on Spectrum, the basic expectation is simple: when a user sends a message, Spectrum should receive it, route it through the right provider path, and send the response back without silently breaking.

Spectrum sits between developer applications and messaging providers. That position is useful because it gives developers one SDK surface for receiving messages, resolving conversations, and sending responses, but it also means reliability depends on many moving parts that do not always fail in obvious ways.

A provider client might fail during setup. An inbound message might not reach Spectrum. A send operation might fail after the developer’s app has already decided what to reply with. A provider might reject or ignore a content type. A message lookup might return nothing. From the outside, many of these failures look the same: the agent did not respond, or the message did not behave the way the developer expected.

We can and should test those paths internally, but internal tests cannot cover every provider state, user environment, network condition, deployment setup, and real production conversation shape. Traces give us a way to understand what happened when a real developer hits a real messaging issue.

What internal tests cannot cover

Internal testing is still the first line of defense. It helps us catch regressions, validate provider behavior, and make sure the common receive and send paths work before a release goes out.

The problem is that messaging infrastructure has a long tail. A developer may run Spectrum with a different deployment setup, a different provider configuration, different traffic patterns, or a sequence of events that never appears in our test suite. A provider can also behave differently depending on account state, platform capabilities, message type, or timing.

That is why tracing matters. It gives Photon and the developer a shared timeline for the messaging path when something happens outside the cases we already covered. Instead of guessing where the receive or send pipeline broke, we can inspect the operation sequence and narrow the issue down quickly.

What this traces, and what it does not trace

This support is scoped to Spectrum’s messaging layer.

It traces SDK and provider operations such as:

  • Spectrum initialization

  • Provider client creation and shutdown

  • Inbound message receive

  • Space or conversation resolution

  • Message send

  • Message lookup with getMessage

  • Reply, edit, reaction, typing, attachment, voice, and grouped-message operations where applicable

  • Unsupported provider operations

It does not mean Spectrum traces the agent’s reasoning, tool calls, model execution, prompts, or business logic inside the developer’s application. If a developer wants visibility into those parts, they can add their own OpenTelemetry instrumentation around their own code.

That boundary is important. Spectrum’s tracing is meant to answer a focused reliability question: did the messaging infrastructure receive, resolve, and send correctly?

How to enable Photon support traces

Telemetry is off by default. Developers opt in by passing telemetry: true when creating the Spectrum app.

import { Spectrum } from "spectrum-ts";
import { imessage } from "spectrum-ts/providers/imessage";

const app = await Spectrum({
	projectId: process.env.PROJECT_ID,
	projectSecret: process.env.PROJECT_SECRET,
	providers: [imessage.config()],
	telemetry: true,
});
import { Spectrum } from "spectrum-ts";
import { imessage } from "spectrum-ts/providers/imessage";

const app = await Spectrum({
	projectId: process.env.PROJECT_ID,
	projectSecret: process.env.PROJECT_SECRET,
	providers: [imessage.config()],
	telemetry: true,
});
import { Spectrum } from "spectrum-ts";
import { imessage } from "spectrum-ts/providers/imessage";

const app = await Spectrum({
	projectId: process.env.PROJECT_ID,
	projectSecret: process.env.PROJECT_SECRET,
	providers: [imessage.config()],
	telemetry: true,
});

With this configuration, Spectrum sends messaging-layer telemetry to Photon’s telemetry endpoint using the project credentials in the app configuration. Developers do not get a built-in dashboard from telemetry: true; this path exists so Photon’s developers can debug messaging reliability issues for developer users when they ask for help.

This is useful during support because it avoids the slowest version of debugging: asking the developer to add temporary logs, reproduce an intermittent issue, and manually paste output back to us. The trace can show whether Spectrum initialized the provider client, received the inbound message, resolved the conversation, attempted to send a response, or stopped somewhere along that path.

When telemetry is not enabled, Spectrum does not initialize the OTLP exporter. Existing apps keep running without exporting traces.

How to redirect traces to your own collector

Some teams want to inspect traces in their own observability stack instead of sending them to Photon. Spectrum supports that too.

Because the implementation uses OpenTelemetry, developers can configure standard OTLP environment variables to redirect telemetry to their own OpenTelemetry-compatible collector or backend.

export OTEL_EXPORTER_OTLP_ENDPOINT="<https://otel-collector.example.com>"
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer ${OTEL_TOKEN}"
export OTEL_EXPORTER_OTLP_ENDPOINT="<https://otel-collector.example.com>"
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer ${OTEL_TOKEN}"
export OTEL_EXPORTER_OTLP_ENDPOINT="<https://otel-collector.example.com>"
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer ${OTEL_TOKEN}"

The Spectrum app can still use the same opt-in flag:

const app = await Spectrum({
	projectId: process.env.PROJECT_ID,
	projectSecret: process.env.PROJECT_SECRET,
	providers: [imessage.config()],
	telemetry: true,
});
const app = await Spectrum({
	projectId: process.env.PROJECT_ID,
	projectSecret: process.env.PROJECT_SECRET,
	providers: [imessage.config()],
	telemetry: true,
});
const app = await Spectrum({
	projectId: process.env.PROJECT_ID,
	projectSecret: process.env.PROJECT_SECRET,
	providers: [imessage.config()],
	telemetry: true,
});

In that setup, the developer controls where the traces go. Photon’s default endpoint is there for support and reliability debugging, but teams that already run OpenTelemetry can route the same messaging-layer traces into their own collector.

What Spectrum records

Spectrum records operational metadata that helps debug the messaging path without turning traces into copies of user conversations.

Area

What the trace can show

Provider

Which provider handled the operation

Message flow

Whether Spectrum received, looked up, or sent a message

Space

The space or conversation identifier where available

Content type

Whether the operation involved reply, edit, reaction, typing, attachment, voice, group, or another content type

Provider support

Whether an operation was unsupported for the current provider

Attachments and voice

Metadata such as MIME type, size, or duration where relevant

Sender

Sanitized sender identifier and sender kind when available

This is enough to answer practical stability questions: did the provider client start, did Spectrum receive the inbound message, did the app ask Spectrum to send something, did the provider accept that send, and did Spectrum shut down cleanly?

Privacy boundaries

The tracing is designed with a strict privacy boundary. Spectrum does not export message bodies as trace attributes. It records the type of content being handled and selected operational metadata around the messaging operation, not the text of the conversation.

Phone numbers and email addresses are sanitized before they are attached as sender identifiers. When Spectrum can identify a sender as a phone number or email address, it records a sanitized value and a kind such as phone or email, rather than exporting the raw contact detail.

This keeps traces useful for reliability work while avoiding the most sensitive parts of messaging: conversation content and direct contact identifiers.

How this improves reliability

The goal is not to collect telemetry for its own sake. The goal is to make Spectrum’s messaging infrastructure more reliable over time.

When a developer opts in and reports an issue, the trace can help Photon find where the receive or send pipeline broke. If the problem is in Spectrum, we can fix it with much better context. If the problem is in a provider-specific edge case, we can identify that faster. If the trace reaches the handoff point where the developer’s own application logic takes over, that is useful too, because it narrows the problem instead of leaving everyone guessing.

Over time, these real-world traces help us see the cases our internal tests missed. That makes the next fix more precise, the next regression test more useful, and the messaging layer more stable for every developer building on Spectrum.

Try it

Upgrade to the latest version of spectrum-ts that includes OpenTelemetry support, then enable telemetry in your Spectrum configuration:

const app = await Spectrum({
	projectId: process.env.PROJECT_ID,
	projectSecret: process.env.PROJECT_SECRET,
	providers: [imessage.config()],
	telemetry: true,
});
const app = await Spectrum({
	projectId: process.env.PROJECT_ID,
	projectSecret: process.env.PROJECT_SECRET,
	providers: [imessage.config()],
	telemetry: true,
});
const app = await Spectrum({
	projectId: process.env.PROJECT_ID,
	projectSecret: process.env.PROJECT_SECRET,
	providers: [imessage.config()],
	telemetry: true,
});

Use the default Photon telemetry path when you want Photon’s engineering team to help investigate a messaging reliability issue. If you want the traces in your own observability stack, set the standard OTLP environment variables before starting the app.

Get started

  • Read the source and latest release details in the Spectrum GitHub repo.

  • Open the Photon dashboard to create your first iMessage agent project.

  • If you hit a messaging reliability issue after opting in, share the project context with Photon so our engineering team can inspect the receive and send trace.


Subscribe Photon Newsletter

Subscribe
Photon Newsletter