oops is live: open-source error tracking with a 4 KB SDK, an ingest API and an MCP server
oops catches the errors your apps throw β in the browser, on the server, in scripts and in AI agents β groups them into issues, tells you how many users each one affects and in which release and environment it happens, and lets you resolve or ignore them from the dashboard, the REST API or an MCP client. Here is what shipped today and how it works.
Every app throws errors its developers never see: a TypeError on a browser nobody tests on, a backend job that fails at 3 a.m., an agent whose tool call times out. oops is a small, open-source service that catches them. One project per app, a public key, and three ways to report: a browser SDK, an ingest API for anything that can send JSON, and an MCP server so AI agents can report their own failures and triage everyone else's.
It is the fifth app in the 3m4 family, built on the same stack and chrome as the URL shortener, the feature-flag service, the feedback inbox and the analytics tracker: Flask + PostgreSQL + Redis behind a Qwik City frontend, with Caddy in front and Docker Compose for self-hosting. MIT licensed, as always.
What an error becomes
Each report is an event: a type and a message, the stack (as frames or as the raw string, which the server parses for V8, Firefox / Safari and Python traceback formats), the level, the release and environment, the URL, an optional user, tags, extra JSON and up to 30 breadcrumbs. The server scrubs anything that looks like a password, token, cookie or card number, drops query strings from URLs, turns the user agent into browser / OS / device and discards it, and hashes the IP unless the project opted in to keep it.
Events are grouped into issues by fingerprint. If you send one, it wins. Otherwise the fingerprint is the error type, the message with numbers, hex blobs, UUIDs and quoted strings replaced by placeholders, and the top in-app frame β so 'User 42 not found' and 'User 43 not found' are one issue, and the same error thrown from a different function is another. Issues carry event and affected-user counts, first / last seen, the environments and the last releases they were seen in, and a per-project number (#12) for humans.
Resolve an issue and it stays resolved until a new event arrives, at which point it reopens and gets a regressed badge. Ignore an issue and it stays quiet, but keeps counting.
The browser SDK
One script tag, under 4 KB gzipped, no dependencies. It captures window.onerror and unhandled promise rejections (and console.error if you ask), keeps a ring buffer of clicks, route changes and failed fetch / XHR calls as breadcrumbs, and sends events with sendBeacon so nothing blocks the page. Identical errors within two seconds are dropped, there is a per-minute cap, and localhost pages are skipped unless you say otherwise. The public API β oops.capture, oops.message, oops.setUser, oops.setTag, oops.setContext, oops.breadcrumb β is queued before load, so you can call it from the first line of your app.
The ingest API and MCP
Backends, CLIs and cron jobs POST to /api/ingest with the project's public key. CORS is open, text/plain bodies are accepted, batches hold up to 20 events, and the answer is always 202: a project that is paused, over budget or reporting from an unlisted origin gets { ok: false, reason } rather than an error, because a failing app must never fail a second time because of its error tracker.
The MCP server exposes the whole management API as tools, filtered by the role of the API key you connect with. Ask Claude Code or any MCP host 'what broke after the 1.4 release?' or 'triage the checkout project' and it will list, inspect, resolve and ignore issues for you β or report its own failures with report_error. Destructive tools (delete a project, purge its events) ask for confirmation, and everything is audited.
Early access
The hosted version at oops.3m4.net is in early access: every account gets the enterprise limits for free β unlimited projects, events and retention, the API and the MCP server. The planned tiers are on the pricing page, and the previous post explains what will eventually sit behind them. Self-hosting is, and will stay, unlimited.
Create a project, paste the script tag, throw an error on purpose. It shows up in a second.