analytics
Session/page-view tracking, heartbeat, Web Vitals, and a business-event bus — the same data Prebit's own dashboard reads.
Boron ships two different tracking mechanisms because the two things
they track have two different trust requirements — one runs in your
app's proxy.ts, the other runs in the browser.
proxy.ts — page views and sessions
/api/store/{storeId}/track (Prebit's real, existing traffic endpoint —
the same one every Prebit storefront's dashboard reads geo/device/
referrer/UTM/session data from) is designed to be called by whatever
server owns the visitor-facing cookie, not by an arbitrary browser — it
isn't CORS-open for a third-party origin. Since a Boron app can be
hosted anywhere, that server
is your own app, in your own proxy.ts (Next.js 16's renamed
middleware.ts convention):
// proxy.ts
import { trackPageView } from "@prebit/boron/server";
export const proxy = trackPageView;
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico|api/).*)"],
};trackPageView() sets a sliding-window session cookie (sid, 30 minutes,
httpOnly — plus a sid_public non-httpOnly mirror the client-side pieces
below read), then fire-and-forgets the page-view to Prebit along with
geo-relevant headers (IP, user agent) and, on a new session only,
referrer/UTM/landing-page attribution. Never throws, never blocks the
real response.
<AnalyticsProvider> — heartbeat, Web Vitals, and page_view for adapters
Mount once, near <CartProvider>:
// app/layout.tsx
import { CartProvider, AnalyticsProvider } from "@prebit/boron/client";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<AnalyticsProvider>
<CartProvider>{children}</CartProvider>
</AnalyticsProvider>
</body>
</html>
);
}This starts three things, all direct browser calls (unlike page-view
tracking above, /heartbeat and /vitals are already CORS-enabled for
any origin, so no proxy route is needed):
- Heartbeat — a
POST /heartbeatevery 60s while the tab is visible (paused via the Page Visibility API), keeping the dashboard's live- visitor count accurate for someone who opens a page and just stays on it. - Web Vitals — LCP/INP/CLS reported via the real
web-vitalspackage,fetch(..., { keepalive: true })(deliberately notsendBeacon— it always attaches ambient cookies with no way to opt out, which turns this endpoint's uncredentialed, wildcard-CORS response into a silently blocked request). page_viewon the event bus (see below) on every route change — for third-party pixel/analytics adapters that need a client-side signal, distinct from the proxy's own page-view write.
track() / subscribe() — the business-event bus
import { track, subscribe } from "@prebit/boron/client";Auto-fired for you: product_view (from <Product>, on mount),
add_to_cart (from useCart().add), checkout_started (from
useCheckout().initiate), page_view (from <AnalyticsProvider>, on
every route change). Fire anything else yourself:
track("purchase", { event_id: order.id, value: order.total, currency: "INR", items: order.items });
track("newsletter_signup", { source: "footer" });purchase is never auto-fired
Only your own order-confirmation page knows the order actually
happened — call track('purchase', { event_id, ... }) there once
payment is confirmed. Passing event_id also gets you automatic
exactly-once dedup (via sessionStorage) so a refreshed confirmation
page can't double-count it.
subscribe(name, callback) wires up an adapter — same shape
new-frontend's embedded prebit.analytics object uses for its Meta
Pixel subscriber:
subscribe("purchase", (name, props) => {
myAnalyticsTool.log(name, props);
});Meta Pixel — built in, opt-in
Set NEXT_PUBLIC_PREBIT_META_PIXEL_ID and <AnalyticsProvider> loads the
pixel and forwards page_view → PageView and purchase → Purchase
automatically. Leave it unset and nothing pixel-related loads at all.