Client
The @blyp/core/client entry gives you two major capabilities:
- browser logging with optional remote sync
- browser-safe error parsing with
parseError() - connector requests for PostHog, Sentry, or named OTLP targets through Blyp ingestion
For Expo apps, use the dedicated @blyp/core/expo logger instead of @blyp/core/client.
createClientLogger()
import { createClientLogger } from "@blyp/core/client";
const logger = createClientLogger({
endpoint: "/inngest",
credentials: "same-origin",
metadata: () => ({
app: "dashboard",
release: "2026.03.10",
}),
traceId: "trace_123",
delivery: {
maxRetries: 3,
retryDelayMs: 5000,
},
});
logger.info("hydrated", { route: window.location.pathname });
logger.error(new Error("button failed to render"));
logger.child({ feature: "checkout" }).warn("client validation failed");When to use it
Use the browser client when you want Blyp to:
- mirror logs to the browser console during development
- forward browser events to your backend ingestion endpoint
- buffer transient failures and retry when connectivity returns
- turn failed
fetch()responses into structuredBlypErrorinstances
If your app only needs local browser logging and no remote sync, disable remoteSync.
const logger = createClientLogger({
endpoint: "/inngest",
remoteSync: false,
});Defaults
| Option | Default |
|---|---|
endpoint | /inngest |
credentials | "same-origin" |
localConsole | true |
remoteSync | true |
traceId | not set |
delivery.maxRetries | 3 |
delivery.retryDelayMs | 5000 |
delivery.maxQueueSize | 100 |
Delivery behavior
Remote browser delivery is managed by a shared in-memory dispatcher:
- failed events are queued in memory
- retryable failures are retried up to
3times by default - the default retry delay is
5000ms - the queue keeps at most
100pending events - when the queue is full, Blyp drops the oldest queued item
- child loggers reuse the same dispatcher instead of creating separate queues
- when the browser comes back online, Blyp resumes queued delivery automatically
Retryable failures are:
- offline browser state
- network errors
- HTTP
429 - HTTP
5xx
Non-retryable response failures, such as 400, fail immediately and trigger terminal failure handling.
If you do not set custom headers, the client logger still uses navigator.sendBeacon() as a last-chance fallback when fetch(..., { keepalive: true }) fails.
Delivery hooks
Use delivery to customize retry policy and observe outcomes:
const logger = createClientLogger({
delivery: {
maxRetries: 3,
retryDelayMs: 5000,
maxQueueSize: 100,
warnOnFailure: true,
onRetry: (ctx) => {
console.log("retrying", ctx.attempt, ctx.retriesRemaining);
},
onSuccess: (ctx) => {
console.log("delivered via", ctx.transport);
},
onFailure: (ctx) => {
console.error("terminal delivery failure", ctx.reason, ctx.status);
},
onDrop: (ctx) => {
console.warn("dropped", ctx.droppedEvent.message, "for", ctx.replacementEvent.message);
},
},
});Hook context highlights
onRetry: receivesattempt,retriesRemaining,nextRetryAt,reason,status, anderroronSuccess: receivesattempt,status, andtransport("fetch"or"beacon")onFailure: receives the terminalreason, plusstatusorerrorwhen availableonDrop: fires when queue overflow forces Blyp to evict the oldest queued event
Event shape
Client events are normalized into a ClientLogEvent shape:
type ClientLogEvent = {
type: "client_log";
source: "client";
id: string;
level: "debug" | "info" | "warning" | "error" | "critical" | "success" | "table";
message: string;
data?: unknown;
bindings?: Record<string, unknown>;
clientTimestamp: string;
page: ClientLogPageContext;
browser: ClientLogBrowserContext;
device?: ClientLogDeviceContext;
session: { pageId: string; sessionId: string };
metadata?: Record<string, unknown>;
traceId?: string;
};Browser error parsing
import { parseError } from "@blyp/core/client";
const response = await fetch("/api/payments", { method: "POST" });
if (!response.ok) {
throw await parseError(response);
}See Parse Error for server and browser parsing patterns in more detail.
Pairing with server adapters
Most server-side adapters automatically register or expose a handler for the configured client ingestion path:
- programmatic server adapters auto-register
POST /inngest - file-based integrations expose a handler helper you mount yourself
- ingested events are tagged as
type: "client_log"andsource: "client"
See the individual pages under Integrations for exact mounting patterns.
Joining a server trace
If your frontend wants its browser logs to join the same trace as the server request that rendered or handled it, pass the server response header through to the client logger:
const response = await fetch("/api/session");
const traceId = response.headers.get("x-blyp-trace-id") ?? undefined;
const logger = createClientLogger({
endpoint: "/inngest",
traceId,
});
logger.info("session hydrated");This is optional for standalone browser logs. Use it when you want browser-originated logs, connector-forwarded logs, and database records to share the same correlation ID.
Connector forwarding requests
The browser client can ask Blyp ingestion to forward logs into a configured connector:
const posthogLogger = createClientLogger({
endpoint: "/inngest",
connector: "posthog",
});
const sentryLogger = createClientLogger({
endpoint: "/inngest",
connector: "sentry",
});
const otlpLogger = createClientLogger({
endpoint: "/inngest",
connector: { type: "otlp", name: "grafana" },
});Important behavior:
- the browser still posts to Blyp first
- Blyp forwards only when the matching server connector is configured
- Blyp warns once if the requested connector is missing on the server
- PostHog client
errorandcriticallogs are promoted into Error Tracking only when server-side PostHog error tracking runs inautomode
Use Connectors for the server-side setup behind these requests.
Expo mobile logging
Expo has its own logger because it does not run in a browser environment and cannot rely on same-origin delivery.
import { createExpoLogger } from "@blyp/core/expo";
const logger = createExpoLogger({
endpoint: "https://api.example.com/inngest",
metadata: () => ({
app: "mobile",
}),
delivery: {
maxRetries: 3,
retryDelayMs: 5000,
},
});Use Expo for the full mobile setup and its delivery constraints.