Skip to Content
Product

Alerts

What an alert is

An alert isn’t a new kind of data — it’s the diff on top of the runs you already have. Every time a dimension checks in, CompetLab compares the fresh reading to the previous one and, when the two differ enough to matter, turns that gap into a short, readable note. So the same run that updates a dashboard can also reach you the moment it lands, without you sitting on the page.

Each alert is built to be understood at a glance, not decoded:

What you seeWhat it means
SeverityHow much this deserves your attention right now — from a heads-up to a drop-everything.
Dimension & competitorWhich of the five things CompetLab watches moved, and for which rival.
What changedA plain-language line — “a rival added 8 landing pages” — not a raw before/after dump.
Why it mattersThe “so what”: how the change lands against your own position.
Suggested next stepOften a concrete move to make, when there’s an obvious one.
The underlying changesAn expandable view of the exact differences the alert was raised from.

The “why it matters” line is the part that makes an alert worth reading. A competitor cutting a price is a fact; you’re now the most expensive option in the market is the reason you’d act on it. CompetLab writes that second sentence for you.

What an alert looks like

A few alerts from a single day read something like this — the severity marker, the dimension and who it’s about, the change in plain words, and the “so what” that follows:

alerts · grouped by dateillustrative
● critical pricing Rival A dropped its entry tier 20% you’re now the most expensive option in the field
● high content a rival added 8 comparison pages you have none for that use case
● medium ai visibility you moved from unranked to #3 on Claude
└ each row expands to the exact changes it was raised from

Because every alert links back to the run it came from, the expandable view underneath a row is the real evidence — the specific pages, prices, or ranks that moved — not a paraphrase. You read the headline, and drill down only when you want the receipts.

How urgent it is

Every alert carries one of four severity levels, so a genuine threat and a routine tick never look the same in the list:

CriticalHighMediumInfo

Severity is also what your notification channels filter on: you can tell a channel to only speak up at High and above and leave the quieter movements to the in-app list. That keeps the signal where you want it loud and the noise where you can scan it later.

Getting them where you work

Alerts live in the app, but they don’t have to stay there. Route them to any of four channels, and give each one its own severity threshold — the floor it fires at — and its own delivery frequency, so an urgent Slack ping and a tidy weekly email can run side by side off the same alerts. Not every channel offers every cadence — email is digest-only, and a webhook fires immediately (see the table).

ChannelWhat it isYou control
EmailAlerts delivered to your inbox.Severity threshold · daily or weekly digest
SlackAlerts posted into a Slack workspace.Severity threshold · immediate, daily, or weekly digest
TelegramAlerts sent to a Telegram chat.Severity threshold · immediate, daily, or weekly digest
WebhookAlerts POSTed to a URL you own, to wire into your own tools.Severity threshold · immediate only

The pairing is the point: a channel set to Critical + immediate interrupts you only for the things that can’t wait, while the same account’s Info + weekly channel gives you a calm Monday-morning recap of everything else. Set the threshold high and the frequency low, and a channel goes quiet without going dark.

Reading and filtering the list

In the app, alerts are grouped by date so the newest movement sits on top and you can see a day’s worth of change together. Three filters narrow the view: by dimension, to focus on just pricing or just content; by competitor, to follow one rival’s moves; and by severity, to pull only the critical ones to the front. The same filters are available on the Alerts API if you’d rather query them from code.

Alerts are raised on the schedule each dimension already runs on — turning dimensions on or off and setting their cadence is covered in How monitoring works, not here. This page is about what an alert is and where it goes once it’s raised.

Wiring up a webhook

The webhook channel turns alerts into an HTTP feed you can pipe into anything — a bot you built, an incident tool, a queue, an n8n flow. Add a URL in your project’s notification settings, give it a severity threshold, and CompetLab POSTs to it the moment a monitoring run raises alerts that clear the bar. It’s immediate-only — there’s no digest for webhooks.

The payload. Each delivery is a single application/json POST. One request carries all the alerts from one dimension’s run, under a small envelope:

{ "version": 2, "event": "alerts.created", "timestamp": "2026-07-11T14:05:00.000Z", "projectId": "65a1b2c3d4e5f6a7b8c9d0e1", "projectName": "Acme", "organizationId": "65a1b2c3d4e5f6a7b8c9d0e2", "runId": "65a1b2c3d4e5f6a7b8c9d0e3", "dimension": "ai-visibility", "alerts": [ { "id": "65a1b2c3d4e5f6a7b8c9d0e4", "severity": "medium", "title": "Your AI Visibility Score on Claude rose from 0 to 72", "actionHint": "Reinforce the pages that lifted you — they're working.", "competitorDomain": "acme.com", "alertType": null, "gapWarnings": [], "context": { "ai-visibility": { "scoreFrom": 0, "scoreTo": 72 } }, "createdAt": "2026-07-11T14:05:00.000Z" } ] }

