Skip to content

Delivery & adapters

analytics({ endpoint: '/api/ux' });
  • Events are batched. A batch is sent when it reaches batchSize events (20), after flushInterval (5 s), when the tab is hidden, and when the page is closed.
  • Sent with navigator.sendBeacon, which the browser completes even after the page unloads. If beacons aren’t available, pagepal falls back to fetch with keepalive.
  • The body is {"events": [...]} with content type text/plain, so cross-origin endpoints need no CORS preflight. Parse it as JSON on the server (examples).
  • Large batches are split to stay under the beacon size limit.
  • pagepal’s own delivery requests are never seen by its request watcher, so they don’t make the pal wait or count as failures.

send receives each batch. Pass one function or several:

analytics({
send: (events) => myQueue.push(...events),
});

A sink may return a promise. Errors, thrown or rejected, are swallowed, so a broken sink can’t break your page. endpoint and send can be used together.

import posthog from 'posthog-js';
import { analytics, toPostHog } from 'pagepal/analytics';
analytics({ send: toPostHog(posthog) });

Adapters send events named pagepal_<type> (for example pagepal_rage_click) with flat properties. The per-view view id is dropped, because those tools have their own session model. page_summary counts are flattened to counts_<type>. page_view is not forwarded, since those tools already count page views.

Combine them freely:

analytics({ endpoint: '/api/ux', send: [toPostHog(posthog), toGA4(window.gtag)] });
const ux = analytics({ endpoint: '/api/ux', batchSize: 50, flushInterval: 10_000 });
ux.flush(); // send what's queued now
ux.events(); // what this page view recorded (last 500)
ux.summary(); // summarize(ux.events())
ux.active; // false if sampled out or a privacy signal is set

Each pal owns one page view. When the pal is destroyed (a route unmounts it, or you call pal.destroy()), analytics closes the view: it records form_abandon for started forms and a page_summary, then flushes. A page restored from the back/forward cache starts a new view.

The pal in the corner is pagepal itself.