Zero-config statistical anomaly alerts via email

anomalisa

Send events, get emailed when something weird happens. No dashboards to stare at. No thresholds to configure. Just statistics and email.

You're shipping fast. Multiple projects, lots of moving parts. Something breaks or spikes at 2am and you find out the next morning from a user complaint. Anomalisa watches your event streams and notifies you the moment the distribution breaks.
$ npx jsr add @uri/anomalisa

Three lines to get started

Install the client SDK, import sendEvent, and send your key business events. No configuration files, no metric schemas.

// 1. Install package
// npx jsr add @uri/anomalisa

import { sendEvent } from "@uri/anomalisa";

await sendEvent({
  token: "your-project-token",
  userId: "user-123",
  eventName: "purchase",
});
Automatic frontend error tracking
import { captureClientErrors } from "@uri/anomalisa";

// Listens to window.onerror and unhandledrejection
// Automatically filters out browser extensions, DOMExceptions, and ResizeObserver loops
captureClientErrors({
  token: "your-project-token",
  userId: "user-123",
});

Built for engineers shipping products

Traditional monitoring forces you to maintain alerts that decay as your traffic scales. Anomalisa adapts automatically.

Event spike detection
Your signup event usually gets ~50/hour. Suddenly it's 200. Or 3. You get an email. Catches unexpected outages and surprise spikes.
Per-user anomalies
One user generating 100x more events than usual. Could be a bot, abuse, or an infinite retry loop in their client. You'll know.
Zero configuration
It learns what's normal from your data using Welford's online algorithm. Stays quiet until the math says something is genuinely off.
Open source
Run it yourself, fork it, rip it apart. Or just use the hosted version and move on with your life. MIT licensed with zero locks.

How does this actually work?

Most anomaly detection tools want you to set thresholds. "Alert me if signups drop below 40 per hour." That means you need to already know what normal looks like, which defeats the purpose.

Anomalisa uses Welford's online algorithm to maintain a running mean and variance from your data. Three numbers in memory: count, mean, and sum of squared deviations. Each hour, the event count gets fed into the model. If the new count is more than 2 standard deviations from the running mean, you get an email. That's it.

No batch jobs, no time-series database. The model updates incrementally with constant memory and stays numerically stable even over millions of updates.

totalCount

Total count anomalies

Your signup event usually gets ~50/hour, suddenly it's 200 or 3. Works in both directions, catches drops as well as spikes.

percentageSpike

Percentage spike detection

Errors go from 2% to 30% of your traffic while total volume stays flat. Absolute counts look fine, but the ratio is off.

userSpike

Per-user spike detection

One user generating 100x their normal volume. Could be a bot, abuse, or a bug in their integration.

Event processing pipeline
App (sendEvent) → API Gateway → Welford Engine [n, μ, M2] → Key-Value Store → Email / Webhook (z > 2)

The entire storage layer is a key-value store. Event counts in hourly buckets with a 7-day TTL, three Welford states per event name, detected anomalies with a 30-day TTL. No relational queries, no migrations. TTLs handle cleanup. The detection engine is one file you can read in five minutes.

The honest engineering reality: It won't catch everything. If your system fails in a way that doesn't affect event counts, you're on your own. But most real failures do show up as something spiking or dropping, and the simplicity means there's almost nothing to debug.

Deeper technical writeup: anomaly detection with nothing but math and a key-value store

Self-host in 60 seconds

No vendor lock-in. Run the identical stack on your own servers or cloud infrastructure.

Terminal setup
# 1. Clone repository
git clone https://github.com/uriva/anomalisa.git
cd anomalisa

# 2. Configure credentials in .env
# DATABASE_URL=...
# DATABASE_AUTH_TOKEN=...
# EMAIL_API_KEY=...

# 3. Run server locally
deno run --allow-net --allow-env --allow-read src/server.ts

Simple, transparent pricing

Start free without a credit card. Generous limits designed for developers shipping real projects.

Free

$0 / month

Generous free tier for side projects, indie hackers, and early prototypes.

  • 100,000 events / month
  • Unlimited projects and tokens
  • Instant email alerts
  • Webhook notifications
  • 7-day hourly counts retention
  • 30-day anomaly history
  • Frontend error tracking SDK
Get started free

Self-Hosted

Free / MIT License

Run Anomalisa on your own servers and infrastructure.

  • Unlimited events and projects
  • Full source code available
  • Deploy to any cloud or VPS
  • Zero vendor lock-in
  • Custom database retention policies
  • Custom email provider integration
  • Community support on GitHub
View on GitHub

Common developer questions

How does cold-start work?
Anomalisa requires 3 hourly data points before statistical detection activates. During these initial hours, baseline data is collected quietly to avoid alerting on empty or incomplete baselines.
Does sendEvent block my application?
No. sendEvent makes an asynchronous HTTP call with automatic retries. If the network or tracking endpoint fails, your business logic continues uninterrupted.
What data do you store?
Only hourly integer counts, Welford state variables (count, mean, variance), and anonymized user tokens. No event payloads, no request bodies, and no PII are stored.
How do you prevent email spam during an outage?
Anomalisa incorporates directional cooldown timers and trend detection. If an event stays in an anomalous state across multiple consecutive hours without escalating, repetitive alerts are suppressed.

Start catching anomalies before your users complain

Create a project in 10 seconds. Copy your token, send one event, and let the statistics do the monitoring for you.