Browser Setup
For Cloudflare and browsers, the simplest setup is Effect's lightweight OTLP
exporter from effect/unstable/observability. It works with FetchHttpClient
and does not require the Node OpenTelemetry SDK.
pnpm add effectIf you want to use the official OpenTelemetry JavaScript SDK in a browser or
Node process, add @effect/opentelemetry and the relevant OpenTelemetry
packages instead. The rest of this guide uses Effect's built-in OTLP layer
because it fits Workers and browser runtimes directly.
Configure the client runtime
Add an OTLP layer to the same runtime that provides your Liminal client.
Browsers usually send OTLP through a same-origin proxy. See Collectors for CORS and credential guidance.
// app/runtime.ts
import { BrowserSocket } from "@effect/platform-browser"
import { Layer } from "effect"
import { FetchHttpClient } from "effect/unstable/http"
import { Otlp } from "effect/unstable/observability"
import { Atom } from "effect/unstable/reactivity"
import { Client } from "liminal"
import { TicTacToeClient } from "./TicTacToeClient.ts"
import * as State from "./State.ts"
const TelemetryLive = Otlp.layerJson({
baseUrl: "/otel",
resource: {
serviceName: "tic-tac-toe-web",
attributes: {
"deployment.environment": import.meta.env.MODE,
},
},
tracerExportInterval: "1 second",
loggerExportInterval: "1 second",
}).pipe(Layer.provide(FetchHttpClient.layer))
export const runtime = Atom.runtime(
State.layer.pipe(
Layer.provideMerge(
Client.layerSocket({
client: TicTacToeClient,
url: "/play",
replay: { mode: "startup" },
}).pipe(Layer.provide(BrowserSocket.layerWebSocketConstructor)),
),
Layer.provideMerge(TelemetryLive),
),
)That is enough for client acquire/listen/send/call spans, client logs, outbound
method-call trace envelopes, and inbound event enqueue spans. Those enqueue
spans cover Liminal receiving an event and publishing it into Client.events;
downstream stream consumers should add their own application spans when needed.