Server
The litetics package handles all server-side analytics work: receiving beacons, enriching them with metadata, and determining visitor uniqueness.
import { createLitetics, createPingResponse } from 'litetics';
const { handleEventRequest, handlePingRequest } = createLitetics({
persist: (data) => {
/* store load event */
},
update: ({ bid, durationMs }) => {
/* attach duration */
},
});
app.post('/event', (c) => handleEventRequest(c.req.raw).then(() => c.body(null, 204)));
app.get('/ping', (c) => handlePingRequest(c.req.raw).then(createPingResponse));Two routes, one handler instance. handleEventRequest processes POST beacons. handlePingRequest processes GET pings.
Input flexibility
Both methods accept a standard Request object, getter functions, or a pre-resolved payload. Pick whichever fits your framework:
// Request object (Hono, Workers, Bun, Deno)
handleEventRequest(c.req.raw);
// Getter functions (Nuxt Nitro, Fastify)
handleEventRequest({
getRequestBody: () => readBody(event),
getRequestHeader: (name) => getHeader(event, name),
});
// Pre-resolved payload (Express, any framework)
handleEventRequest({
requestBody: req.body,
requestHeaders: { 'user-agent': req.headers['user-agent'] },
});See the handler reference for full API details, and the integration pages for framework-specific examples.
Error Handling
The handlers do not throw on malformed input:
- Invalid JSON body → logged (if
debug: true), event dropped - Missing or invalid page URL → event dropped
- Unknown event type → logged (if
debug: true), event dropped - Bot user-agent → event dropped
persist and update errors propagate normally. Wrap with try/catch if needed.
No Storage
Litetics never stores data. You provide persist and update callbacks. Common patterns: in-memory array (dev), database insert/update, log stream, analytics platform API call, or a combination.