Getting started
Capture errors from your server
Report crashes from API routes, cron jobs and background workers with glitchgrab/server
Steps checked September 12, 2026
The browser SDK only sees errors in an open tab. A cron job that fails at 3am, a webhook a payment provider rejects, or an email that times out never reaches it. glitchgrab/server sends those to the same repo, as GitHub issues, from any Node code.
Before you start
- The
glitchgrabpackage installed (see Add Glitchgrab to your Next.js app). - A
gg_token for the repo (see Create an API token). On the server it can be a normal env var — noNEXT_PUBLIC_.
GLITCHGRAB_TOKEN=gg_your_token
Report an error you caught
// app/api/cron/daily-digest/route.ts
import { reportServerError } from "glitchgrab/server";
export async function GET() {
try {
await sendDigest();
return Response.json({ ok: true });
} catch (error) {
await reportServerError(error, { context: "cron/daily-digest" });
throw error;
}
}
The issue carries the error message, the stack, the Node version and the region.
Always await it. On Vercel and other serverless hosts your function can be frozen the moment it returns; an un-awaited report dies with it and never arrives.
Report a failure that isn't a thrown error
Often the useful failure is a value — an API that answers { ok: false }:
const result = await sendWhatsApp(payload);
if (!result.success) {
await reportServerError(result.error, {
context: "whatsapp/task-reminder",
description: `Template ${payload.template} rejected`,
severity: "high",
});
}
severity must be low, medium, high or critical; it becomes a severity:<value> label on the issue.
Set the token once and catch everything
// instrumentation.ts
import { configureServerReporter, captureServerErrors } from "glitchgrab/server";
export function register() {
configureServerReporter({
token: process.env.GLITCHGRAB_TOKEN,
metadata: { service: "web" },
});
// Optional: report every uncaught exception and unhandled rejection.
captureServerErrors();
}
captureServerErrors() only watches — your process still crashes exactly as it would have. A reporter that kept a broken process alive would be worse than none.
Give every call site its own context
context decides which reports count as the same problem. Two different jobs both throwing "Timeout" stay two issues as long as their contexts differ (cron/daily-digest, cron/invoice-sync). Reuse a context and they merge.
How often you get an issue
- One issue per error per 24 hours, and nothing new for 7 days while an issue for that error is still open. A job failing every hour files one issue, not twenty-four.
- Nothing is sent in development unless you pass
enableInDevelopment: true. This is on purpose: a server sends no browser origin, so this flag is the only thing stopping a local refactor from filing real issues.
Options
| Option | What it does |
|---|---|
context | The grouping key, e.g. cron/daily-digest |
description | What the job was doing |
severity | low / medium / high / critical |
type | Report type, default BUG |
metadata | Your own key-values |
reporter | Who triggered it, when there is a person (id, name, email) |
token / baseUrl | Override GLITCHGRAB_TOKEN / GLITCHGRAB_BASE_URL |
enableInDevelopment | Send while NODE_ENV is development |
Troubleshooting
- Nothing arrives — are you in development? Is
GLITCHGRAB_TOKENset on the server that runs the job, not just locally? Did youawaitthe call? reportServerErrorreturnednull— nothing was filed: no token, development mode, or the API refused it. It never throws.- Several different failures merged into one issue — they share a
context. Give each call site its own.