Skip to content

Platform

Alerts and webhooks

Alert rules, where they’re delivered, the webhook payload and how to verify its signature.

Alerts watch your traffic so you don’t have to. Every new site starts with three rules turned on: a traffic spike, the first conversion of the day, and an error spike. There is no limit on the number of rules.

Alert rules

KindFires whenOptions
traffic_spikeVisitors are well above the usual level for this hourpercent, minVolume
traffic_dropVisitors are well below the usual levelpercent, minVolume
goal_conversionA goal converts (optionally only the first of the day)goalId, firstOfDay
eventA matching event arrives: “a visitor from news.ycombinator.com on /pricing”, “a purchase over $500”event, path, referrer, channel, country, minRevenue
error_spikeJavaScript errors are well above usualpercent, minVolume
online_thresholdOnline now crosses a numberthreshold

Each rule has a cooldown (30 minutes by default, cooldownMinutes) so a busy day doesn’t flood you, and a Send test button.

Delivery

  • Always: the notification center in the dashboard, plus browser notifications if you allow them.
  • Optionally: a webhook URL per rule. Slack and Discord webhook URLs are detected and get a formatted message; any other URL gets the JSON below.
  • Webhook URLs must point to a public address; private and loopback addresses are refused.

Webhook payload

POST to your URL · Content-Type: application/json
{
  "type": "alert.triggered",            // or "alert.test"
  "alert": { "id": "alr_…", "name": "Traffic spike", "kind": "traffic_spike" },
  "site": { "id": "SITE_ID", "name": "Acme", "domain": "acme.com" },
  "title": "Traffic spike on acme.com",
  "message": "412 visitors in the last hour, 3.1× the usual.",
  "data": { … },                         // kind-specific numbers
  "url": "https://your-globatics/app/SITE_ID",   // when GLOBATICS_PUBLIC_URL is set
  "ts": 1792631000000,
  "triggeredAt": "2026-10-21T14:23:20.000Z"
}
HeaderValue
X-Globatics-Signaturehex(HMAC-SHA256(raw body, signing secret))
X-Globatics-Eventalert.triggered or alert.test
X-Globatics-DeliveryUnique delivery id (same on retries)

Verify the signature

Each site has its own signing secret (it starts with whsec_), shown in the alerts settings and returned by GET /api/sites/:siteId/alerts. Compute the HMAC over the raw request body, before parsing it, and compare in constant time.

import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyGlobatics(rawBody: string, signature: string | null, secret: string): boolean {
  if (!signature) return false;
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(expected, "hex");
  const b = Buffer.from(signature, "hex");
  return a.length === b.length && timingSafeEqual(a, b);
}

// Next.js route handler
export async function POST(req: Request) {
  const raw = await req.text();
  if (!verifyGlobatics(raw, req.headers.get("x-globatics-signature"), process.env.GLOBATICS_WHSEC!)) {
    return new Response("Bad signature", { status: 401 });
  }
  const event = JSON.parse(raw);
  // …
  return new Response(null, { status: 204 });
}

Self-hosting

Signing secrets are derived from the server secret: GLOBATICS_SECRET when it is set, otherwise a random secret generated on first start and stored in the database. Changing it changes every site’s signing secret.

Retries and logs

  • A delivery succeeds on any 2xx response. Timeouts, network errors, 408, 429 and 5xx responses are retried 3 times with backoff (4 attempts in all).
  • Redirects aren’t followed. Answer quickly and do the work in the background.
  • Every delivery is logged with its payload, status, response code and attempts: GET /api/sites/:siteId/alerts/deliveries.