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",
}),
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 |
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>;
};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.
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.