All documentation

Alerts

A daily watch on your visibility that raises an alert when something moves enough to be worth reading, and shows why it fired.

Visibility alerts list showing a competitor surge alert with the alert count and prompts affected

What this is

Alerts is a daily comparison the watchdog runs for every active project, no model involved: the last 7 days measured against the 7 days before them, with a row written when one of four specific changes crosses its threshold (api/services/watchdog.py#detect_alerts_for_project). Every project gets this whatever plan it is on; the only part of it gated by plan is the email copy of a day's alerts (see Delivery below).

What can trigger one, and at what threshold

Four kinds, each with its own floor and threshold (api/services/watchdog.py#build_aggregate_alerts, #build_prompt_alerts):

  • Visibility drop: your own visibility across the whole project fell at least 20% relative to the week before, counted only when that prior week's own visibility was itself at least 10% (#OWN_DROP_THRESHOLD, #OWN_DROP_BASELINE_MIN).
  • Competitor surge: evaluated only while your own visibility is under 20%. A tracked competitor whose own visibility reached at least 10% rose at least 30% relative to its own prior week (#OWN_VIS_WEAK_CEILING, #COMPETITOR_MIN_VISIBILITY, #COMPETITOR_SURGE_THRESHOLD).
  • Prompt drop: one prompt's own visibility fell at least 25% relative to its prior week, counted only when that prompt's prior-week visibility was itself at least 15% (#PROMPT_DROP_THRESHOLD, #PROMPT_DROP_BASELINE_MIN).
  • Rank slide: a prompt still cites you about as often as before (it did not also cross the drop threshold above), but your average citation rank on it was in the top 5 the week before and slid by at least 2 full positions (#RANK_SLIDE_TOP_N, #RANK_SLIDE_MIN_POSITIONS).

Two volume floors before any of that is checked

Before the thresholds above are evaluated at all, the project needs at least 5 days of measured history in the prior week, and at least 20 completed answers, project-wide, in both the prior week and the current one; short of either floor the whole project is skipped for that day, whatever the raw percentages would say (#BASELINE_MIN_DAYS, #MIN_WINDOW_EXECUTIONS, #detect_alerts_for_project). A prompt-level check adds a second, its own: that one prompt itself needs at least 20 answers in both windows, not just the project as a whole (#_has_window_volume, #build_prompt_alerts).

Runs once a day, automatically

A systemd timer fires at 04:00 UTC and runs api.cli run-watchdog, which enqueues one watchdog job for every project that is active and whose owner is active, with no opt-in setting and no plan check at this step (discoveredby-cli@run-watchdog.timer, api/cli.py#cmd_run_watchdog, api/tasks.py#_enqueue_watchdog_for_all_projects). Each job runs as its own background task and calls the same detection and persistence logic described above (#run_visibility_watchdog_task, api/services/watchdog.py#run_watchdog_for_project). The only other path that reaches it is an admin running it manually for one project or every project from the internal admin panel, not something a regular user can do (api/routers/admin.py#admin_trigger_watchdog, #admin_trigger_watchdog_all).

A repeat is suppressed, not re-shown

A change that would fire the same kind again for the same project, the same prompt (or none) and the same competitor (or none) within the last 7 days is dropped before it is ever written, so a drop that stays down does not post a fresh alert every single day (api/services/watchdog.py#_is_duplicate, #DEDUPE_WINDOW_DAYS).

Why it fired is stored, not recomputed

Everything behind "why it fired", the exact before and after figures, the engine-by-engine breakdown, whether competitors moved too, is built once, at the moment the alert is detected, and saved on the row itself (#run_watchdog_for_project). The detail page you open later reads that saved record; it does not re-run the comparison against today's data (api/routers/alerts.py#get_alert, #_to_read).

The boundary with notifications

Notifications is the account's inbox, and an alert is one of seven things that can land in it, not the only one. When the watchdog persists one or more fresh alerts for a project, it writes exactly one notification per project member, summarizing every alert from that run together, and links each of those alert rows back to the notification created for the project's owner (api/services/watchdog.py#run_watchdog_for_project). A day with three alerts still produces one notification, not three. The reverse does not hold at all: most notifications are not about an alert, see Notifications for the other six.

Delivery

Every fresh alert always appears on this screen and in the notification above. On top of that, when the project owner is on a paid plan and has an email on file, the day's alerts, up to the 5 highest by impact, also go out as one email; without either of those, the alert still exists, just without the email copy (#run_watchdog_for_project, #DIGEST_TOP_K, api/services/email.py#send_visibility_alert_email).

What's on the screen

The list comes back ordered by the day each alert was detected, so it opens on the most recent alert rather than the biggest (api/routers/alerts.py#list_project_alerts, frontend/src/routes/(app)/alerts/+page.svelte#latest). Every alert does carry an impact_score, and all four kinds build it the same way: the size of the move, times the visibility it moved from, times the log of how many answers ran in the current week, plus a small constant on the two kinds that are not about a single prompt (api/services/watchdog.py#_impact_score, #build_prompt_alerts). What supplies the size differs, positions for a rank slide and a relative visibility change for the other three, so the score is what ranks a day's alerts against each other for the email above, rather than a number to read on its own.

Left alone, the list opens on the last 28 days, and you can switch it to 7, 28, or 90 days; 180 is the ceiling this screen enforces regardless of what you put in the URL (frontend/src/routes/(app)/alerts/+page.server.js#MAX_WINDOW_DAYS). The API returns up to 200 alerts for the window, and the screen says so once a list comes back full (#ROW_CAP, api/routers/alerts.py#list_project_alerts). Below the hero, alerts group by the day they were detected. Opening one shows the before and after pair for that kind, the two date ranges being compared, which engine moved most, whether competitors moved too or this looks specific to you, and, for a rank slide, the rank movement itself (frontend/src/routes/(app)/alerts/[id]/+page.svelte#movement, #category).

  • Notifications: the account-wide inbox an alert lands in, and the other six kinds that land there too
  • Competitors: the comparison a competitor surge alert draws on
  • Prompts: where a prompt drop or rank slide links back to

Last verified 2026-08-11

Start monitoring your AI visibility.

See how AI search engines talk about your brand.

Free to start. No credit card required.