dimension is the canonical slug — one of ai-visibility, positioning, pricing, content, or tech-trust — and each alert’s context is keyed by that same slug, carrying the dimension-specific before/after figures the alert was raised from (the same numbers you see when you expand the alert in the app). severity is one of critical, high, medium, or info; alertType and createdAt may be null, and gapWarnings is always an array. There’s no top-level message or deep-link field — the human-readable text is title plus actionHint.

Verifying it’s really from CompetLab. Set a signing secret on the channel and every request carries an X-CompetLab-Signature-256 header — sha256= followed by the HMAC-SHA256 of the raw request body, keyed by your secret. Recompute it over the untouched body and compare before you trust a payload:

import crypto from 'node:crypto' function isFromCompetLab(rawBody, signatureHeader, secret) { const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex') return crypto.timingSafeEqual(Buffer.from(signatureHeader), Buffer.from(expected)) }

If your receiver authenticates a different way, you can instead set a custom header (say X-API-Key) that CompetLab sends verbatim with each request.

Delivery. CompetLab waits up to 10 seconds for a 2xx, and retries a failed delivery up to three times with a 1s / 2s / 4s backoff. A 400, 403, 404, or 410 reads as a permanent misconfiguration — no retry, and the channel is switched off with the error recorded, so you can fix the endpoint and turn it back on. Delivery is best-effort and at-most-once: alerts raised while a channel is off aren’t replayed when you re-enable it, so treat the webhook as a live feed, not a system of record — the Alerts API is there when you need to reconcile the full list.

Work with it in code

Every alert is available programmatically — the same list the app renders, with the same filters.

FAQ

What triggers an alert?

A meaningful difference between one check and the one before it. Every time a monitored dimension runs, CompetLab compares the fresh reading to the last stored one, and when the gap is big enough to matter it raises an alert. That means alerts ride on the same runs the dashboards use — they're the diff layer on top of your history, not a separate scan. A rival cutting a price, adding a batch of pages, reworking its messaging, changing its tech or trust signals, or your own rank shifting on one of the AI engines can all set one off. Small, routine wobble doesn't; the point is to surface the moves worth a second look, not every byte that changed.

What do the severity levels mean?

There are four: Critical, High, Medium, and Info. They rank how much attention an alert deserves right now, so a real competitive threat and a minor tick don't look identical in the list. Critical is the drop-everything end — a change that moves your standing in the market; Info is the quiet, for-the-record end. Severity does double duty: it sorts the in-app list, and it's the dial your notification channels filter on, so you can tell a channel to only speak up at High and above. That way the urgent things interrupt you and the rest wait in the app until you go looking.

Where can alerts be sent?

Four places: email, Slack, Telegram, and a webhook. Email, Slack, and Telegram deliver a readable alert to an inbox or chat; the webhook POSTs to a URL you own so you can pipe alerts into your own tooling. Each channel is independent — you can run all four, or just one. What makes them useful rather than noisy is that every channel has its own severity threshold and its own delivery frequency, so an interrupt-me Slack channel and a weekly summary email can both draw from the same stream of alerts without stepping on each other. You configure channels in the project's settings.

How do I keep alerts from becoming noise?

Two controls per channel: the severity threshold and the digest frequency. Raise the threshold and a channel only fires for the alerts that clear it — set Slack to High and above and the Medium and Info movements stay in the app where you can scan them at your own pace. Lower the frequency and a channel batches what it does send: an immediate channel pings you the moment an alert lands, a daily or weekly one collects them into a single digest. Combine the two — a high threshold with a weekly digest — and a channel goes calm without going silent. Most people run one loud, high-threshold channel and one quiet, catch-all one.

Can I filter which alerts I see?

Yes. In the app, alerts are grouped by date and can be narrowed three ways: by dimension, so you see only pricing or only content; by competitor, so you can follow a single rival's moves; and by severity, so you can pull the critical ones to the top. The three filters combine, so "critical pricing alerts about one rival" is a single view. The same filters exist on the Alerts API, which returns the list as JSON — handy if you want to build your own dashboard or feed alerts into another system rather than reading them in CompetLab.

How is an alert different from the run it came from?

A run is a full measurement of a dimension — the current state of every competitor, stored as history. An alert is the change between two runs, written up in plain language. So the run tells you where things stand; the alert tells you what just moved and why you'd care. They're never in conflict, because the alert is derived from the runs, not gathered separately — each alert links back to the exact run it was raised from, and its expandable view shows the specific differences. If you want the whole picture, you read the dimension's dashboard; if you want to know what changed since last time, you read the alert.

Last updated on