Changelog
New features, improvements, and fixes.
3.18.3
Research → platform: OAI-SearchBot + PerplexityUser + honest schema scope2026-05-03
AddedOAI-SearchBot added to the AI_CRAWLERS check list (src/lib/crawler-analytics.ts) — closes the gap between Article 1 of the research stream ("OpenAI's three crawlers") and what the Crawler Access tool actually reports. Publishers can now see whether their robots.txt allows OpenAI's search-index crawler separately from GPTBot (training) and ChatGPT-User (user-initiated)
AddedPerplexityUser added to AI_CRAWLERS — closes the gap with Article 3 ("PerplexityBot vs PerplexityUser"). Per Perplexity's published policy, PerplexityUser is not bound by robots.txt for user-initiated fetches, but publishers still benefit from seeing whether their robots.txt addresses it nominally
FixedArticle 4 ("Schema.org types Google AI Overviews favors") was overstating Monitor's coverage — it claimed the Entity Clarity scorer checks Organization/LocalBusiness/Article/FAQPage/Product when in reality only Organization + completeness + Author ship today. Article rewritten with honest "currently checked" vs "not yet checked" sections so research stays grounded in code, not aspiration
ImprovedFirst closed-loop on the research → platform integrity contract: every claim in a research article should be verifiable against code on the day it ships. The audit that surfaced these gaps becomes the template for future research-stream sanity checks
3.18.2
Research-monitor: signal-only Slack2026-05-03
FixedSlack notification now fires only when at least one *material* change is detected (new bot, new robots.txt directive, new schema type, policy change). 403s/404s/first-seen baselines/minor copy edits all still get logged to ResearchSourceChange but no longer ping the channel — most weeks = zero Slack messages, the week a real change drops you hear about it
ImprovedSharpened the LLM severity prompt so material/minor labels are stricter. Default behaviour on uncertainty is now "minor" instead of "unknown" — alert fatigue beats false positives
AddedSlack message footer shows aggregate counts of suppressed activity ("Also this week: 2 minor changes · 4 fetch failures — see ResearchSourceChange table") so non-actionable noise is visible at a glance without taking up alert real-estate
ImprovedCron stays on the existing weekly Mondays 09:00 UTC cadence — AI/LLM provider docs don't push changes daily, weekly catches material shifts without burning fetches against bot-blocked sources
3.18.1
Fix silently-failing Gemini model name2026-05-03
FixedThree Gemini API call sites were pointing at gemini-2.0-flash which has been deprecated and now 404s. Replaced with gemini-2.5-flash to match the model registry. Affected: research-monitor LLM diff summaries (returning null), brand-alignment scoring (silently failing), and Growth+ recommendation enhancements (silently failing). All three would return empty data with no error visible to the user — explains why brand-alignment + LLM recommendations may have looked quieter than expected
FixedResearch-monitor cron crontab entry was reading the wrong env var name (ADMIN_KEY instead of MONITOR_ADMIN_KEY). Fixed on the host so Monday's run authenticates correctly
3.18.0
Research source watcher — automated change detection across provider docs2026-05-03
AddedWeekly cron at /api/cron/research-monitor that watches a seed list of ~16 external sources (OpenAI Platform Bots, Google Search Central blog, Anthropic news, Perplexity docs, schema.org releases, Cloudflare Radar AI insights, etc.) and detects material changes via content hashing
AddedWhen a source changes, Gemini Flash summarises what materially shifted vs cosmetic edits and labels it material / minor / unknown. Material changes lead the Slack notification — the cron pings #SLACK_RESEARCH_WEBHOOK_URL (or falls back to SLACK_WEBHOOK_URL) with one grouped message per run
AddedResearchSource + ResearchSourceChange Prisma models — every detected change is persisted with old/new text snapshots, severity, and an articleSlug field so the human can later mark "this became research article X". Foundation for an admin review UI in v3.19
AddedHash-based detection avoids LLM-spamming on cosmetic edits (timestamps, header reshuffles, footer copy). Quiet weeks send no Slack message at all
AddedSource list lives at src/lib/research-sources.ts as a TypeScript array. Add a source: append + redeploy. Disable without deleting: flip enabled=false on the DB row
3.17.1
Research page: real industry research, not changelog2026-05-03
FixedResearch page reframed from "product methodology updates" to actual industry research about how AI crawls, ranks, and cites web content. The first three v3.17.0 articles read as changelog dressed up as research and have been removed
AddedArticle frontmatter now supports a `sources` field — every research article includes a citations block at the bottom with title, publisher, and direct URL to provider documentation. Required for industry-research articles, optional for methodology notes
AddedFour sourced replacement articles: OpenAI's three crawler user agents (GPTBot / OAI-SearchBot / ChatGPT-User) and what blocking each one actually does; Google-Extended for opting out of Gemini training without losing Search; PerplexityBot vs PerplexityUser and the user-initiated-fetch carve-out; the Schema.org types Google AI Overviews surfaces and the ones it doesn't
ImprovedIndex page copy now positions the page as ongoing industry research with sources, not internal methodology
3.17.0
Research page + methodology versioning2026-05-01
AddedPublic Research page at /monitor/research — methodology updates and analysis published as markdown articles in the repo. First three pieces cover the GPT-4o-mini probe routing decision, multi-model brand-mention detection methodology, and topic-gap clustering. Each article includes BlogPosting JSON-LD so search engines and LLMs can cite them directly
AddedRSS feed at /monitor/research/feed.xml + a sitemap.ts covering landing, research, changelog, docs, and pricing — first sitemap on Monitor, helps LLM ingestion pipelines pick up new methodology updates automatically
AddedMethodology version stamp (METHODOLOGY_VERSION = "2.0", updated 2026-04-30) shown in the site footer with a link to the research page. PerformanceSnapshot rows now record the version they were scored under, so future "which rubric produced this number" queries are answerable
AddedAll 11 sibling tools (analyzer, leaderboard, citation-simulator, entity-gap, cro-scan, links, page-grader, trust-audit, ux-audit, a11y-audit, localization-audit) gained the same footer line linking back to /monitor/research — turning Monitor into the canonical methodology surface for the suite
Improved"Research" added to the site nav between Pricing and Leaderboard (and beside Changelog when authed)
3.16.2
OpenAI cost reductions2026-04-30
ImprovedPerformance probes now use gpt-4o-mini instead of gpt-4o. Brand-mention detection was the only thing using GPT-4o-class reasoning, and 4o-mini hits the same pass/fail signal at ~1/16th the per-token cost. Single biggest line item in the OpenAI bill drops by ~93%
FixedRecommendations endpoint now caches per domain per day (same shape as topic-gaps). Previously fired a fresh OpenAI chat completion on every Overview page load — with 64 active domains and dashboard polling, that was hundreds of uncached calls per day
FixedCost-tracking math fixed. The per-snapshot estimatedCostUsd was averaging input + output costs over the combined token total, which undercounts because output is 4× more expensive per token. Now uses inputTokens × inputCost + outputTokens × outputCost so the recorded cost actually matches what providers bill
3.16.1
Header alignment + workspace flow polish2026-04-29
FixedSidebar logo block lower border now lines up exactly with the dashboard header strip — pinned to h-[57px] to match the bordered button content height inside the header (previously sat 5px short)
AddedTrash button on every product in the "Products added" intermediate state — same hover-reveal pattern as the Product overview cards. Was a dead-end before: products could be added but not removed until they had probe data
ImprovedCreate workspace now opens a proper Dialog with FormField + Input + Cancel/Create buttons instead of the browser's native window.prompt. Same shell as Add domain / Add product so the experience reads consistently
FixedSwitching workspace no longer flashes the public landing page. We now resolve the new workspace's first domain client-side and navigate directly to /dashboard/{domainId} instead of bouncing through /monitor/dashboard. Inline spinner on the menu item while the switch is in flight
3.16.0
Design system depth — Dialog, SectionHeader, status helpers2026-04-28
AddedDialog primitive (Dialog.Body / Dialog.Footer / ConfirmDialog) — backdrop, escape handler, max-width container, and header strip with close button now centralised. Migrated AddDomainDialog, AddProductDialog, ChangelogDialog, and the settings ConfirmDialog so all four share one shell
AddedSectionHeader primitive — title + description + right-aligned actions row. Use outside Cards (Card has its own Card.Header). Pass mb={0|2|4|6|8} to control bottom spacing
AddedStatus-tone helpers in @/lib/status-tones — mentionTone(rate), sentimentTone(label), severityTone(severity), positionTone(position), scoreTone(score). Single source of truth for the colour ternaries that were duplicated across products / prompts / performance pages
AddedChart tokens module — CHART dimensions, AXIS styling, SERIES_YOU + competitorColor(i) palette, pickXTicks(total). Future charts now agree on padding, axis colours, and series palette without copy-pasting constants
ImprovedSettings page bulk migration — all `.btn-cta` button calls converted to <Button>, inline form fields converted to <Input>, the local ConfirmDialog deleted in favour of the shared one. Save-bar buttons + invite buttons + create-key / create-webhook / save-SEO-keys actions now share the loading-state pattern
ImprovedSite header migrated to <Button> + <Icon> primitives — hamburger / close icons now share the dashboard's icon library
ImprovedToast dismiss button uses <Icon name="close"> instead of a hardcoded × character — same visual weight as every other close affordance on the platform
ImprovedProducts page sentiment chips and mention-rate pills now route through the status-tone helpers — replaces hand-rolled ternaries that had drifted from the canonical thresholds
ImprovedPrompts page SENTIMENT_TONE map replaced with the shared sentimentTone() helper. Cross-page consistency for sentiment colours is now structurally guaranteed
AddedCLAUDE.md updated with Dialog, SectionHeader, status-tones, chart-tokens documentation + an extended migration checklist
3.15.2
Sidebar polish2026-04-28
FixedAccount dropdown no longer clips to sidebar width when the sidebar is collapsed — it now anchors to the right of the trigger and floats over the dashboard content instead of being trapped inside a 56px column
ImprovedSidebar logo block height now matches the dashboard header strip exactly — lower borders align across the two columns. Logo bumped from 32×32 to 28×28 and the "Monitor" wordmark switched from medium to bold for tighter visual weight
3.15.1
Spinner / status-dot rendering fix2026-04-28
FixedLoading spinners now render as circles instead of U-shapes. The global `* { border-radius: 0 !important }` rule that enforces our sharp-corner brand aesthetic was also stripping `rounded-full`, breaking the gaps-page and Button-loading spinners. Added a CSS opt-in (`.rounded-full`, `.rounded-half`) that wins on specificity so circular elements render correctly while everything else stays sharp
3.15.0
Design system rollout — remaining pages2026-04-28
ImprovedAI Overviews page migrated to primitives — StatTile for the hero stats, Card around the trend chart, EmptyState replaces the long unconfigured/no-data fallbacks
ImprovedCitations page migrated — summary stats use Card density="compact", panels wrap in Card with composable headers, query chips use Badge primitive, show-all toggles use Button variant="ghost"
ImprovedPrompts page migrated — sentiment chips, In-AIO badges, volume badges, descriptor pills all routed through the Badge primitive (single SENTIMENT_TONE map). Cards wrap Share-of-Voice, summary tiles, cited pages, industry sources, SEO Correlation, Response Archive. Expand chevrons use the Icon primitive
ImprovedCompetitors page migrated — tracked competitors panel uses Card + Button primitives (incl. inline form using Input + FormField), share-of-voice and visibility-trend cards wrap in Card, opportunity rows use Card.Header. Stat tiles for the visibility summary row swap in StatTile
ImprovedProducts page migrated — empty/loading states use EmptyState, product cards become Card, mention-rate pills become Badge with tone mapping, Add-product button uses Button + Icon
ImprovedGaps page migrated — loading/error/empty states use the EmptyState primitive, hero panel and cluster cards wrap in Card, Highest-impact and query-count chips use Badge, Refresh button uses Button variant="ghost", expand chevron uses Icon
ImprovedSettings page partially migrated — confirm dialog, locked-feature panel, and failed-to-load state use the new primitives. Import bridges Badge/Button/Card/EmptyState/FormField/Icon/Input so future settings edits naturally flow through the design system. (Inline placeholder helper renamed InlineEmpty to make room for the page-level EmptyState primitive)
ImprovedDomain card uses Badge for the Competitor pill
ImprovedUpgrade banner and Pending Invites banner both use Card tone="accent" and Button primitives — same shell pattern as everywhere else now
3.14.0
Design system foundation2026-04-28
AddedEight UI primitives in src/components/ui/ — Button (5 variants × 3 sizes), Card (with Header/Title/Description/Content/Footer), Badge (6 tones), Icon (37 named icons in 3 sizes), Input + Label + FormField, Dropdown (composable Trigger/Menu/Group/Item), EmptyState, StatTile. Replaces hand-rolled implementations of the same patterns scattered across pages
AddedCLAUDE.md design-system reference at the repo root — typography table, spacing rules, primitive cheat-sheet, migration checklist. Read before adding new pages so drift stops accumulating
ImprovedHeader chrome (sidebar nav, OrgSwitcher, DomainSwitcher, AccountMenu, NotificationBell + drawer) all migrate to the new primitives. Outside-click + Escape handling now lives centrally in Dropdown — no more per-component duplication
ImprovedOverview / Performance / Readiness pages migrate stat tiles, panels, empty states, and dialogs to primitives. Padding, typography, and dropdown shells now match across the high-traffic surface
ImprovedAdd Domain and Add Product dialogs use FormField + Input + Button. Form padding, focus states, and label patterns are now identical across the platform
FixedRecommendation priority badges no longer use uppercase styling (was inherited from .text-h6)
FixedTopic gap cluster theme headings no longer render in uppercase mono — sentence case using text-body-sm font-semibold
FixedSettings confirmation dialog title uses text-h5 instead of the deprecated text-h6 (uppercase mono)
ImprovedDeleted dead CSS — .btn-secondary, .btn-cta-primary, .text-h6 (none in use). Removed the unused stat-card.tsx component (superseded by StatTile)
3.13.0
Polish from EIP review2026-04-28
FixedReverted the combined workspace+domain picker — left header slot is now just the workspace selector (with Create), right slot is just the domain selector (with Add). One job per dropdown reads cleaner than the dual-purpose nested picker
AddedTracked competitors now appear in the domain dropdown under their own "Tracked competitors" section, labelled with a competitor pill. Same drill-down dashboard experience as your own domains, just one click away
AddedRemove product button on each product card — hover reveals a trash icon that stops tracking that product. Historical probe data stays; no new probes run for the removed product
FixedVisibility Score chart no longer loops backwards when a competitor has sparse data. Missing periods are now rendered as 0 (semantically: "not mentioned") instead of being skipped, which made the monotone-spline overshoot wildly. Top-3 competitors are also now picked by sustained presence rather than peak rate
ImprovedTopic gaps loading state now shows explicit "Computing topic gaps — this takes ~20 seconds on first load" copy instead of bare skeleton blocks. First-cluster computation is a synchronous LLM call so users were seeing a blank-looking page
FixedRecommendation priority badges in the Readiness tool diagnostics no longer SHOUT — sentence case (High/Medium/Low) instead of all caps
3.12.0
Diagnosis pathway — show what to fix first2026-04-27
Added"Fix these first" panel on the Overview page — surfaces the top 3 readiness tools dragging your composite score down (low score × tool weight) with one-line guidance per tool and direct links to the Readiness deep-dive. Bridges the gap between "your score is low" and "here's what to actually fix"
AddedCompetitive rank in the dashboard header — "#3 of 6" pill beside readiness score and mention rate, colour-coded green when you're top-2 and red when bottom-third. Visible on every page, not just buried in the Overview leaderboard table
AddedTopic gap clusters now ranked by opportunity score (gap size × competitor heat) — the highest-impact cluster gets a "Highest impact" badge and primary-coloured left border. Each cluster shows estimated additional AI mentions you could earn by closing it, so you can sequence work instead of staring at undifferentiated cards
ImprovedReadiness page tool sections now have anchor IDs and auto-expand when you arrive via #tool-key. Lets the Overview "Fix these first" links jump you straight to the relevant diagnostic
3.11.0
Flow shortcuts — close the discovery → action loop2026-04-26
AddedAuto-login on invite acceptance — first-time invitees land directly on the workspace dashboard instead of bouncing through /login. The invite token is single-use and email-bound, so it's trust-equivalent to a magic link
Added"Since you were last here" widget on the Overview page — surfaces readiness-score delta and any new alerts since your last visit, so weekly check-ins start with what changed instead of a wall of cards
Added+ Track button on every Topic Gap query — adds the gap query as a tracked custom prompt in one click, with an idempotent ✓ Tracked badge if it's already in the list. Closes the loop between discovery (Gaps) and action (Settings → Custom queries) without manual copy/paste
AddedCross-model compare in Performance → Query results — expanding a query now shows tabs for every model that probed it, each with its own mention indicator and position. Spot model-specific weakness without scrolling between tabs
ImprovedAuto-scan after adding a tracked competitor — kicks off a fresh scan in the background so the new competitor populates within ~10 minutes instead of waiting for the daily cron tick
AddedCopy invite link on pending team invites (Owners + Admins only) — useful when email delivery is slow or you want to forward the link with personal context. Link is single-use and tied to the invitee's email
AddedCombined workspace + domain picker in the dashboard header for multi-workspace users — switch workspace AND domain in a single click, instead of trips through two separate dropdowns. Single-workspace users see the original layout unchanged
3.10.0
First-run tour + hero shortcuts2026-04-27
AddedFirst-run tour for new dashboard users — 4 steps covering what we track, the three core questions (Readiness / Performance / Gaps), where to customise (prompts, target messaging, competitors), and scan cadence. Skippable, dismissal stored in localStorage so it doesn't repeat
Added"Customise prompts →" link in the Performance hero footer and the Topic Gaps hero — short-circuits the 'wait, where do I edit these queries?' moment
3.9.0
UX polish from EIP review2026-04-27
FixedCompetitors page empty-state copy clarified — explains that Share of Voice and Query Coverage below show auto-detected mentions even when you haven't manually added any tracked competitors yet
FixedPerformance → Query results now shows up to ~600px of the AI response (was 256px) with relaxed line-height for readability
FixedAI probe maxTokens raised from 800 → 1200 — verbose models (Gemini, Claude) were getting cut off mid-list, killing brand-mention detection on top-N queries
ImprovedPer-product query templates rewritten to read naturally regardless of category phrasing — was 'Recommend a good telecom and SEP patent litigation for a growing business', now 'Who should I consider for telecom and SEP patent litigation?'
ImprovedAI Overviews empty state explains what AIO are, why this page is empty, and what to do — replaces the technical 'SerpAPI / scan recently / SERPAPI_KEY' message
ImprovedQuery Coverage matrix capped to top 20 queries by default with Top 20 / Gaps / All filter buttons. New Gaps view shows only the queries where competitors appear but you don't — the highest-impact targets. Click a column header to reveal the full query text below the matrix
ImprovedCitations page lists (your cited pages, external sources) capped to top 10 by default with show-all toggle. External sources description clarifies what they're useful for (industry directories, peer sites you should aim to be quoted by)
ImprovedPrompts page badges now labelled — 'High vol' / 'Med vol' / 'Low vol' for search volume, 'Importance NN' for the score bar, with explanatory tooltips on hover
3.8.0
Competitor curation + documentation page2026-04-27
AddedTracked competitors panel on the Competitors page — add competitor domains explicitly with one click. Each tracked competitor gets full scans on the next cron tick and their own dashboard you can view independently. Plan-gated by the existing maxCompetitors limit (Growth: 1, Agency: 5)
AddedAuto-detected mentions still appear in the Share of Voice leaderboard below — the two layers complement each other. Empty state still shows the curation panel so you can add competitors before/while waiting for auto-detection
Added/docs page — single-page documentation covering core concepts (scans, probes, scoring, workspaces, plans), every dashboard page (Overview, Prompts, Performance, Products, Gaps, AI Overviews, Competitors, Citations, Readiness, Settings), and how-to guides for the most-asked tasks (add competitor, customise prompts, set target messaging, invite team, switch workspace, force rescan, export data, REST API, webhooks). Anchor-linkable, search-friendly
AddedDocs link in the dashboard sidebar bottom strip, opens in new tab so you don't lose your dashboard context
3.7.0
Pricing page + extended upgrade prompts2026-04-27
AddedStandalone /pricing route — same PricingTable as the landing page #pricing anchor, but accessible directly from every upgrade CTA across the dashboard. Includes FAQ section covering plan switching, data retention on cancel, annual discount, and AI model cost coverage
AddedFree tier now visible on the pricing table — dashed-border callout below the paid plans with a Start free CTA that goes straight to /login (magic-link signup auto-activates the FREE plan)
ImprovedScheduled reports + benchmark reports endpoints return the structured upgrade hint when blocked (matches the shape used by Add Domain and locked Settings tabs)
AddedProduct catalog hint in Domain settings — surfaces the per-plan active probe limit. FREE/LITE/STARTER see 'tracked via passive detection only — Growth runs active probes on 5 products' with an inline See plans link. Growth users see how many active slots they've used
3.6.1
Locked-feature upgrade prompts2026-04-27
ImprovedAPI Keys, Webhooks and Team tabs are no longer hidden for plans without access — they show as locked with a 'See plans' panel listing what each feature unlocks. Showing what you'd get is a stronger upgrade prompt than hiding it
AddedLock icon on locked tabs in the Settings sidebar; tab counts hidden when locked
ImprovedAPI key creation, webhook creation and team invite endpoints now return the structured upgrade hint (currentPlan / suggestedPlan / limitHit / url) — same shape as the Add Domain dialog uses, ready for any caller that wants to render an inline upgrade CTA
3.6.0
Upgrade-prompt UX for FREE tier2026-04-27
AddedPersistent upgrade banner at the top of the dashboard for FREE-tier users — dismissible per browser with a 7-day re-show window so it nudges without nagging
ImprovedPlan-limit error responses (max domains, max competitors) now return a structured upgrade hint with currentPlan, suggestedPlan, and a /pricing link. Generic 403 wall replaced with an inline 'See plans' CTA in the Add Domain dialog
ImprovedAdd Domain dialog distinguishes plan-limit errors from validation errors — friendly upgrade prompt for the former, plain destructive text for the latter
3.5.0
Free tier, custom roles, encryption rotation, append-only audit logs2026-04-27
AddedFree tier — every new signup lands on the FREE plan automatically (1 domain, weekly scans, 30-day history). No Polar checkout required to try the product. Existing inactive accounts still go to the pricing page rather than auto-upgrading
AddedTwo new workspace roles: ANALYST (can edit prompts and run scans, but not domain identity or member management) and VIEWER (strict read-only). Surfaced in the invite + role-change dropdowns with hover-over descriptions
AddedhasPermission(role, permission) helper and a single role-permission matrix in src/lib/team-auth.ts — all future fine-grained access checks should go through it instead of inferring from role names
AddedEncryption-key rotation support — set ENCRYPTION_KEY_PREVIOUS to the old key during rotation; decrypts try primary first then fall back. New writes always use the current key. Documented KMS migration path (AWS KMS / GCP KMS / Vault) in src/lib/seo-integrations.ts
AddedAppend-only audit logs at the database level — BEFORE UPDATE/DELETE/TRUNCATE triggers on AuditLog raise an exception regardless of role. Even an attacker with full app-DB access can't tamper with history without explicitly dropping the trigger first
3.4.1
Disk-hygiene hardening (post-incident)2026-04-27
FixedRecovered from a host disk-full incident that left postgres unable to checkpoint. Root cause: systemd-journald accumulated ~60GB of logs since deploy, plus docker build cache from frequent rebuilds. No customer data lost — confirmed by row-count check against the pre-incident backup (4 users, 63 domains, 6087 PerformanceSnapshots, all matching)
Added/etc/systemd/journald.conf.d/size-limits.conf caps journal at 500MB system-wide with a 2GB free-space floor
AddedWeekly disk-hygiene cron (Sundays 04:00 UTC) prunes dangling docker images + old stopped containers, and posts a Slack alert if disk usage crosses 80%
AddedFresh post-recovery DB backup taken to confirm clean state before the next deploy
3.4.0
Slack scaffolding + off-site backup readiness2026-04-26
AddedSlack app endpoints scaffolded — /api/slack/commands handles `/visibility <domain>` and returns the latest readiness score for any tracked domain; /api/slack/events handles the url_verification handshake and link_shared events
AddedSlack signing-secret verification with replay protection (5-minute window) and constant-time comparison. Both endpoints stay dormant when SLACK_SIGNING_SECRET isn't set — safe to deploy ahead of having a real Slack app
AddedOff-site backup uploader scaffold at /root/db-backups/backup-offsite.sh — uses rclone to sync local pg_dumps to any cloud bucket (S3, B2, Wasabi, Backblaze). Inactive until rclone is installed and an 'offsite' remote is configured on the host
3.3.0
Google AI Overviews position tracking2026-04-26
AddedNew AI Overviews page in the dashboard sidebar — track how your brand surfaces in Google's AI-generated answer panels over time. Mention rate, average position, and best position with deltas vs the previous period
AddedPosition-over-time chart with inverted Y-axis (lower position = higher on chart, since position 1 is best). Wide-viewBox SVG, axis-label thinning consistent with the readiness chart
AddedPeriod history table — every scan period with its mention rate, avg/best position, and total queries run. Useful for spotting drift week-over-week
ImprovedReuses the existing SerpAPI scaffolding (data has been captured per scan since v1.2.0) — no new probes, no extra cost. This release just makes the historical trend visible
3.2.0
Sprint 3 hardening — token entropy, Zod validation, audit-log invariant2026-04-26
ImprovedMagic-link, team-invite, org-invite and webhook secrets all upgraded from UUID v4 (122 bits) to 256-bit cryptographically random hex tokens. Stronger against offline brute-force; same UX
AddedCentralised Zod schemas in src/lib/validation.ts plus a parseBody helper. Wired into POST /api/monitor/orgs, /switch, /[id]/invite, and PATCH /[id]/members/[memberId]. Catches type confusion and length-bomb input at the route boundary instead of failing deeper in the call stack
ImprovedAppend-only audit-log invariant documented at the top of src/lib/audit-log.ts. logAction is the only sanctioned write path; no other code calls update/delete/upsert. DB-role separation (Sprint 4) will enforce this at the database layer
AddedAdmin key rotated; all callers (host crontab, environment) updated atomically
3.1.0
Multi-workspace v3 polish — rename, transfer ownership, move domains2026-04-26
AddedInline workspace rename in Settings → Workspace (Owner only). Click the workspace name, type a new one, blur or hit Enter to save
AddedTransfer ownership: Owner can change any member's role between Owner / Admin / Member via inline dropdown. Multiple Owners are allowed (encouraged for redundancy). Last-Owner protection refuses any change that would leave the workspace ownerless
AddedMove domain to another workspace via Settings → Domain → Workspace. Requires Owner/Admin role in BOTH the source and target workspaces — the API enforces this independently of any UI gating, so no smuggling domains into workspaces you only have Member access to
AddedPATCH /api/monitor/orgs/[id]/members/[memberId] (role change, Owner only) and PATCH /api/monitor/domains/[id] now accepts organizationId
3.0.0
Data-safety hardening (pre-launch)2026-04-26
FixedScoreSnapshot and PerformanceSnapshot foreign keys to MonitoredDomain changed from onDelete: Cascade to onDelete: Restrict — a future code path (or accidental admin action) that deletes a domain can no longer silently destroy months of historical probe + score data
FixedForce-rescan now wraps the delete + create in a single Prisma $transaction with an optimistic concurrency check (status=COMPLETED) — prevents lost data if a rescan fails mid-flight, and prevents two concurrent rescans from racing each other into a corrupted state
AddedAccount deletion is now a soft-delete with a 30-day recovery window. Sessions are invalidated immediately; the account can't sign in; nothing is destroyed. A nightly cron permanently purges accounts past the grace period (GDPR Article 17 compliant). Admins can restore via POST /api/admin/users/[id]/restore within the window
AddedAutomated daily PostgreSQL backups via host cron at 03:00 UTC — 5 databases, 14-day daily rotation + 4-week weekly rotation. Off-site/cloud backup is a follow-up requiring S3/B2 credentials
ImprovedScheduled-reports cron now skips schedules whose underlying domain is inactive or whose owner is soft-deleted — no more zombie email deliveries after a domain is removed
ImprovedDaily scan cron excludes soft-deleted users, so accounts in the deletion grace window stop incurring scan cost immediately
AddedRate limits added to SSO start (10/5min per IP — defends against email-domain enumeration), org invite (20/hour per org), team invite (20/hour per inviter), and data export (3/hour per user — protects against runaway DB load)
AddedLogin page recognises a new account_deleted error so users who try to sign back into a deleted account see a clear "contact support to restore within 30 days" message
2.9.1
Multi-workspace polish — leave, delete, pending-invite banner2026-04-26
AddedLeave workspace button (non-Personal, non-last-Owner) — Settings → Workspace → Danger zone. Switches you back to your Personal workspace on success
AddedDelete workspace button (Owner of TEAM workspace only). Domains aren't deleted — they stay accessible to whoever originally created them via their Personal workspace, thanks to the schema's onDelete: SetNull on MonitoredDomain.organizationId
AddedPending-invites banner at the top of the dashboard — surfaces unaccepted org invites for users who already have a session under the same email and didn't click the email link. One-click accept inline
AddedGET /api/monitor/orgs/[id], PATCH (rename), DELETE (delete workspace), POST /api/monitor/orgs/[id]/leave, GET /api/monitor/orgs/pending-invites
2.9.0
Multi-workspace (Phase 2) — workspace switcher + invites2026-04-26
AddedWorkspace switcher in the dashboard header — Agency-tier customers can spin up additional workspaces (e.g. one per client) and switch between them; everyone else sees their Personal workspace surface only when they actually have multiple to choose from
AddedSettings → Workspace tab: see members of the current workspace, invite teammates by email with role (Admin / Member), remove members. Owner-protection: refuses to remove the last Owner of an org
AddedEmail-based invite flow with single-use token, 7-day expiry, magic-link-style accept route. Pending invites display in the members list until accepted
AddedDomain creation now scopes to the current workspace — when you switch workspaces, you only see that workspace's domains. Existing domains stay where they were after the v2.8.0 backfill
AddedPOST /api/monitor/orgs (Agency only — create workspace), POST /api/monitor/orgs/switch, POST /api/monitor/orgs/[id]/invite, GET /api/monitor/orgs/[id]/members, DELETE .../members/[memberId], GET /api/monitor/orgs/accept?token=...
ImprovedPlan limits unchanged — total domain count is still capped per user across all workspaces, so multi-workspace organises rather than expands the underlying quota
2.8.0
Multi-workspace foundation (Phase 1, internal)2026-04-26
AddedOrganization + OrganizationMember data model — every existing user is migrated to a Personal workspace with themselves as OWNER. Foundation for the agency-tier multi-client view coming in Phase 2
AddedMonitoredDomain.organizationId — every domain is now linked to an org. The legacy userId column is kept indefinitely for rollback safety and as a record of who originally created the domain
AddedTeam-auth dual-read — domain access is granted via the legacy userId/TeamMember paths OR via OrganizationMember, whichever resolves first. No behavior change for existing users
ImprovedIdempotent backfill script (scripts/backfill-organizations.ts) with --dry-run and --commit modes, transactional per-user. DB backed up before migration
2.7.0
Topic gap clustering2026-04-26
AddedNew Gaps page in the dashboard sidebar — clusters the queries where AI mentioned competitors but not your brand into 4–8 themes ('Patent litigation in telecom', 'Biotech IP for startups', etc.) so you can see opportunity areas at a glance instead of scrolling a flat list of failed queries
AddedEach cluster shows: the theme, a one-sentence rationale, example queries verbatim, and the top 3 competitors who showed up for that theme — directly actionable for content/messaging work
AddedPowered by gpt-5.4-mini, last 30 days of probe data, ~$0.01 per cluster analysis. Process-local cache means repeat views are free until midnight UTC; manual Refresh available (rate-limited 5/hour)
AddedGET /api/monitor/domains/[id]/topic-gaps endpoint (VIEWER role) with optional ?refresh=true
2.6.1
Polish pack — toasts, Cmd+S, tab badges2026-04-26
AddedToast notifications for save/error states across Settings (Domain save, SEO keys, API key create/revoke, team invite/remove). Replaces the old inline "Saved" / "Failed to save" text patterns
AddedCmd+S / Ctrl+S keyboard shortcut on the Domain tab — saves immediately when there are unsaved changes
AddedTab badges in the Settings sidebar show counts for Team members, API keys and Webhooks at a glance
2.6.0
SAML/SSO via WorkOS (Agency tier)2026-04-26
AddedSAML and OIDC single sign-on for Agency-tier customers via WorkOS — works with Okta, Azure AD, Google Workspace, OneLogin, and any other major identity provider out of the box
AddedEmail-domain routing — when a user enters an email at /login whose domain has a configured SSO connection, they're transparently redirected to their identity provider instead of getting a magic link
AddedDomain-mismatch protection on the SSO callback — refuses to log a user in if the IdP returns an email whose domain doesn't match the configured connection (defends against misconfigured connections impersonating users from other tenants)
AddedAdmin-managed mappings via /api/admin/sso-domains (POST/GET/DELETE) — we configure SSO per Agency customer; there's no end-user CRUD by design
AddedSSO logins are tagged in the audit trail with `method: "sso"` + connectionId so compliance teams can distinguish from magic-link logins
2.5.0
Audit log CSV export2026-04-26
AddedDownload CSV button on the admin audit log viewer — exports the currently filtered set (action, user, date range) as a properly RFC-4180-escaped CSV with timestamp, action, user, resource, IP and metadata columns
AddedGET /api/admin/audit-log?format=csv endpoint, ADMIN-gated, capped at 10,000 rows per request to protect memory on large accounts
AddedExports self-log a data.export entry against the admin who pulled them — full SOC 2-friendly trail of who exported what and when
2.4.0
Active per-product probes2026-04-26
AddedPer-product probe queries — each product in your catalog gets 3 dedicated AI queries ("best [category]", "recommend a [category]", "alternatives to [category]") tagged with the product so we can measure brand visibility per practice area / SKU / service line independently
AddedProducts page restored to the dashboard sidebar nav (was previously hidden because passive detection was unreliable)
ImprovedProducts page now prefers active probe data when available and falls back to passive response scanning otherwise. Each product card shows whether the signal is "Active probe" or "Passive scan"
AddedPlan-gated product limits — Growth gets 5 products with active probes, Agency gets 20. Lite/Starter still see passive detection on the Products page
ImprovedPerformanceSnapshot.queryResults now carries an optional productName tag so per-product aggregates work without a database migration
2.3.0
Brand sentiment surfacing on Performance page2026-04-26
AddedEndorsement rate metric on the Performance hero — share of AI mentions where the brand is described positively (vs neutrally listed). Color-coded with delta vs previous period
AddedBrand sentiment section showing the full label distribution (endorsing / neutral / mixed / dismissive) as a stacked bar with counts
AddedTop descriptors panel — most-frequent words AI uses to describe your brand (e.g. "specialist", "affordable", "limited"), ranked by frequency
AddedPer-model endorsement breakdown — see which model describes you most/least flatteringly (e.g. ChatGPT endorses, Perplexity is cold)
AddedSentiment chips on every query result row, with descriptors revealed in the expanded view
ImprovedPrompts page already showed per-query sentiment; Performance page now surfaces it as a first-class top-line metric
2.2.1
Settings UX overhaul & chart polish2026-04-26
ImprovedSettings redesigned around a vertical sidebar nav (Stripe/Linear style) — tabs no longer require scrolling back up to switch
ImprovedDomain tab grouped into Brand identity / Tracking / AI representation / SEO Tool Integration / Danger zone sub-sections instead of one long form
AddedSticky save bar in the Domain tab — slides in only when there are unsaved changes; Discard reverts and Save changes persists. Adds a beforeunload guard to prevent navigating away with pending edits
AddedConfirmation dialogs for destructive actions (Remove domain, Revoke API key, Delete webhook, Remove team member, Remove SEO key) with Esc/Enter shortcuts
ImprovedEmpty states across Custom queries, Target messaging, Product catalog, API keys, Webhooks and Team members are now bordered cards with inline CTAs ("+ Add your first query") instead of plain greyed-out text
ImprovedSettings page no longer reflows when user data loads — skeleton rows fill the sidebar + content shell during load
ImprovedSwitching between Settings tabs scrolls the page to the top synchronously, so the sidebar position stays anchored
ImprovedSettingsRow contrast bumped (label is now text-body font-semibold; description is text-body-sm with leading-relaxed) and column gap widened to 12 for clearer scanning
FixedReadiness score chart is now full-width (was leaving 200+px of blank space on either side because of a narrow viewBox + fixed height + default preserveAspectRatio)
FixedReadiness chart x-axis now caps at ~7 evenly-spaced labels with the last period anchored, instead of labeling every snapshot and producing an unreadable smear of overlapping text
2.2.0
Custom Prompt Builder2026-04-26
AddedTest prompt button — run any custom query through every enabled model in seconds without saving, with per-model response cards, mention status, position, and competitors named
AddedAI-suggested prompts — Suggest button asks GPT-5.4-mini to propose 5 new prompts based on competitor-gap data (queries where rivals were mentioned but you weren't)
AddedTemplate gallery — 10 patterns auto-filled with your category/company name (best X, top 10, recommend a Y for Z, X vs Y, alternatives, …) — one click to add
AddedBulk import — paste one query per line; queryType auto-detected from natural language
AddedQuality dot per query — green/amber/red heuristic based on length, category mention, and clear ask verb
AddedPer-query history — mention-rate badge and 7-period sparkline pulled from PerformanceSnapshot results, color-coded by latest value
AddedPOST /api/monitor/domains/[id]/prompts/test and /prompts/suggest endpoints (ADMIN role, rate-limited)
ImprovedSettings page redesigned with a two-column 50/50 layout across all tabs (General, Domain, Notifications, API Keys, Webhooks, Team) — labels and descriptions on the left, fields on the right
2.1.0
Multi-model accuracy + cost-aware scanning2026-04-26
AddedGPT-5.4 across all probes (was GPT-4o) — sharper category classification and brand recognition
AddedPlan-based scan cadence — Lite weekly, Starter every 3 days, Growth/Agency daily; cuts API spend on lower tiers
AddedDaily scan batch Slack alert redesigned — header, two-column stat grid, per-model probe health, top gainers/decliners, degraded-probe section
AddedCross-tool health check posts to Slack (daily heartbeat + 6-hourly silent checks for OpenAI / Anthropic / Google AI / Perplexity / Resend quotas)
AddedLLM-rewritten recommendations — descriptions now reference the site's actual score, mention rate, and competitors instead of templated boilerplate
AddedBranded PDF benchmark report — CW logo header/footer, table styles, color-coded score badges, per-model breakdown
ImprovedPerformance page mention rate now only counts probes that actually ran (skipped models no longer drag the average to zero)
ImprovedPer-model 'Probe skipped' state distinguishes quota/auth failures from real 'not mentioned' results
ImprovedVisibility Score chart x-axis thinned to ≤7 ticks so 60-day windows are readable
ImprovedHero CTA simplified — 'View leaderboard' button removed from the marketing page
ImprovedAuto-discovered competitor domains now validated (length cap + HEAD request) — stops hallucinated URLs polluting scans
FixedPerformance probes that hit quota on every query now correctly mark FAILED with the error, instead of silently completing with 0 queries
FixedPerplexity citations now captured — citations page populates with real cited URLs (was reading message content only, ignoring the citations array)
FixedTeam Settings menu link now lands on the Team tab via ?tab=team (was always defaulting to General)
FixedManage Subscription button now shows feedback on error and redirects to /pricing when no Polar customer record exists (was silently doing nothing)
2.0.0
Launch release2026-03-15
AddedSOC 2 audit logging — all key actions logged with user, IP, timestamp, and metadata
AddedGDPR compliance — data export and data deletion endpoints
AddedSEO tool integrations — connect SEMrush or Ahrefs to correlate search volume with AI visibility
AddedSEO correlation on Prompts page — see which high-volume queries AI ignores
AddedAdmin audit log viewer with filtering by action, user, and date range
AddedESLint React Hooks rule — catches conditional hook calls at build time
ImprovedSecurity headers — X-Content-Type-Options, X-Frame-Options, XSS protection, referrer policy
ImprovedCI pipeline now runs ESLint before tests and deploy
ImprovedUpdated meta tags and OG data for all shipped features
ImprovedProduct mention detection uses fuzzy word matching (not just exact string)
FixedReact hooks called after early returns — root cause of #310 hydration errors
FixedNull safety for new domain fields (targetMessaging, productCatalog, regions)
1.4.0
Product visibility & multi-region2026-03-15
AddedShopping/Product Visibility — add a product catalog, track product-level mentions across AI models with heatmap matrix
AddedMulti-Region/Language — configure regions (US, UK, DE, FR, etc.), probes run localized queries, filter dashboard by region
AddedProducts page with overview cards, product x model heatmap, and per-product query breakdown
AddedRegion selector in header bar (shown when multiple regions configured)
AddedRegion settings with 10 supported regions in Settings > Domain tab
ImprovedNon-global regions use cheap models (Gemini Flash) to minimize API costs
ImprovedDashboard context filters performance data by selected region
1.3.0
Brand alignment & AI content strategy2026-03-15
AddedBrand Message Alignment — define target messaging, measure how well AI represents your brand (0-100 score)
AddedPer-message alignment breakdown on Performance page with matched/missing/distorted badges
AddedAlignment drift detection — alerts when AI perception of your brand shifts
AddedTarget brand messaging editor in Settings > Domain tab (up to 10 messages)
1.2.0
Competitive intelligence & GEO audit2026-03-15
AddedCitation tracking — dedicated Citations page showing your cited pages, external sources, and citation trends
AddedQuery volume estimation — High/Med/Low volume badges on prompts based on model coverage and consistency
AddedGoogle AI Overviews tracking via SerpAPI — see if your brand appears in Google's AI answers
AddedGEO Audit — 10-signal generative engine optimization score (FAQ schema, entity markup, E-E-A-T, and more)
AddedLLM-powered content recommendations — AI-generated content strategy suggestions alongside rule-based recs
AddedAuto-scan competitors — top competitors from AI probes are automatically scanned under the system user
AddedCross-domain data sharing — new domains see historical visibility data from other users' probes
AddedCompetitor favicons via cached proxy (no hotlinking)
ImprovedCompetitors page redesigned — query coverage heatmap matrix, visibility opportunities, heatmap trend
ImprovedCompetitors are now auto-detected from AI probes (no manual setup needed)
ImprovedDomain switcher opens an add-domain dialog instead of inline form
ImprovedPerformance tracking settings moved from readiness page to Settings > Domain tab
ImprovedRecommendations fetched from server API (enables LLM enhancement for Growth/Agency plans)
FixedSidebar nav uses Next.js Link for instant client-side navigation
1.1.0
Notifications, onboarding & polish2026-03-15
AddedEmail notification preferences — toggle alerts, digests, and report emails in Settings
AddedDashboard onboarding flow with welcome state after checkout
AddedScanning progress indicator with auto-refresh on first scan
AddedFirst results celebration banner with next steps
AddedIn-app changelog with 'What's new' dialog in sidebar
AddedGitHub Actions CI/CD pipeline — auto-deploy on git tag push
ImprovedDashboard content now has max-width and is centered
ImprovedPricing table — 3-column layout with Lite callout, updated features for all tiers
ImprovedChangelog dialog spacing and readability
1.0.0
Platform launch2026-03-14
AddedDashboard onboarding flow with scanning progress and first-results celebration
AddedCompetitive Readiness Deep Dive — side-by-side tool and category comparison
AddedAI Discovery Potential — opportunity sizing vs top competitor
AddedContent-gap-driven recommendations in the overview
AddedYour Most Cited Pages + Industry Sources split on Prompts page
AddedLITE plan ($149/mo) — lower entry point for essential tracking
AddedREST API with SHA-256 hashed API keys and rate limiting
AddedUser-configurable webhooks with HMAC-SHA256 signatures and SSRF prevention
AddedScheduled weekly/monthly PDF reports via email
AddedHistorical benchmark report PDF download
AddedWhite-label branding for Visibility OS client dashboards
AddedTeam collaboration with RBAC (Owner/Admin/Viewer) and invite flow
AddedTabbed settings page (General, API Keys, Webhooks, Team)
AddedCompetitors nav item in sidebar
ImprovedSettings page now lives inside the dashboard with shared sidebar
ImprovedSidebar is fixed/sticky so Settings link is always visible
ImprovedPricing table layout — 3-column with Lite callout bar
FixedUnlimited history no longer shows as 'null-month history'
FixedManage Billing button now shows error message on failure