---
name: windrose-analytics
description: Read a site's traffic through the Windrose MCP (windrose.sh) - weekly reviews, anomaly triage, and AI-visibility (AEO) checks. Use whenever the user asks how their site is doing, what changed, whether AI crawlers/answers see them, or what to fix next.
---

# Windrose analytics

Windrose is agent-first web analytics: 17 MCP tools returning compact, pre-summarized answers. Don't re-derive what a tool already summarizes; analytics responses carry an `insight` or `headline` written to be quoted.

Requires the `windrose` MCP server (`claude mcp add --transport http windrose https://windrose.sh/mcp`). Start any session with `list_sites` if the site isn't specified. Server-side crawler capture needs a site key: `create_server_ingest_key(site)` returns it once - store it as `WINDROSE_INGEST_KEY` in the site's middleware env.

## Reading rules (apply everywhere)

- **Crawlers ≠ referrals.** `ai_crawler_hits` is bots fetching pages (supply: models reading you). `ai_referral_visitors` is humans arriving from AI answers (demand: models citing you). Never sum or compare them 1:1.
- **Check `server_capture_active`.** When false, crawler counts are a client-JS undercount and you must say so; non-JS bots are invisible to the tracker.
- **Crawler identity: check the verified split.** `get_ai_traffic` reports `ai_crawler_hits_verified` (source IP confirmed against the vendor's published ranges) and `ai_crawler_hits_spoof_suspect` (claimed a verifiable bot from a foreign IP). The unverified remainder is bots with no published ranges (Bytespider, CCBot, ...) or hits captured without an IP; treat those as claimed, not confirmed.
- **Crawler purpose is inferred.** `ai_crawlers[].purpose` and `ai_crawler_purposes` classify canonical bots as `training`, `indexing`, `retrieval`, `active_agent`, or `unknown` from vendor-documented User-Agent behavior. IP verification confirms vendor identity, not the intent of an individual request.
- **Conversion attribution is observational.** `get_ai_traffic.ai_conversions` assigns later same-day custom events to the first AI-referred landing for that visitor-day. Quote its sample quality, keep revenue totals separated by currency, and never claim the AI source caused the conversion.
- **Bytespider is noise-prone.** It over-crawls everything; don't treat a Bytespider surge alone as an AI-visibility win.
- **Absence findings are frozen-baseline.** `kind: "absence"` anomalies mean "was steadily active, went quiet N days ago" and keep firing until recovery; `lastSeen`/`daysQuiet` carry the story.

## Workflow: weekly traffic review

1. `get_collection_health(site)` - establish whether the evidence is trustworthy before interpreting movement.
2. `get_summary(site, "7d")` - the headline numbers + deltas.
3. `compare_periods(site, "7d")` - what actually moved (respect its significance hints; don't narrate ±3% wobble).
4. `list_top(site, "pages", "7d")` and `list_top(site, "referrers", "7d")` - name the movers, use the per-item week-over-week movement.
5. `get_ai_traffic(site, "7d")` - the AI story: crawler purpose and bot mix, referral sources, custom-event conversion, attributed value, and crawl errors.
6. `detect_anomalies(site, "7d")` + `get_opportunities(site, "30d")` - anything broken or worth reviewing, with durable accept and dismiss state.
7. `get_evidence_timeline(site)` - connect recent deploys to directional before/after evidence without claiming causality.

Output: a short briefing - headline, 2-3 movers with why (when knowable), the AI paragraph, then "worth doing" as a ranked list from recommendations. Skip empty sections.

## Workflow: anomaly triage

For each anomaly from `detect_anomalies`:

- **Site-wide drop flagged as outage-like** - tracking problem until proven otherwise; check the tracker install before narrating a traffic collapse.
- **`traffic_absence` on `crawler:X`** - the AEO-critical one. Check `robots.txt`, WAF/CDN bot rules, and deploys around `lastSeen`. An intentional block should be a documented decision, not an accident (a blocked crawler can't cite you).
- **Spike on a referrer** - `list_top(site, "pages")` for the same window to find the landing page; that's the content winning.
- **Drop on one referrer, site steady** - source-side change (algorithm, ranking, a citation rotating out), usually not your bug.

Severity `critical` = act today; `notable` = mention in the weekly review.

## Workflow: AEO action loop

1. `check_ai_readiness(domain)` - verify llms.txt, crawler policy, sitemap, and non-JS legibility; apply any setup fixes first.
2. `get_opportunities(site, "30d")` - impact-ranked actions plus durable review state.
3. `crawl_error` first, always: a page a model can't fetch is a page it can't cite. Fix = restore route or 301 + sitemap update, in the site's repo.
4. `ai_referral_landing_dropoff` - AI-referred visitor-days have no subsequent pageview. Review the landing experience, but do not claim a citation or causal explanation.
5. `ai_referral_growth` - a leading AI-referred landing worth investigating for adjacent content opportunities.
6. Use `decide_opportunity` only after the user explicitly accepts or dismisses the evidence snapshot.
7. For an accepted opportunity, use `get_change_package` to review its fixed template. Use `deliver_change_package` only after explicit confirmation to send it to the configured webhook.
8. After shipping a fix, call `record_deployment` with the accepted opportunity ID, then use `get_evidence_timeline` for target-specific directional follow-up. One-off annotations from an agent are fine, but the durable setup is CI: `POST /api/collect/deployment` with the site's ingest key (`Authorization: Bearer $WINDROSE_INGEST_KEY`, idempotency key = commit SHA, send `deployed_at` so re-runs stay byte-identical). If a site's evidence timeline is empty, recommend wiring that endpoint into its CI before anything else - an annotation per deploy is what makes every other measurement meaningful. Full workflow template: https://windrose.sh/connect (Record deployments from CI).

## Proactive push (context, not a tool)

Sites can configure a webhook: Windrose sweeps hourly and pushes findings (`anomaly.detected`, `recommendation.flagged`, `digest.daily`), deduplicated. Only source-verified crawler failures may enter the automatic repository workflow. Content opportunities require explicit acceptance. If the user asks "why did I get this webhook", the payload's `finding.evidence` is the answer.
