Install

deno add jsr:@uri/anomalisa

Or import directly from JSR:

import { sendEvent, getAnomalies } from "jsr:@uri/anomalisa";

sendEvent

Records an event. The server builds a statistical model from your events and emails you when something looks anomalous.

await sendEvent({ token: "your-project-token", userId: "user-123", eventName: "purchase", });
Field Type Description
token string Your project token from the dashboard
userId string Identifies the user performing the action
eventName string Name of the event (e.g. "signup", "purchase")

Returns an empty object. Anomaly detection and alerting happen server-side.

getAnomalies

Fetches all detected anomalies for a project. Anomalies are kept for 30 days.

const { anomalies } = await getAnomalies({ token: "your-project-token" });

Each anomaly has:

Field Type Description
eventName string The event that spiked
metric "totalCount" | "userSpike" | "percentageSpike" Type of anomaly detected
userId string? Present when metric is "userSpike"
bucket string The hourly bucket (ISO timestamp)
expected number Running mean for this event
actual number Observed count in this bucket
zScore number Standard deviations from mean (totalCount/userSpike) or percentage change (percentageSpike)
detectedAt string ISO timestamp of detection

How detection works

Events are counted in hourly buckets. The server maintains a running mean and variance per event using Welford's online algorithm. When a bucket's count deviates by more than 2 standard deviations, it's flagged as an anomaly and you get an email.

Three things are tracked independently:

Total count (z-score) -- the total number of times an event fires per hour across all users. Fires when count is more than 2 standard deviations from the mean.

Percentage spike -- fires when hourly count more than doubles compared to the rolling mean (and the absolute difference is at least 3). Catches gradual increases that z-score misses in noisy data.

Per-user spikes -- each user's hourly event count is compared against that user's historical pattern.