{
  "$meta": {
    "version": "1.1",
    "generated": "2026-08-05",
    "note": "Researched inventory. Derived from MCP verb schemas, LookML, skill definitions and 90-day Looker usage, NOT from the design fixture, whose values were wrong (a different method ladder, 21 skill slugs that do not exist). Every record carries a verification state and provenance; the public projection strips provenance. Counts render from this file, never from copy.",
    "verificationStates": {
      "verified": "Formula or semantics pinned in code, LookML or approved product docs, with a citation.",
      "inferred": "Returned by a governed verb, but the calculation lives in LookML not read here, no formula is stated.",
      "review": "Meaning contested between parts of the product, measure gated or deferred, or unit/direction unestablishable. Calculation and interpretation are suppressed."
    },
    "metricTypes": [
      "raw measure",
      "derived metric",
      "score",
      "share",
      "rank",
      "rate",
      "monetary",
      "statistical verdict"
    ],
    "verifiedAgainst": "Quattr MCP main @ 78713945, and the LookML semantic layer, on 2026-08-04. No human product review has taken place, every state on this page describes what the code says, not what a reviewer signed off.",
    "verifiedAgainstShort": "the shipped semantic layer"
  },
  "sources": {
    "search-console": {
      "name": "Google Search Console",
      "color": "#47566B",
      "page": "/sources/search-console"
    },
    "web-analytics": {
      "name": "GA4 or Adobe Analytics",
      "color": "#9D2B62",
      "page": "/sources/web-analytics"
    },
    "google-ads": {
      "name": "Google Ads",
      "color": "#8A5B1C",
      "page": "/sources/google-ads"
    },
    "server-logs": {
      "name": "Server logs",
      "color": "#A6421F",
      "page": "/sources/server-logs"
    },
    "site-crawl": {
      "name": "Site crawl",
      "color": "#6E5844",
      "page": "/sources/site-crawl"
    },
    "rank-tracking": {
      "name": "Rank tracking",
      "color": "#8D3A82",
      "page": "/sources/rank-tracking"
    },
    "ai-visibility": {
      "name": "AI visibility",
      "color": "#5B4B9E",
      "page": "/sources/ai-visibility"
    },
    "lighthouse": {
      "name": "Lighthouse and Core Web Vitals (CWV)",
      "color": "#34656D",
      "page": "/sources/lighthouse"
    }
  },
  "rungs": {
    "R1": "Reachable",
    "R2": "Retrieved",
    "R3": "Referenced",
    "R4": "Represented",
    "R5": "Rewarded"
  },
  "levers": {
    "L1": "Technical & crawl health",
    "L2": "Demand modeling",
    "L3": "Refresh & content quality",
    "L4": "Internal linking & architecture",
    "L5": "Net-new content",
    "L6": "Authority & off-site",
    "L7": "AI-answer visibility",
    "L8": "Paid/organic interplay"
  },
  "metrics": [
    {
      "slug": "ai-referral-conversion-rate",
      "name": "AI referral conversion rate",
      "aliases": [
        "AI referral CVR",
        "Assistant referral conversion rate"
      ],
      "definition": "The rate at which assistant-referred visitors completed a configured goal. It is a governed measure in the semantic layer with its own denominator, distinct visitors, not sessions, so it is not the conversion count over anything a breakdown hands you.",
      "category": "AI referral traffic",
      "type": "rate",
      "unit": "a 0 to 1 fraction in the semantic layer, formatted as a percent for display",
      "direction": "higher-better",
      "verification": "review",
      "aggregation": "Never average two conversion rates to get a combined rate, and never rebuild it from a session and conversion breakdown, the semantic layer computes it as its own measure, and its denominator is a distinct-visitor estimate while the conversion count is a plain sum.",
      "grain": "One traffic-source value (or the whole-domain total) for one date range.",
      "dimensions": [
        "source/medium",
        "landing page",
        "goal",
        "country",
        "device"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "ai-referral-traffic-report"
      ],
      "skills": [
        "search-to-revenue",
        "cross-domain-correlator"
      ],
      "verbs": [],
      "rungs": [
        "R5"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "Do assistant referrals convert better or worse than organic search?",
        "What is our conversion rate on AI referral traffic?"
      ],
      "caveats": [
        "Inherits the classification blocker of the whole family, the denominator is a hand-assembled set of traffic-source rows, not a measured channel.",
        "The denominator is distinct visitors, not sessions. A rate rebuilt as conversions over sessions is a different number, and the gap widens as the population shrinks, which is exactly where assistant referrals live.",
        "Assistant volumes are small enough that the rate is dominated by sampling noise; the significance verdict is the thing to read, not the arrow.",
        "The web-analytics feed exposes two conversion-rate measures, one dividing summed conversions by a distinct-visitor estimate, the other averaging a per-row rate column, and they do not agree. Say which one the number came from."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Declaring assistant traffic 'higher intent' from a rate computed on a few dozen visitors.",
        "Reconstructing the rate from a breakdown and getting a different figure from the one the layer returns.",
        "Quoting the two twin rate measures interchangeably."
      ],
      "notSameAs": [
        {
          "slug": "ai-referral-conversions",
          "why": "The count is a sum of goal completions; the rate is a separate measure in the semantic layer with its own denominator, a distinct-visitor estimate, not the sessions or the rows a breakdown gives you. One is not derivable from the other with the numbers to hand, and treating the rate as count-over-sessions is the standard way this family is misread."
        }
      ],
      "related": [
        "ai-referral-sessions",
        "ai-referral-conversions",
        "conversion-rate",
        "conversion-rate-change"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-referral-conversions",
      "name": "AI referral conversions",
      "aliases": [
        "Assistant referral conversions",
        "AI-sourced conversions"
      ],
      "definition": "Completions of your configured analytics goals on sessions that arrived from an AI assistant.",
      "category": "AI referral traffic",
      "type": "raw measure",
      "unit": "conversions",
      "direction": "higher-better",
      "verification": "review",
      "aggregation": "The underlying conversion measure sums across rows, unlike the visitor and session measures beside it, which are distinct-count sketches, which is exactly why a conversion rate cannot be reassembled from a breakdown of the two.",
      "grain": "One traffic-source value (or the whole-domain total) for one date range.",
      "dimensions": [
        "source/medium",
        "landing page",
        "goal",
        "country",
        "device"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "ai-referral-traffic-report",
        "search-to-revenue-report"
      ],
      "skills": [
        "search-to-revenue",
        "cross-domain-correlator",
        "monthly-exec-review"
      ],
      "verbs": [],
      "rungs": [
        "R5"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "Do AI referral visits convert?",
        "How many conversions came from AI assistants last month?",
        "Which goals do assistant visitors complete?"
      ],
      "caveats": [
        "Inherits the whole classification problem of the sessions metric: with no assistant classifier, the population being converted is assembled by hand.",
        "Which goals are counted is a per-property configuration, so the same metric name means different things on two tenants, name the goals beside the number.",
        "Assistant-referred volumes are small on most sites, so a conversion count can move by a large percentage on a handful of events."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Attributing a conversion to an assistant when the analytics property is on last-click and the assistant was only the first touch.",
        "Comparing this against the ad platform's own conversion count, which is measured on a different model entirely."
      ],
      "notSameAs": [
        {
          "slug": "ai-referral-conversion-rate",
          "why": "The rate is its own measure in the semantic layer, not this count divided by anything you have to hand. Dividing a summed conversion count by a distinct-count session figure from a breakdown produces a different number from the rate the layer returns, and the two diverge most where the traffic is smallest, which is where assistant referrals live."
        }
      ],
      "related": [
        "ai-referral-sessions",
        "ai-referral-conversion-rate",
        "conversions-count",
        "per-goal-conversions"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-referral-session-change",
      "name": "AI referral session change",
      "aliases": [
        "Assistant referral trend",
        "AI referral session delta"
      ],
      "definition": "The movement in assistant-referred sessions between two comparable periods, in sessions and as a relative change.",
      "category": "AI referral traffic",
      "type": "derived metric",
      "unit": "sessions for the absolute move; the relative move inherits the product's contested delta-percent scale",
      "direction": "higher-better",
      "verification": "review",
      "aggregation": "A comparison between two period reads, not a measure that aggregates. Both periods must use the same source/medium selection or the change describes the selection rather than the traffic.",
      "grain": "One traffic-source value (or the whole-domain total) across a pair of date ranges.",
      "dimensions": [
        "source/medium",
        "landing page",
        "country",
        "device"
      ],
      "requiredFilters": [
        "date range",
        "comparison date range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "ai-referral-traffic-report"
      ],
      "skills": [
        "search-to-revenue",
        "significance-referee",
        "anomaly-investigator"
      ],
      "verbs": [],
      "rungs": [
        "R5"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "Is AI referral traffic growing?",
        "Did assistant referrals move enough to matter this month?"
      ],
      "caveats": [
        "Inherits the classification blocker: if the hand-picked source list differs between the two periods, the change is an artefact of the selection.",
        "The relative change is returned as a fraction by one part of the product and as a percent by another, so a delta percent is ambiguous until you know which produced it.",
        "At the volumes typical for assistant referrals, most period-over-period moves fail a significance test, report the trend across several periods rather than one comparison.",
        "A per-source time series is available, the trend mode combines with a traffic-source breakdown for exactly this, but a comparison range and a trend are still separate modes, so a two-period delta and a series are two reads, not one."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Quoting a triple-digit percentage growth that rests on a move from nine sessions to twenty-eight.",
        "Reading a delta percent as a percent when the module that produced it returned a fraction."
      ],
      "notSameAs": [],
      "related": [
        "ai-referral-sessions",
        "pop-delta",
        "pop-delta-pct",
        "real-noise-verdict"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-referral-sessions",
      "name": "AI referral sessions",
      "aliases": [
        "Assistant referral sessions",
        "LLM referral sessions",
        "AI-sourced sessions"
      ],
      "definition": "Sessions that begin on your site after a visitor follows a link out of an AI assistant, the visit half of the AI story, as distinct from being cited inside an answer.",
      "category": "AI referral traffic",
      "type": "raw measure",
      "unit": "sessions",
      "direction": "higher-better",
      "verification": "review",
      "aggregation": "The underlying session measure is a distinct-count sketch, not a sum, so session rows must never be added across a breakdown to reach a total, the total is its own read. Whole-domain only; the analytics dataset does not accept a segment.",
      "grain": "One traffic-source value (or the whole-domain total) for one date range.",
      "dimensions": [
        "source/medium",
        "landing page",
        "country",
        "device",
        "keyword",
        "intent",
        "category"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "ai-referral-traffic-report"
      ],
      "skills": [
        "search-to-revenue",
        "ai-citation-monitoring",
        "cross-domain-correlator"
      ],
      "verbs": [],
      "rungs": [
        "R5"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "How much traffic do AI assistants send us?",
        "Is AI referral traffic growing?",
        "Which assistant sends the most visits?"
      ],
      "caveats": [
        "Nothing in the product classifies a traffic source as an AI assistant. The analytics feed carries a free-text source/medium string, no code or semantic-layer field interprets any value as an assistant, and the governed surface says explicitly that there is no AI or LLM channel bucket to ask for. The grouping is done by eye.",
        "The way it is done: enumerate the real traffic-source values, pick the assistant ones by hand, and request that exact set, the read is restricted to those values, and any requested value that matched nothing is echoed back rather than silently dropped. A saved segment or a handful of contains-matches in the app is the same manoeuvre.",
        "The web-analytics dataset is whole-domain only: no segment scoping, so an assistant figure cannot be narrowed to a tracked segment.",
        "Assistants that strip or rewrite the referrer never appear at all, so any figure produced this way is a floor and not a total.",
        "Assistant hostnames and medium strings change without notice; a source that falls to zero is a renaming until proven otherwise."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Reading a hand-picked set of source/medium rows as if it were a measured AI channel.",
        "Reading a requested source that returned no rows as proof it does not exist, when the read was narrowed by the period and the other filters.",
        "Taking a top-N breakdown as the full assistant list, when a named source can be requested explicitly.",
        "Comparing an AI referral session count against a Search Console click count as if they were the same quantity."
      ],
      "notSameAs": [
        {
          "slug": "ai-citation-count",
          "why": "Being cited is not being visited. A citation is an answer engine using your URL as a source of its answer, it is counted on the AI-visibility dataset at R3 Referenced, and it happens whether or not anyone clicks. A referral session is a person arriving on your site, counted in web analytics at R5 Rewarded. Most citations produce no session, and a session can arrive from an assistant that never cited you in the tracked prompt basket, so the two never reconcile and neither can stand in for the other."
        }
      ],
      "related": [
        "ai-referral-conversions",
        "ai-referral-conversion-rate",
        "ai-referral-session-change",
        "ai-referral-source-split",
        "sessions"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-referral-source-split",
      "name": "AI referral source split",
      "aliases": [
        "AI assistant mix",
        "Referral split by assistant"
      ],
      "definition": "How assistant-referred sessions divide across the individual assistants, which answer surface is actually sending the traffic.",
      "category": "AI referral traffic",
      "type": "share",
      "unit": "percent of assistant-referred sessions attributed to each traffic-source value",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "A composition of one period's sessions across traffic-source values. The parts sum to the selected set, not to all assistant traffic, because unclassified and referrer-stripped visits sit outside it, and because the sessions measure is a distinct-count sketch, the parts need not add to the whole-domain total either.",
      "grain": "One traffic-source value within one date range, as a share of the selected set.",
      "dimensions": [
        "source/medium",
        "landing page",
        "country",
        "device"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "ai-referral-traffic-report"
      ],
      "skills": [
        "search-to-revenue",
        "ai-citation-monitoring",
        "cross-domain-correlator"
      ],
      "verbs": [],
      "rungs": [
        "R5"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "Which AI assistant sends us the most visits?",
        "Is our assistant traffic concentrated in one surface?"
      ],
      "caveats": [
        "The denominator is whatever set of traffic-source rows was selected by hand, so two people can produce different splits from the same data.",
        "The default breakdown ranks a top-N by volume, so a small assistant can fall outside it, but a named source can be requested explicitly, and any requested value that matched nothing is echoed back. A missing row is recoverable, not a dead end.",
        "This split is not comparable to the per-engine cut on the AI-visibility side: that one is scoped to a tracked prompt basket, this one to whatever referrers the analytics property recorded."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Reading a missing assistant as zero traffic when it fell outside the top-N, instead of requesting it by name.",
        "Lining this split up against the per-engine citation split and expecting the shares to correspond."
      ],
      "notSameAs": [
        {
          "slug": "ai-citation-category-mix",
          "why": "Both are compositions on the word 'AI', and they describe different populations on different datasets. The citation category mix divides your citations across content categories inside a tracked prompt basket at R3; this divides arriving sessions across referring assistants in web analytics at R5. Neither is a view of the other, and no row in one corresponds to a row in the other."
        }
      ],
      "related": [
        "ai-referral-sessions",
        "ai-referral-conversions",
        "sessions"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-answer-presence-score",
      "name": "AI answer presence score",
      "aliases": [
        "AI answer presence"
      ],
      "definition": "A weighted points total for how present your brand is in answer-engine responses: each citation counts 1.25 and each brand mention counts 1, summed over the tracked prompt basket for one answer engine.",
      "category": "AI visibility",
      "type": "score",
      "unit": "weighted points (citations weighted 1.25, mentions weighted 1)",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "(1.25 × your citations) + (1.0 × your mentions), summed over the slice. It is the numerator of AI share of voice, whose denominator applies the same weights to every tracked domain's citations and mentions.",
      "aggregation": "Additive points, so the cross-engine figure is the same quantity whether the semantic layer re-aggregates it or the verb sums the per-engine scores, both reduce to 1.25 × all your citations + 1.0 × all your mentions. It is a points total, not a ratio, so it is not comparable across segments or periods with different basket sizes.",
      "grain": "One answer engine, plus a cross-engine overall, for one tracked segment over one date range.",
      "dimensions": [
        "answer engine",
        "intent",
        "branded vs non-branded"
      ],
      "requiredFilters": [
        "tracker (unified segment id) for segment-scoped reads",
        "date range"
      ],
      "sources": [
        "ai-visibility"
      ],
      "reports": [
        "ai-visibility-report"
      ],
      "skills": [
        "aeo-audit",
        "quattr-iq"
      ],
      "verbs": [
        "ai_visibility_overview"
      ],
      "rungs": [
        "R3"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "What is our AI answer presence score?",
        "Which engine has the strongest presence score?"
      ],
      "interpretation": "Read it as the raw weight behind share of voice, not as a level with a ceiling, it has no upper bound and rises with basket size. The comparable figure is the share of voice built from it; the score itself is for ordering engines and periods with the same basket.",
      "caveats": [
        "A points total with no ceiling: it grows with the size of the tracked prompt basket, so two periods with different baskets are not comparable on this number.",
        "The country- and device-filtered path returns it empty. The filtered source does carry its own presence-score measure, but the verb does not request it there, this is a gap in what the verb asks for, not a gap in the data.",
        "The code carries an explicit guard against substituting mention counts for this score when it is absent, they are different quantities on different scales, and a card missing the score must show it missing.",
        "Answer-engine citations and Google's on-SERP AI Overviews are different surfaces, on different datasets, measured separately and never rolled together.",
        "Every figure is scoped to a tracked prompt basket, a sample, not a census, so the basket's coverage belongs beside the number it produced."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Substituting mention counts or citation counts when the score is absent.",
        "Comparing a score from the unfiltered grid against a country- or device-filtered card, where the verb leaves it empty.",
        "Reading it as a percentage or a 0 to 100 index, it is an unbounded points total.",
        "Comparing scores across periods whose prompt baskets differ in size."
      ],
      "notSameAs": [
        {
          "slug": "ai-mention-count",
          "why": "A weighted points total and a raw count. Mentions are one of the two inputs to the score, weighted 1 against a citation's 1.25, so the score moves when either input moves; the code guards against filling an absent score with mentions because they are not the same quantity."
        }
      ],
      "related": [
        "ai-citation-rate",
        "ai-share-of-voice",
        "ai-mention-count"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-citation-count",
      "name": "AI citation count",
      "aliases": [
        "Citations",
        "Total citations"
      ],
      "definition": "The number of times answer engines cited your site across the tracked prompt basket in a period.",
      "category": "AI visibility",
      "type": "raw measure",
      "unit": "citations",
      "direction": "higher-better",
      "verification": "inferred",
      "aggregation": "Additive across answer engines, prompts and cited URLs, the verbs sum it to build per-prompt and per-URL totals. Where the semantic layer's own aggregate row is available the verbs report that instead of their own sum.",
      "grain": "One answer engine, prompt, cited URL or competitor domain for one tracked segment over one date range.",
      "dimensions": [
        "answer engine",
        "prompt",
        "cited URL",
        "competitor domain",
        "citation category",
        "intent",
        "branded vs non-branded"
      ],
      "requiredFilters": [
        "tracker (unified segment id) or tracked segment id",
        "date range"
      ],
      "sources": [
        "ai-visibility"
      ],
      "reports": [
        "ai-bot-activity-report",
        "ai-visibility-report"
      ],
      "skills": [
        "aeo-audit",
        "ai-citation-monitoring",
        "ai-visibility-pulse",
        "competitor-deep-dive",
        "quattr-iq"
      ],
      "verbs": [
        "ai_visibility_citation_audit",
        "ai_visibility_overview",
        "ai_visibility_trend",
        "ai_visibility_drilldown",
        "ai_page_citations"
      ],
      "rungs": [
        "R3"
      ],
      "levers": [
        "L7",
        "L6"
      ],
      "questions": [
        "How many citations did we earn last month?",
        "Which engine produced most of our citations?",
        "Did our citation count grow while the rate stayed flat?"
      ],
      "interpretation": "The count moves with basket size as well as with performance, so it is read next to the collected-prompt count rather than alone. A count that grew while the rate held usually means the basket grew, not that the answers changed.",
      "caveats": [
        "Two different constructions carry the word \"citations\". On the AI-visibility grid and trend it is a summed client-citation quantity from the answer-engine dataset; on the cited-URL and prompt paths it is a row count of market-share rank rows that carry a cited page URL. They are close in meaning and not guaranteed to reconcile exactly.",
        "This is an aggregated cited-page count across all answer-engine runs in the period, not a per-engine sampled share estimate with a confidence interval, the per-engine interval needs a repeated-sampling harness that is not in place.",
        "Every figure is scoped to a tracked prompt basket, a sample, not a census, so the basket's coverage belongs beside the number it produced.",
        "Engines are non-deterministic: the same prompt can answer differently twice, so a count is a count of observations, not of distinct facts about the world.",
        "A large share of citation inventory is third-party content, so a citation count is not by itself a count of your own pages performing.",
        "The shipped name-based formatter classifies the underlying per-row citation measure as a percentage because the word \"citation\" sits in its percent list. The verbs rename the field before it reaches a card, so the misclassification does not currently reach this number, but any new surface reading the raw field name would render a count with a percent sign."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Comparing counts across periods whose prompt baskets differ in size.",
        "Presenting a count as a share of anything, the denominator is not carried with it.",
        "Summing citations and mentions into one AI number."
      ],
      "notSameAs": [
        {
          "slug": "ai-mention-count",
          "why": "Separate measures on separate rows. Citations count your URL being used as a source; mentions count your brand being named. They are reported as side-by-side columns and are never added together."
        },
        {
          "slug": "ai-overview-inclusion",
          "why": "A citation is an answer engine sourcing your URL; AI Overview inclusion is presence in Google's on-SERP answer box on a different dataset. The two are named separately every time they could be confused."
        },
        {
          "slug": "prompt-citation-count",
          "why": "Same underlying events at a different grain and from a different verb family, the account-level count is not the sum of the prompts returned here, because only the requested or busiest prompts are returned.",
          "mirroredFrom": "prompt-citation-count"
        },
        {
          "slug": "ai-referral-sessions",
          "why": "Being cited is not being visited. This counts answer engines using your URL as a source, on the AI-visibility dataset at R3 Referenced, and it happens whether or not anyone clicks through. Referral sessions count people arriving on your site, in web analytics at R5 Rewarded. Most citations produce no session at all, and sessions can arrive from an assistant that never cited you inside the tracked prompt basket, the two never reconcile, and a rise in one is not evidence about the other.",
          "mirroredFrom": "ai-referral-sessions"
        }
      ],
      "related": [
        "ai-citation-rate",
        "cited-page-citation-count",
        "prompt-citation-count",
        "ai-mention-count",
        "ai-referral-sessions"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-citation-rate",
      "name": "AI citation rate",
      "aliases": [
        "Citation rate",
        "Citation %",
        "Citation percentage"
      ],
      "definition": "Your share of all the citations answer engines awarded across the tracked competitor set for a prompt basket, your citations as a percentage of every tracked domain's citations, not the proportion of answers that cited you.",
      "category": "AI visibility",
      "type": "share",
      "unit": "percent of all tracked domains' answer-engine citations",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "(your citations / all tracked domains' citations) × 100, computed by the semantic layer on every AI-visibility source. The product labels it a citation market share of tracked demand in answer engines, and the drilldown sources label the identical formula \"Citation Share %\", it is a share, not a rate of inclusion.",
      "numerator": "Citations of your domain in answer-engine responses in the slice.",
      "denominator": "Citations of every tracked domain, you and the tracked competitors, in the same slice.",
      "aggregation": "Never average the per-platform percentages to get the cross-platform figure. The verbs run the summary dataset twice, once grouped by answer engine for the rows, once measure-only so the semantic layer re-aggregates the ratio, and the second read is the number reported as overall.",
      "grain": "One answer engine (or the cross-engine overall) for one tracked segment over one date range.",
      "dimensions": [
        "answer engine",
        "intent",
        "branded vs non-branded",
        "country",
        "device",
        "competitor domain"
      ],
      "requiredFilters": [
        "tracker (unified segment id) for segment-scoped reads",
        "date range"
      ],
      "sources": [
        "ai-visibility"
      ],
      "reports": [
        "ai-visibility-report",
        "monthly-executive-search-report"
      ],
      "skills": [
        "ai-visibility-pulse",
        "aeo-audit",
        "ai-citation-monitoring",
        "search-pulse",
        "ai-vs-traditional-gap",
        "quattr-iq"
      ],
      "verbs": [
        "ai_visibility_citation_audit",
        "ai_visibility_overview",
        "ai_visibility_trend",
        "ai_visibility_drilldown",
        "ai_visibility_competitors"
      ],
      "rungs": [
        "R3"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "How often does ChatGPT cite us?",
        "Is our citation rate rising or falling?",
        "Which answer engine cites us least?"
      ],
      "interpretation": "Read it per engine before reading it blended, engines differ enough that one weak engine can hide inside a healthy overall. Because the denominator is the tracked roster, it moves when a competitor gains or loses citations even if yours are flat. A move at low citation counts is direction, not a result.",
      "caveats": [
        "The name says rate; the formula is a share. It does not answer \"what fraction of answers cited us\", it answers \"what fraction of the tracked set's citations were ours\", so it falls when a rival gains even if your own citations hold.",
        "The denominator is the tracked competitor set, not every domain an engine could cite. An untracked domain taking citations does not appear in it.",
        "Answer-engine citations and Google's on-SERP AI Overviews are different surfaces, on different datasets, measured separately and never rolled together.",
        "Every figure is scoped to a tracked prompt basket, a sample, not a census, so the basket's coverage belongs beside the number it produced.",
        "Engines are non-deterministic: the same prompt can answer differently twice, which is why this is reported as a rate over repeated observation rather than as a state.",
        "The answer-engine filter keys on the platform key (\"chatgpt\", \"gemini\"), not the display name; filtering the display dimension with a key returns no rows.",
        "Where a period-over-period comparison is attached, the delta percentage is returned as a fraction by the shared comparison helper and as a percentage by the significance verbs, check which one a card is rendering."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Reading it as an inclusion rate, \"engines cite us in 12% of answers\", when it is a share of the tracked set's citations.",
        "Reading a blended cross-engine figure as if it described every engine.",
        "Treating a week-over-week move at single-digit citation counts as a trend.",
        "Assuming an empty result means zero citations when it means the tracker, segment or platform filter did not bind."
      ],
      "notSameAs": [
        {
          "slug": "ai-mention-share",
          "why": "Same denominator family, different behaviour counted. A citation is your URL used as a source of the answer; a mention is your brand named in the answer text. A majority of citations produce no mention, so the two shares diverge routinely."
        },
        {
          "slug": "ai-share-of-voice",
          "why": "Both are shares against the same tracked set, over different numerators. This one counts citations only; share of voice adds mentions at a weight of 1 against a citation's 1.25 and divides by the same weighted total. A rising citation share can sit beside a flat share of voice when mentions moved the other way."
        },
        {
          "slug": "ai-overview-inclusion",
          "why": "Different surfaces entirely. This is an answer engine citing your URL as a source; AI Overview inclusion is Google's on-SERP answer box, measured on a separate dataset. Every AI-visibility verb opens its description by disclaiming the swap."
        },
        {
          "slug": "prompt-citation-share",
          "why": "Same ratio at two grains, and they do not decompose into each other: the prompt-level figure divides within one prompt, the account-level figure divides across the whole slice. A prompt where you hold every citation can sit inside a slice where you hold very few.",
          "mirroredFrom": "prompt-citation-share"
        }
      ],
      "related": [
        "ai-citation-count",
        "ai-share-of-voice",
        "ai-mention-share",
        "prompt-citation-share",
        "cited-page-citation-count"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-mention-count",
      "name": "AI mention count",
      "aliases": [
        "Mentions",
        "Total AI-answer mentions",
        "Brand mentions in AI answers"
      ],
      "definition": "The number of answer-engine responses in the period that named your brand.",
      "category": "AI visibility",
      "type": "raw measure",
      "unit": "mentions",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "The sum of your brand's mention counts across the answer-engine responses in the slice. Three differently named semantic-layer measures carry it depending on which source a verb reads, the grid's client-mention sum, the drilldown sources' all-mention sum for your row, and the prompt path's validated visible-mention sum, and all three sum the same underlying per-response counts.",
      "aggregation": "Additive across prompts and answer engines, the prompt-level verbs sum it per prompt to build the mention column and the share-of-voice input.",
      "grain": "One answer engine, prompt or competitor domain for one tracked segment over one date range.",
      "dimensions": [
        "answer engine",
        "prompt",
        "competitor domain",
        "intent",
        "branded vs non-branded"
      ],
      "requiredFilters": [
        "tracker (unified segment id) or tracked segment id",
        "date range"
      ],
      "sources": [
        "ai-visibility"
      ],
      "reports": [
        "ai-visibility-report"
      ],
      "skills": [
        "aeo-audit",
        "ai-citation-monitoring",
        "competitor-deep-dive",
        "quattr-iq"
      ],
      "verbs": [
        "ai_visibility_overview",
        "ai_visibility_competitors",
        "ai_visibility_drilldown",
        "ai_visibility_trend"
      ],
      "rungs": [
        "R4",
        "R3"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "How many AI answers mentioned us last month?",
        "Do we get mentioned without being cited?"
      ],
      "interpretation": "Reported beside the citation count, never added to it. The two columns diverging is the normal case rather than a data problem.",
      "caveats": [
        "Three differently named semantic-layer fields feed this output key depending on which source a verb reads, the grid, the drilldown and the prompt-level path each name it differently, and the prompt path prefers validated visible mentions over legacy engine-reported counts where both exist.",
        "Every figure is scoped to a tracked prompt basket, a sample, not a census, so the basket's coverage belongs beside the number it produced.",
        "Engines are non-deterministic: the same prompt can answer differently twice, so this counts observations of a mention rather than distinct facts.",
        "It moves with basket size as well as with performance, so it is read next to the collected-prompt coverage rather than alone."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Adding mentions to citations to produce one AI number.",
        "Reading a rise in mentions as a rise in favourable coverage without the sentiment split."
      ],
      "notSameAs": [
        {
          "slug": "ai-citation-count",
          "why": "Separate measures kept in separate columns: a mention names your brand in the answer, a citation sources your URL for it. Most citations carry no mention, so summing them double-counts nothing and describes nothing."
        },
        {
          "slug": "ai-answer-presence-score",
          "why": "A count and a weighted points total. Mentions are one input to the score at a weight of 1 against a citation's 1.25; the code guards against filling an absent score with mentions because they are not the same quantity."
        },
        {
          "slug": "serp-brand-mentions",
          "why": "On-SERP brand mentions are observed in Google search results. AI-answer mentions are counted inside answer-engine responses. A brand can be mentioned constantly on the SERP and never inside an answer."
        },
        {
          "slug": "ai-mention-share",
          "why": "A share and a count. The share needs a denominator of all tracked brands' mentions; the count is your mentions alone and moves with basket size.",
          "mirroredFrom": "ai-mention-share"
        }
      ],
      "related": [
        "ai-mention-share",
        "ai-positive-mention-count",
        "ai-citation-count"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-mention-share",
      "name": "AI mention share",
      "aliases": [
        "Mentions %",
        "Share of answers",
        "Mention rate"
      ],
      "definition": "The share of answer-engine responses naming your brand, relative to the brands named across the tracked set.",
      "category": "AI visibility",
      "type": "share",
      "unit": "percent of tracked answer-engine mentions",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "(your mentions / all tracked domains' mentions) × 100. Two differently named semantic-layer measures carry it, the grid's and the drilldown sources', and both compute the identical ratio under the label \"Share of Answers\".",
      "numerator": "Mentions of your brand in answer-engine responses in the slice.",
      "denominator": "Mentions of every tracked domain in the same slice.",
      "aggregation": "Never average the per-engine percentages for a cross-engine figure; the semantic layer re-aggregates the ratio on a measure-only read.",
      "grain": "One answer engine or competitor domain for one tracked segment over one date range.",
      "dimensions": [
        "answer engine",
        "competitor domain",
        "intent",
        "country",
        "device",
        "branded vs non-branded"
      ],
      "requiredFilters": [
        "tracker (unified segment id) for segment-scoped reads",
        "date range"
      ],
      "sources": [
        "ai-visibility"
      ],
      "reports": [
        "ai-visibility-report"
      ],
      "skills": [
        "aeo-audit",
        "ai-vs-traditional-gap",
        "competitor-deep-dive",
        "quattr-iq"
      ],
      "verbs": [
        "ai_visibility_overview",
        "ai_visibility_competitors",
        "ai_visibility_drilldown"
      ],
      "rungs": [
        "R4",
        "R3"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "How often do AI answers name us versus our rivals?",
        "Are we mentioned more than we are cited?"
      ],
      "interpretation": "Mention share and citation rate answer different questions and routinely diverge, being named without being sourced is common, and the gap between the two columns is itself the read.",
      "caveats": [
        "Two differently named semantic-layer fields feed this one output key depending on which source a verb reads. They compute the same ratio, so a grid figure and a drilldown figure are the same measure under two names, but the names differ in exports and in the app.",
        "The denominator is the tracked competitor set, not every brand an engine could name.",
        "Being named in an answer says nothing about being described correctly, that is the sentiment read, and canon flags the Represented rung as only partly instrumented.",
        "Every figure is scoped to a tracked prompt basket, a sample, not a census, so the basket's coverage belongs beside the number it produced.",
        "Engines are non-deterministic: the same prompt can answer differently twice, which is why this is reported as a rate over repeated observation rather than as a state."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Using mention share as a proxy for citation rate when a citation column is empty.",
        "Blending mentions and citations into a single AI visibility number."
      ],
      "notSameAs": [
        {
          "slug": "ai-citation-rate",
          "why": "Same denominator family, different behaviour counted. A mention is your brand named in the answer text; a citation is your URL used as a source. The two are carried as separate columns everywhere and a majority of citations arrive with no mention attached."
        },
        {
          "slug": "ai-mention-count",
          "why": "A share and a count. The share needs a denominator of all tracked brands' mentions; the count is your mentions alone and moves with basket size."
        }
      ],
      "related": [
        "ai-mention-count",
        "ai-citation-rate",
        "ai-share-of-voice",
        "prompt-mention-share"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-share-of-voice",
      "name": "AI share of voice",
      "aliases": [
        "Share of Voice %",
        "AI answer share of voice",
        "SoV"
      ],
      "definition": "A single figure combining how often answer engines cite you and how often they name you, expressed as a share of the same weighted total across the tracked competitor set.",
      "category": "AI visibility",
      "type": "share",
      "unit": "percent of tracked answer-engine voice",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "(1.25 × your citations + 1.0 × your mentions) ÷ (1.25 × all tracked domains' citations + 1.0 × all tracked domains' mentions) × 100. The numerator is the AI answer presence score; the denominator applies the same two weights to the whole tracked set.",
      "numerator": "Your citations weighted 1.25 plus your mentions weighted 1, the AI answer presence score.",
      "denominator": "The same weighted combination computed over every tracked domain, you included.",
      "aggregation": "Never average the per-engine percentages for a cross-engine figure, the semantic layer re-aggregates the ratio on a measure-only read. The competitor, intent, geography and brand tabs rank rows by this measure; the prompt tab ranks by mentions and the cited-URL tab by citations, so a share-of-voice ordering is not universal across the drilldown.",
      "grain": "One competitor domain (including your own), answer engine, intent, country, device or brand bucket for one tracked segment over one date range.",
      "dimensions": [
        "competitor domain",
        "answer engine",
        "intent",
        "country",
        "device",
        "branded vs non-branded"
      ],
      "requiredFilters": [
        "tracker (unified segment id)",
        "date range"
      ],
      "sources": [
        "ai-visibility"
      ],
      "reports": [
        "ai-visibility-report"
      ],
      "skills": [
        "aeo-audit",
        "ai-visibility-pulse",
        "competitor-deep-dive",
        "quattr-iq"
      ],
      "verbs": [
        "ai_visibility_overview",
        "ai_visibility_competitors",
        "ai_visibility_trend",
        "ai_visibility_drilldown"
      ],
      "rungs": [
        "R3"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "What is our share of voice in AI answers?",
        "Who leads share of voice on this tracker?",
        "Is our share of voice improving per engine?"
      ],
      "interpretation": "Read as standing against the tracked competitor set, not as a share of all AI answers everywhere. Because it folds two behaviours into one number under fixed weights, a move is a prompt to look at the citation and mention columns underneath it rather than a finding on its own.",
      "caveats": [
        "The 1.25 and 1.0 weights are a product decision carried in the semantic layer, not a quantity any engine reports. The ordering changes if the weights change.",
        "The measure read by these verbs is the position-agnostic one. An older position-weighted variant still exists beside it, labelled \"Share of Answers (%)\"; it is deliberately not read, so a figure quoted from an older report may not match.",
        "Absence from the standings means untracked, not absent, a competitor the segment does not track cannot appear in the denominator or the ranking.",
        "Every figure is scoped to a tracked prompt basket, a sample, not a census, so the basket's coverage belongs beside the number it produced."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Reading it as a share of the entire AI-answer market rather than of the tracked competitor set.",
        "Explaining a share-of-voice move without checking whether it came from the citation half or the mention half.",
        "Comparing it against a figure produced by the deprecated position-weighted variant, which carries a different formula and an adjustment constant."
      ],
      "notSameAs": [
        {
          "slug": "ai-citation-rate",
          "why": "Share of voice is the weighted blend of citations and mentions over the tracked set; the citation share is citations alone over the same set. They share a denominator family, so the gap between them is entirely the mention half."
        },
        {
          "slug": "prompt-share-of-voice-share",
          "why": "Same weights, two grains and two implementations. This one is a semantic-layer measure over the whole slice; the prompt-level one is computed in the verb per prompt, dividing your weighted voice by every cited domain's weighted voice for that prompt. Neither decomposes into the other."
        },
        {
          "slug": "ai-overview-inclusion",
          "why": "Share of voice is measured on answer-engine responses; AI Overview inclusion is Google's on-SERP feature on a different dataset. Neither is folded into the other."
        },
        {
          "slug": "search-market-share",
          "why": "Both get called \"share of voice\". This one is CTR-modeled search market share of tracked demand on the Google SERP; the other is share of answer-engine responses. Different surfaces, different denominators, and they move independently."
        },
        {
          "slug": "prompt-share-of-voice-score",
          "why": "A share and the points total it is built from. The score is your weighted voice alone; this is that score over the tracked set's weighted total. The score rises with basket size; the share does not.",
          "mirroredFrom": "prompt-share-of-voice-score"
        },
        {
          "slug": "ai-competitive-rank",
          "why": "A position and the quantity it was ordered by. Share of voice can fall while the rank holds, and the rank can fall on a share-of-voice gain if a rival gained more.",
          "mirroredFrom": "ai-competitive-rank"
        }
      ],
      "related": [
        "ai-citation-rate",
        "ai-mention-share",
        "prompt-share-of-voice-score",
        "ai-competitive-rank"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-avg-citation-position",
      "name": "Average citation position",
      "aliases": [
        "Avg citation position"
      ],
      "definition": "Where a cited URL tends to appear in the answer's citation order, averaged over the period.",
      "category": "AI visibility",
      "type": "rank",
      "unit": "average ordinal position in the answer's citation list",
      "direction": "lower-better",
      "verification": "verified",
      "calculation": "The arithmetic mean of the citation-position value across the cited-URL rows in the slice, a plain average of an ordinal, with no weighting by citation count.",
      "aggregation": "An average already, never sum it. Averaging two of these without their citation counts as weights is wrong, and the measure itself does not carry that weighting.",
      "grain": "One cited URL for one tracked segment over one date range.",
      "dimensions": [
        "cited URL",
        "competitor domain",
        "citation category",
        "prompt",
        "answer engine"
      ],
      "requiredFilters": [
        "tracker or tracked segment id",
        "date range"
      ],
      "sources": [
        "ai-visibility",
        "rank-tracking"
      ],
      "reports": [
        "ai-visibility-report"
      ],
      "skills": [
        "ai-citation-monitoring",
        "aeo-audit",
        "competitor-deep-dive"
      ],
      "verbs": [
        "ai_page_citations"
      ],
      "rungs": [
        "R3"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "Are our pages cited first or last in AI answers?",
        "Which competitor pages sit ahead of ours in the citation list?"
      ],
      "interpretation": "Read beside the citation count for the same URL: a page cited often but late is a different situation from one cited rarely but first. Position is ordinal, so a change of half a place is not a magnitude.",
      "caveats": [
        "It averages an ordinal, so the arithmetic is exact but the distances are not meaningful: the gap between slot 1 and 2 is not the same quantity as the gap between 8 and 9.",
        "Direction is not asserted by the semantic layer. Lower-is-better here comes from a name-based rule that treats anything containing \"position\" as lower-better, a sound convention for this field, but a convention rather than a pinned claim.",
        "Only rows carrying a cited URL contribute, so the average describes cited pages rather than the answer as a whole.",
        "Engines are non-deterministic: the same prompt can answer differently twice, so the average is over repeated observation rather than a stable placement."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Treating a move from 3.4 to 2.9 as an improvement of half a citation slot rather than a small ordinal shift.",
        "Averaging positions across pages without weighting by citations."
      ],
      "notSameAs": [
        {
          "slug": "cited-page-citation-count",
          "why": "How often a page is cited and where it sits when cited are separate readings, a page can hold the top slot on one prompt and be absent everywhere else."
        }
      ],
      "related": [
        "cited-page-citation-count",
        "ai-citation-category-mix",
        "prompt-citation-count"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-citation-category-mix",
      "name": "Citation category mix",
      "aliases": [
        "Cited URL categories",
        "Citation category breakdown"
      ],
      "definition": "The Citation Category summary on the cited-URL drilldown: your citations grouped by a category attached to the cited page, with each group's percentage of the slice.",
      "category": "AI visibility",
      "type": "share",
      "unit": "percent of your citations in the slice",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "The percentages complete the slice, so they are read together; a single group's figure means little without the mix beside it.",
      "grain": "One citation category within one tracked segment, date range and cited-URL slice.",
      "dimensions": [
        "citation category",
        "answer engine",
        "intent",
        "branded vs non-branded",
        "country",
        "device"
      ],
      "requiredFilters": [
        "tracker (unified segment id)",
        "date range"
      ],
      "sources": [
        "ai-visibility",
        "rank-tracking"
      ],
      "reports": [
        "ai-visibility-report"
      ],
      "skills": [
        "aeo-audit",
        "ai-citation-monitoring",
        "ai-prompt-coverage-gaps"
      ],
      "verbs": [
        "ai_visibility_drilldown"
      ],
      "rungs": [
        "R3"
      ],
      "levers": [
        "L7",
        "L3"
      ],
      "questions": [
        "What kind of pages do AI answers cite us for?",
        "Are we cited for documentation or for comparisons?"
      ],
      "caveats": [
        "Which taxonomy this actually is has not been settled. The surface advertises citation types, blog, comparison, product, documentation, but the verb reads the generic content-category dimension, while a purpose-built citation-category dimension with exactly that taxonomy exists beside it and is not read.",
        "The category field is not populated for every slice; when it comes back empty across the board the summary is omitted with a stated reason rather than shown as zeros.",
        "A transient failure to fetch the category summary is reported separately from the category not being live at all, and neither affects the cited-URL rows in the same response.",
        "Categories describe an attribute of the page; they are not a statement about why the engine chose it.",
        "Every figure is scoped to a tracked prompt basket, a sample, not a census, so the basket's coverage belongs beside the number it produced."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Reading an omitted summary as an even split or as zero citations.",
        "Treating a transient failure of the category leg as evidence the field does not exist.",
        "Briefing content work off group labels before it is settled which taxonomy produced them."
      ],
      "notSameAs": [
        {
          "slug": "cited-page-citation-count",
          "why": "The mix is a distribution over page groups; the page count is the citation total for one URL. The mix can shift with no change in total citations, and unlike the page count, which taxonomy the mix uses is still under review."
        },
        {
          "slug": "ai-referral-source-split",
          "why": "Two compositions that both carry the word AI, over different populations on different datasets. This divides your citations across content categories inside a tracked prompt basket at R3; the referral source split divides arriving sessions across referring assistants in web analytics at R5. No row in one corresponds to a row in the other, and neither is a view of the other.",
          "mirroredFrom": "ai-referral-source-split"
        }
      ],
      "related": [
        "cited-page-citation-count",
        "ai-avg-citation-position",
        "ai-citation-count",
        "ai-referral-source-split"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "cited-page-citation-count",
      "name": "Citations per cited page",
      "aliases": [
        "Cited URL citations",
        "Citations by page"
      ],
      "definition": "How many times answer engines cited one specific URL of yours, or of a named competitor, in the period.",
      "category": "AI visibility",
      "type": "raw measure",
      "unit": "citations",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "A row count of market-share rank rows for the URL, filtered to rows that carry a cited page URL, one row is one citation instance. The leaderboard sums it per URL and orders descending.",
      "aggregation": "Additive across prompts; the verb sums it per URL and per citation category, and orders the leaderboard by it descending.",
      "grain": "One cited URL for one tracked segment over one date range.",
      "dimensions": [
        "cited URL",
        "competitor domain",
        "citation category",
        "answer engine",
        "intent",
        "branded vs non-branded"
      ],
      "requiredFilters": [
        "tracker or tracked segment id",
        "date range"
      ],
      "sources": [
        "ai-visibility",
        "rank-tracking"
      ],
      "reports": [
        "ai-bot-activity-report",
        "ai-referral-traffic-report",
        "ai-visibility-report"
      ],
      "skills": [
        "ai-citation-monitoring",
        "aeo-audit",
        "ai-prompt-coverage-gaps",
        "competitor-deep-dive"
      ],
      "verbs": [
        "ai_page_citations",
        "ai_visibility_drilldown"
      ],
      "rungs": [
        "R3"
      ],
      "levers": [
        "L7",
        "L6"
      ],
      "questions": [
        "Which of our pages do AI answers cite most?",
        "Which of a competitor's pages earn their citations?",
        "Did we gain or lose cited pages this month?"
      ],
      "interpretation": "This is the supply side of being referenced, the specific pages answers are built from. It joins naturally to whether AI crawlers fetched those pages, which is the question a citation count alone cannot answer.",
      "caveats": [
        "A \"citation\" here is one rank row carrying a page URL, so the count is of citation instances rather than of distinct answers or distinct prompts.",
        "Rows without a cited URL are filtered out twice, once by the measure itself and again in the verb, so the leaderboard describes pages, not every citation event in the period.",
        "Your own pages are scoped by the configured customer site's exact www and apex aliases rather than by a domain dimension, so a page served from an unconfigured subdomain will not appear in your rows.",
        "This is an aggregated cited-page count across all answer-engine runs in the period, not a per-engine sampled share estimate with a confidence interval.",
        "New and lost cited URLs churn at low counts; weekly movement on a single URL is direction, not a result.",
        "The shipped name-based formatter classifies this measure as a percentage because the word \"citation\" sits in its percent list. The verbs rename it before it reaches a card, so the count renders correctly today, but the raw field name would render \"412\" as \"412%\".",
        "Answer-engine citations and Google's on-SERP AI Overviews are different surfaces, on different datasets, measured separately and never rolled together."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Reading a page's citation count as traffic, a citation is not a visit.",
        "Concluding a page lost citations when the prompt basket that used to reach it changed."
      ],
      "notSameAs": [
        {
          "slug": "ai-overview-inclusion",
          "why": "A cited page is a URL an answer engine sourced; AI Overview inclusion is presence in Google's on-SERP answer box, measured on a different dataset. The verb descriptions open by disclaiming the swap."
        },
        {
          "slug": "prompt-citation-count",
          "why": "Page grain versus prompt grain. One page can be cited across many prompts and one prompt can cite many pages, so neither total decomposes cleanly into the other."
        },
        {
          "slug": "ai-avg-citation-position",
          "why": "How often a page is cited and where it sits when cited are separate readings, a page can hold the top slot on one prompt and be absent everywhere else.",
          "mirroredFrom": "ai-avg-citation-position"
        },
        {
          "slug": "ai-citation-category-mix",
          "why": "The mix is a distribution over content types; the page count is the citation total for one URL. The mix can shift with no change in total citations.",
          "mirroredFrom": "ai-citation-category-mix"
        }
      ],
      "related": [
        "ai-citation-count",
        "ai-avg-citation-position",
        "ai-citation-category-mix",
        "prompt-citation-count"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "prompt-citation-count",
      "name": "Citations per prompt",
      "aliases": [
        "Prompt citations",
        "Total citations for a prompt"
      ],
      "definition": "How many citations one answer-engine prompt produced in the period, split into the citations your domain earned and the total across every cited domain.",
      "category": "AI visibility",
      "type": "raw measure",
      "unit": "citations",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "Two reads of the same rank dataset that differ only by the client filter, one restricted to your domain, one unrestricted, each summed per prompt in the verb and then joined on the prompt key. The client total is the restricted sum; the prompt total is the unrestricted sum, falling back to the client total when the unrestricted leg returns nothing for that prompt.",
      "aggregation": "Additive within a prompt across domains and URLs. The prompt tab orders by mentions, not by this total, so the busiest-citation prompt is not necessarily the first row.",
      "grain": "One prompt for one tracked segment over one date range, with a domain breakdown beneath it.",
      "dimensions": [
        "prompt",
        "competitor domain",
        "cited URL",
        "answer engine",
        "intent",
        "branded vs non-branded"
      ],
      "requiredFilters": [
        "tracker or tracked segment id",
        "date range"
      ],
      "sources": [
        "ai-visibility",
        "rank-tracking"
      ],
      "reports": [
        "ai-visibility-report"
      ],
      "skills": [
        "aeo-audit",
        "ai-prompt-coverage-gaps",
        "ai-citation-monitoring"
      ],
      "verbs": [
        "ai_visibility_drilldown"
      ],
      "rungs": [
        "R3"
      ],
      "levers": [
        "L7",
        "L5"
      ],
      "questions": [
        "Who wins the prompts we are missing from?",
        "Which pages beat us on this prompt?",
        "Which prompts produce the most citations at all?"
      ],
      "interpretation": "The client total against the prompt total is the competitive read at prompt grain. A prompt with a large total and a zero client total is the shape a coverage gap takes; a zero total on both sides is a prompt nobody was cited for.",
      "caveats": [
        "The two totals come from two queries joined on the prompt key inside the verb, not from one keyed result set, they are the same query with and without the client filter, which is a narrower guarantee than a single result set.",
        "There is no domain breakdown on this path. The prompt total names no rivals, so a prompt-to-winner-to-URL table cannot be assembled from it.",
        "When the unrestricted leg returns no row for a prompt, the prompt total falls back to your own total, which makes your share of that prompt read as complete rather than unknown.",
        "This is an aggregated cited-page count across all answer-engine runs in the period, not a per-engine sampled share estimate with a confidence interval.",
        "Rows without a cited URL do not contribute, so a domain that was named but not sourced does not appear here.",
        "Engines are non-deterministic: the same prompt can answer differently twice, so these totals count observations over repeated runs."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Assembling a prompt-to-winner-to-URL table by joining separate verb results, this path carries no winner.",
        "Reading a zero client total on a low-total prompt as a competitive loss.",
        "Reading a hundred-percent client share without checking whether the all-domain leg returned a row at all."
      ],
      "notSameAs": [
        {
          "slug": "prompt-cited-pages-count",
          "why": "This counts citation events for the prompt; the cited-pages count counts how many distinct pages of yours the answer drew on, and it comes from a different dataset and a different verb. A prompt can cite one page many times or many pages once."
        },
        {
          "slug": "ai-citation-count",
          "why": "Same behaviour at a different grain, computed on a different dataset, the account-level count is a semantic-layer citation sum, this is a per-prompt row count assembled in the verb. They will not add up."
        },
        {
          "slug": "cited-page-citation-count",
          "why": "Page grain versus prompt grain. One page can be cited across many prompts and one prompt can cite many pages, so neither total decomposes cleanly into the other.",
          "mirroredFrom": "cited-page-citation-count"
        }
      ],
      "related": [
        "cited-page-citation-count",
        "prompt-citation-share",
        "prompt-cited-pages-count",
        "ai-avg-citation-position"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "prompt-cited-pages-count",
      "name": "Cited pages per prompt",
      "aliases": [
        "Cited pages count",
        "Pages cited in the answer"
      ],
      "definition": "How many of your pages the answer to one tracked prompt drew on, the measure the coverage-gap and citation-attribution rankings are built from.",
      "category": "AI visibility",
      "type": "raw measure",
      "unit": "cited pages",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "A distinct count of your customer pages per prompt. The coverage-gap verb sorts it ascending, the attribution verb sorts it descending; both read the same measure on the same dataset.",
      "aggregation": "Reported per prompt and ranked, not summed into a total, the same page cited on two prompts would be counted twice by a naive sum.",
      "grain": "One prompt for one tracked segment over one date range.",
      "dimensions": [
        "prompt",
        "intent",
        "answer engine",
        "branded vs non-branded"
      ],
      "requiredFilters": [
        "tracked segment id or tracker",
        "date range"
      ],
      "sources": [
        "ai-visibility",
        "rank-tracking"
      ],
      "reports": [],
      "skills": [
        "ai-prompt-coverage-gaps",
        "aeo-audit",
        "ai-citation-monitoring"
      ],
      "verbs": [
        "ai_prompt_coverage_gap",
        "ai_citation_attribution"
      ],
      "rungs": [
        "R2",
        "R3"
      ],
      "levers": [
        "L7",
        "L5"
      ],
      "questions": [
        "Which AI prompts do not cite us?",
        "Which prompts cite us most?",
        "Where are our AI-answer coverage gaps?"
      ],
      "interpretation": "Sorted ascending it is the coverage-gap list; sorted descending it is the attribution list. The same measure answers both questions, which is why the two verbs return the same field in opposite order.",
      "caveats": [
        "A distinct count of pages, not of citations, the same page cited three times on one prompt counts once.",
        "This is an aggregated cited-page count across all answer-engine runs in the period, not a per-engine sampled share estimate with a confidence interval.",
        "A gap where every winner is third-party content is earned media rather than a brief for a new page.",
        "Every figure is scoped to a tracked prompt basket, a sample, not a census, so the basket's coverage belongs beside the number it produced.",
        "Prompt-level mention and sentiment enrichment is best-effort: when that leg fails the coverage answer still returns, with the mention columns empty rather than zero.",
        "Both verbs require the market-share source; without it they return a stated note rather than rows."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Reading a zero as absence from the answer engine when the tracker has no segment for the requested engine, the verb returns an explicit no-data note for that case, and the note is the answer.",
        "Summing cited pages across prompts into a distinct-page total."
      ],
      "notSameAs": [
        {
          "slug": "prompt-citation-count",
          "why": "Pages versus citation events. A prompt that cites one page three times has one cited page and three citations."
        }
      ],
      "related": [
        "prompt-citation-count",
        "prompt-citation-share"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-negative-sentiment-rate",
      "name": "Negative sentiment share of AI mentions",
      "aliases": [
        "Negative Sentiment %"
      ],
      "definition": "The share of answer-engine mentions of your brand classified negative in tone, per answer engine.",
      "category": "AI visibility",
      "type": "rate",
      "unit": "percent of mentions classified negative",
      "direction": "lower-better",
      "verification": "review",
      "grain": "One answer engine and time bucket for one tracked segment.",
      "dimensions": [
        "answer engine",
        "time bucket",
        "intent",
        "branded vs non-branded"
      ],
      "requiredFilters": [
        "tracker (unified segment id)",
        "date range"
      ],
      "sources": [
        "ai-visibility"
      ],
      "reports": [
        "ai-visibility-report"
      ],
      "skills": [
        "aeo-audit"
      ],
      "verbs": [
        "ai_visibility_trend"
      ],
      "rungs": [
        "R4"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "Are AI answers describing us negatively?"
      ],
      "caveats": [
        "Read this per engine. Cross-engine aggregate views do not measure it, a zero at the aggregate level means not measured, not an absence of negative coverage.",
        "That aggregate series is only built for the all-metrics chart view with no platform selected. Every per-engine series reads a real measure, so the same field is measured on one leg of the same verb and fabricated on the other.",
        "The per-competitor breakdown returns it as empty rather than zero, which is the honest shape the aggregate series does not use.",
        "Every figure is scoped to a tracked prompt basket, a sample, not a census, so the basket's coverage belongs beside the number it produced."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Reporting a clean negative-sentiment record from an aggregate chart whose zeros were assigned in code.",
        "Escalating on a negative share computed as the remainder of the positive share.",
        "Comparing an aggregate-series value against a per-engine value as if both were measured."
      ],
      "notSameAs": [
        {
          "slug": "ai-positive-sentiment-rate",
          "why": "Not complements. The positive share is a measured semantic-layer field; the negative share is unmeasured on the aggregate leg, so one cannot be derived from the other."
        }
      ],
      "related": [
        "ai-positive-sentiment-rate",
        "ai-neutral-sentiment-rate"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-neutral-sentiment-rate",
      "name": "Neutral sentiment share of AI mentions",
      "aliases": [
        "Neutral Sentiment %"
      ],
      "definition": "The share of answer-engine mentions of your brand classified neutral in tone, per answer engine.",
      "category": "AI visibility",
      "type": "rate",
      "unit": "percent of mentions classified neutral",
      "direction": "neutral",
      "verification": "review",
      "grain": "One answer engine and time bucket for one tracked segment.",
      "dimensions": [
        "answer engine",
        "time bucket",
        "intent",
        "branded vs non-branded"
      ],
      "requiredFilters": [
        "tracker (unified segment id)",
        "date range"
      ],
      "sources": [
        "ai-visibility"
      ],
      "reports": [],
      "skills": [
        "aeo-audit"
      ],
      "verbs": [
        "ai_visibility_trend"
      ],
      "rungs": [
        "R4"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "What share of AI mentions are neutral?"
      ],
      "caveats": [
        "Read this per engine. Cross-engine aggregate views do not measure it, a zero at the aggregate level means not measured, not an absence of neutral coverage.",
        "That aggregate series is only built for the all-metrics chart view with no platform selected. Every per-engine series reads a real measure, so the same field is measured on one leg of the same verb and fabricated on the other.",
        "The per-competitor breakdown returns it as empty rather than zero, which is the honest shape the aggregate series does not use.",
        "Canon flags the Represented rung as only partly instrumented.",
        "Every figure is scoped to a tracked prompt basket, a sample, not a census, so the basket's coverage belongs beside the number it produced."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Charting the aggregate series and reading its flat zero line as a real neutral share.",
        "Using positive, neutral and negative together as a complete distribution when only positive is measured on the aggregate leg."
      ],
      "notSameAs": [
        {
          "slug": "ai-positive-sentiment-rate",
          "why": "The positive share is read from a measured semantic-layer field on both legs; this one is measured on the per-engine leg and hardcoded to zero on the aggregate leg, so the two are not comparable parts of one distribution."
        }
      ],
      "related": [
        "ai-positive-sentiment-rate",
        "ai-negative-sentiment-rate"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "prompt-citation-share",
      "name": "Per-prompt citation share",
      "aliases": [
        "Citation % (prompts tab)"
      ],
      "definition": "Your share of all citations awarded on one answer-engine prompt, across every tracked brand cited for it.",
      "category": "AI visibility",
      "type": "share",
      "unit": "percent of that prompt's citations",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "(your citations for the prompt / all cited domains' citations for the prompt) × 100, returned empty when the prompt drew no citations at all. The two legs are the same rank query with and without the client filter, each summed per prompt and joined on the prompt key.",
      "numerator": "Citations of your domain on that prompt.",
      "denominator": "Citations of every cited domain on that prompt.",
      "aggregation": "Do not average these across prompts to get an overall citation share, each prompt carries its own denominator. The account-level citation rate is a separate measure.",
      "grain": "One prompt for one tracked segment over one date range.",
      "dimensions": [
        "prompt",
        "answer engine",
        "intent",
        "branded vs non-branded",
        "country",
        "device"
      ],
      "requiredFilters": [
        "tracker or tracked segment id",
        "date range"
      ],
      "sources": [
        "ai-visibility",
        "rank-tracking"
      ],
      "reports": [
        "ai-visibility-report"
      ],
      "skills": [
        "aeo-audit",
        "ai-prompt-coverage-gaps",
        "ai-citation-monitoring"
      ],
      "verbs": [
        "ai_visibility_drilldown"
      ],
      "rungs": [
        "R3"
      ],
      "levers": [
        "L7",
        "L5"
      ],
      "questions": [
        "On which prompts do we hold most of the citations?",
        "Which prompts cite everyone but us?"
      ],
      "interpretation": "A prompt where the share is zero and the denominator is large is a coverage gap with demand behind it; a zero share on a prompt nobody is cited for is not a gap at all. Read the share and the prompt's total citations together.",
      "caveats": [
        "Empty means the prompt drew no citations from any domain, not that you scored zero against a populated field.",
        "When the all-domain leg returns no row for a prompt, the denominator falls back to your own citations and the share reads as one hundred percent. A complete-looking share on a thin prompt is worth checking against the prompt's citation total.",
        "The prompt tab reads the market-share rank and brand-mention datasets. If the tracker has no market-share segment for the requested engine the tab returns no rows with a stated reason, rather than zeros.",
        "Engines are non-deterministic: the same prompt can answer differently twice, so a prompt's share is a rate over repeated observation rather than a state.",
        "A large share of citation inventory is third-party content, so a gap on a prompt is not automatically a case for a new page."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Averaging per-prompt shares into an account citation rate.",
        "Treating an empty share as a competitive loss rather than an uncited prompt."
      ],
      "notSameAs": [
        {
          "slug": "prompt-share-of-voice-share",
          "why": "Neighbouring columns on the same row over the same population, differing only in what they count. This divides your prompt citations by every cited domain's citations; the share-of-voice percentage divides your weighted citations-plus-mentions by the same weighted total for all domains on that prompt."
        },
        {
          "slug": "ai-citation-rate",
          "why": "Same ratio at two grains. This divides within one prompt; the account-level share divides across the whole slice. Neither decomposes into the other, and a prompt where you hold every citation can sit inside a slice where you hold very few."
        },
        {
          "slug": "prompt-mention-share",
          "why": "Separate measures with separate denominators on the same row: mentions count your brand being named on the prompt, citations count your URL being sourced for it.",
          "mirroredFrom": "prompt-mention-share"
        }
      ],
      "related": [
        "prompt-mention-share",
        "prompt-share-of-voice-score",
        "prompt-citation-count",
        "prompt-cited-pages-count"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "prompt-mention-share",
      "name": "Per-prompt mention share",
      "aliases": [
        "Mentions % (prompts tab)"
      ],
      "definition": "Your share of all brand mentions made on one answer-engine prompt, across every tracked brand named for it.",
      "category": "AI visibility",
      "type": "share",
      "unit": "percent of that prompt's mentions",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "(your mentions for the prompt / all tracked brands' mentions for the prompt) × 100, returned empty when the prompt drew no mentions. The two legs are the same brand-mention query with and without the client filter, each summed per prompt and joined on the prompt key.",
      "numerator": "Mentions of your brand on that prompt.",
      "denominator": "Mentions of every tracked brand on that prompt.",
      "aggregation": "Per-prompt denominators differ, so these are not averaged into an account mention share.",
      "grain": "One prompt for one tracked segment over one date range.",
      "dimensions": [
        "prompt",
        "answer engine",
        "intent",
        "branded vs non-branded",
        "country",
        "device"
      ],
      "requiredFilters": [
        "tracker or tracked segment id",
        "date range"
      ],
      "sources": [
        "ai-visibility",
        "rank-tracking"
      ],
      "reports": [
        "ai-visibility-report"
      ],
      "skills": [
        "aeo-audit",
        "ai-prompt-coverage-gaps"
      ],
      "verbs": [
        "ai_visibility_drilldown"
      ],
      "rungs": [
        "R4",
        "R3"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "On which prompts do answers name us rather than our rivals?",
        "Are we named on the prompts that cite us?"
      ],
      "interpretation": "Compared against the citation share on the same row, this separates being talked about from being used as a source, the two diverge on most prompts and the direction of the divergence is the useful part.",
      "caveats": [
        "Empty means the prompt drew no mentions from any tracked brand, not that you scored zero against a populated field.",
        "When the all-brand leg returns no row for a prompt, the denominator falls back to your own mentions and the share reads as one hundred percent.",
        "The prompt tab reads the market-share brand-mention dataset. If the tracker has no market-share segment for the requested engine the tab returns no rows with a stated reason, rather than zeros.",
        "Every figure is scoped to a tracked prompt basket, a sample, not a census, so the basket's coverage belongs beside the number it produced."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Reading it as a citation share because both columns sit on the same row and both end in a percent sign.",
        "Averaging per-prompt shares into one account-level figure."
      ],
      "notSameAs": [
        {
          "slug": "prompt-citation-share",
          "why": "Separate measures over the same prompt from two different datasets: mentions count your brand being named, citations count your URL being sourced. They routinely diverge and the direction of the divergence is the read."
        },
        {
          "slug": "prompt-share-of-voice-share",
          "why": "This divides by all tracked brands' mentions on the prompt; the share-of-voice percentage divides the same population's weighted citations-plus-mentions, so it moves with the citation half too."
        }
      ],
      "related": [
        "prompt-citation-share",
        "prompt-share-of-voice-score",
        "ai-mention-share"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-positive-mention-count",
      "name": "Positive AI mentions",
      "aliases": [
        "Positive Mentions",
        "Total positive mentions"
      ],
      "definition": "The number of answer-engine responses that named your brand and were classified positive in tone.",
      "category": "AI visibility",
      "type": "raw measure",
      "unit": "mentions classified positive",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "The sum of your brand's positive-classified mention counts across the answer-engine responses in the slice. It is the numerator of the positive sentiment rate, which the verbs read as its own measure rather than deriving it from this count.",
      "aggregation": "Additive across prompts and answer engines. It is the numerator of the positive sentiment rate, so it is reported beside its denominator rather than alone.",
      "grain": "One answer engine, prompt or competitor domain for one tracked segment over one date range.",
      "dimensions": [
        "answer engine",
        "prompt",
        "competitor domain",
        "intent",
        "branded vs non-branded"
      ],
      "requiredFilters": [
        "tracker (unified segment id) or tracked segment id",
        "date range"
      ],
      "sources": [
        "ai-visibility"
      ],
      "reports": [],
      "skills": [
        "aeo-audit",
        "competitor-deep-dive",
        "quattr-iq"
      ],
      "verbs": [
        "ai_visibility_overview",
        "ai_visibility_competitors",
        "ai_visibility_drilldown"
      ],
      "rungs": [
        "R4"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "How many AI answers described us positively?",
        "Did positive mentions grow with total mentions or faster?"
      ],
      "interpretation": "A count of positive mentions rises with mention volume, so it is read against the total mention count, the rate is the comparable figure.",
      "caveats": [
        "Canon flags the Represented rung as only partly instrumented: mentions and sentiment are measured, the positioning-fidelity half is not.",
        "Neutral and negative mention counts are not returned by these verbs, the competitor breakdown returns them as empty, so positive mentions cannot be differenced into the rest of the distribution.",
        "The classifier has a neutral bucket, so total mentions minus positive mentions is not negative mentions.",
        "Every figure is scoped to a tracked prompt basket, a sample, not a census, so the basket's coverage belongs beside the number it produced."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Inferring the negative count by subtracting positives from total mentions, the classifier's neutral bucket sits in between and is not returned here.",
        "Reading a rise in positive mentions as improved framing when total mentions rose by the same proportion."
      ],
      "notSameAs": [
        {
          "slug": "ai-positive-sentiment-rate",
          "why": "The count is the numerator; the rate divides it by all mentions. The rate is its own measure in the semantic layer and is never derived by the verbs from the count."
        }
      ],
      "related": [
        "ai-positive-sentiment-rate",
        "ai-mention-count",
        "ai-neutral-sentiment-rate",
        "ai-negative-sentiment-rate"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-positive-sentiment-rate",
      "name": "Positive sentiment share of AI mentions",
      "aliases": [
        "Positive Sentiment %",
        "Sentiment %"
      ],
      "definition": "The share of answer-engine mentions of your brand that were classified positive in tone.",
      "category": "AI visibility",
      "type": "rate",
      "unit": "percent of mentions classified positive",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "your positive mentions ÷ your all mentions × 100, labelled \"Positive Sentiment %\" on every source that carries it, the grid, the trend and the competitor breakdown all compute the identical ratio under differently named all-mention denominators.",
      "numerator": "Mentions classified positive.",
      "denominator": "All mentions of your brand in answer-engine responses in the period.",
      "aggregation": "Never average the per-engine percentages for a cross-engine figure, the semantic layer re-aggregates the ratio on a measure-only read. Recomputing it from returned counts is not equivalent, because the neutral and negative counts are not returned.",
      "grain": "One answer engine, competitor domain, prompt or time bucket for one tracked segment over one date range.",
      "dimensions": [
        "answer engine",
        "competitor domain",
        "prompt",
        "intent",
        "country",
        "device",
        "branded vs non-branded"
      ],
      "requiredFilters": [
        "tracker (unified segment id)",
        "date range"
      ],
      "sources": [
        "ai-visibility"
      ],
      "reports": [
        "ai-visibility-report"
      ],
      "skills": [
        "aeo-audit",
        "competitor-deep-dive",
        "quattr-iq"
      ],
      "verbs": [
        "ai_visibility_overview",
        "ai_visibility_trend",
        "ai_visibility_competitors",
        "ai_visibility_drilldown"
      ],
      "rungs": [
        "R4"
      ],
      "levers": [
        "L7",
        "L6"
      ],
      "questions": [
        "How positively do AI answers describe us?",
        "Is our sentiment better or worse than the leader's?",
        "Has sentiment moved since last quarter?"
      ],
      "interpretation": "Read as a distribution over prompts rather than as one number against an absolute threshold, canon's Represented rung is described exactly that way. Because the complementary neutral and negative shares are not measured on the aggregate leg, a falling positive share tells you positives fell, not where they went.",
      "caveats": [
        "The neutral and negative shares that would complete this distribution are set to zero in code on the cross-engine aggregate series, they are not measured there, so this rate is the only sentiment figure with measurement behind it in that path. The per-engine series does carry all three.",
        "The prompt-level path computes it against a sentiment-scored-mentions denominator rather than an all-mentions one, so a prompt-tab figure and a grid figure are not the same ratio.",
        "Canon flags the Represented rung as only partly instrumented: sentiment and mentions are measured, the positioning-fidelity half is not.",
        "Sentiment applies only to answers that mention you, an answer that cites your page without naming you contributes nothing here.",
        "Engines are non-deterministic: the same prompt can answer differently twice, which is why this is reported as a rate over repeated observation rather than as a state."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Deriving the negative share as one hundred minus the positive share, the neutral bucket sits between them and is not measured on the aggregate leg.",
        "Reading a sentiment move at a handful of mentions as a change in how AI describes you.",
        "Averaging the per-engine percentages instead of taking the re-aggregated figure."
      ],
      "notSameAs": [
        {
          "slug": "ai-positive-mention-count",
          "why": "The rate is its own semantic-layer measure with an all-mentions denominator; the count is the numerator alone. The verbs read the rate rather than dividing the counts they return."
        },
        {
          "slug": "ai-negative-sentiment-rate",
          "why": "They are not complements in this data. The negative share is hardcoded to zero on the aggregate leg, so a low positive share cannot be turned into a negative share."
        },
        {
          "slug": "serp-sentiment-share",
          "why": "Sentiment measured on SERP brand mentions is a different corpus from sentiment measured in answer-engine text. They are collected separately, on different cadences, and are not comparable."
        },
        {
          "slug": "ai-neutral-sentiment-rate",
          "why": "The positive share is read from a measured field on both legs of the trend; the neutral share is measured on the per-engine leg and set to zero in code on the aggregate leg, so the two are not comparable parts of one distribution there.",
          "mirroredFrom": "ai-neutral-sentiment-rate"
        }
      ],
      "related": [
        "ai-positive-mention-count",
        "ai-neutral-sentiment-rate",
        "ai-negative-sentiment-rate",
        "ai-mention-count"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "prompt-share-of-voice-share",
      "name": "Prompt share-of-voice percentage",
      "aliases": [
        "Share of Voice % (prompts tab)"
      ],
      "definition": "Your share of the weighted voice on one answer-engine prompt: your citations and mentions, weighted, as a percentage of every cited domain's citations and mentions on that same prompt.",
      "category": "AI visibility",
      "type": "share",
      "unit": "percent of that prompt's weighted voice",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "(1.25 × your citations for the prompt + your mentions for the prompt) ÷ (1.25 × all domains' citations for the prompt + all brands' mentions for the prompt) × 100, returned empty when the prompt drew no weighted voice at all.",
      "numerator": "Your weighted voice on the prompt, citations at 1.25, mentions at 1.",
      "denominator": "The same weighted combination across every cited domain and named brand on that prompt.",
      "aggregation": "Each prompt carries its own denominator, so these do not average into an account-level share and do not sum to a hundred down the column.",
      "grain": "One prompt for one tracked segment over one date range.",
      "dimensions": [
        "prompt",
        "answer engine",
        "intent",
        "branded vs non-branded",
        "country",
        "device"
      ],
      "requiredFilters": [
        "tracker or tracked segment id",
        "date range"
      ],
      "sources": [
        "ai-visibility",
        "rank-tracking"
      ],
      "reports": [
        "ai-visibility-report"
      ],
      "skills": [
        "aeo-audit",
        "ai-prompt-coverage-gaps"
      ],
      "verbs": [
        "ai_visibility_drilldown"
      ],
      "rungs": [
        "R3"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "What share of voice do we hold on this prompt?"
      ],
      "interpretation": "A competitive standing on one prompt, comparable in kind to the citation and mention shares beside it. Because it folds two behaviours together under fixed weights, a move is a prompt to read the citation and mention columns rather than a finding on its own.",
      "caveats": [
        "The 1.25 and 1.0 weights are a product decision, not a quantity any engine reports. They match the semantic layer's own presence score, so the prompt figure and the account figure weight the same way.",
        "When the all-domain legs return no rows for a prompt, both sides of the ratio fall back to your own totals and the share reads as one hundred percent. On a thin prompt, check the prompt's citation and mention totals before reading it as dominance.",
        "The same column label appears on the competitor, intent, geography and brand tabs carrying a semantic-layer measure computed over the whole slice rather than per prompt. Same weights, different population.",
        "The prompt tab reads the market-share rank and brand-mention datasets. If the tracker has no market-share segment for the requested engine the tab returns no rows with a stated reason.",
        "Every figure is scoped to a tracked prompt basket, a sample, not a census, so the basket's coverage belongs beside the number it produced."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Comparing a prompt's figure here against the same-named figure on the competitor tab, which is computed over the whole slice.",
        "Averaging per-prompt shares into an account-level share of voice.",
        "Reading a hundred-percent share on a low-volume prompt without checking whether the all-domain legs returned anything."
      ],
      "notSameAs": [
        {
          "slug": "prompt-citation-share",
          "why": "Neighbouring columns over the same prompt population, differing in what they count. The citation share divides your prompt citations by every cited domain's citations; this divides your weighted citations-plus-mentions by the same weighted total."
        },
        {
          "slug": "prompt-share-of-voice-score",
          "why": "The score is your weighted points total on the prompt; this is that total over the prompt's weighted total across all domains. The score rises with volume, the share does not."
        },
        {
          "slug": "ai-share-of-voice",
          "why": "Same weights, two grains and two implementations: the grid and competitor tabs read a semantic-layer measure over the whole slice, this is computed in the verb per prompt. Neither decomposes into the other."
        },
        {
          "slug": "prompt-mention-share",
          "why": "The mention share divides by all tracked brands' mentions on the prompt; this divides the same population's weighted citations-plus-mentions, so it moves with the citation half too.",
          "mirroredFrom": "prompt-mention-share"
        }
      ],
      "related": [
        "prompt-share-of-voice-score",
        "prompt-citation-share",
        "prompt-mention-share",
        "ai-share-of-voice"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "prompt-share-of-voice-score",
      "name": "Prompt share-of-voice score",
      "aliases": [
        "Share of Voice score",
        "SoV score"
      ],
      "definition": "A weighted points score for how much of an answer-engine prompt's voice you hold, counting each citation as 1.25 and each mention as 1.",
      "category": "AI visibility",
      "type": "score",
      "unit": "weighted points (citations weighted 1.25, mentions weighted 1)",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "score = 1.25 × your citations for the prompt + your mentions for the prompt, rounded to a whole number. Both inputs are filtered to your own domain before the weighting is applied.",
      "aggregation": "A points total per prompt. Not comparable across segments or periods with different basket sizes, and not a component of the percentage beside it, that percentage divides this score by the same weighted total across every domain on the prompt, not by a sum of your scores.",
      "grain": "One prompt for one tracked segment over one date range.",
      "dimensions": [
        "prompt",
        "answer engine",
        "intent",
        "branded vs non-branded",
        "country",
        "device"
      ],
      "requiredFilters": [
        "tracker or tracked segment id",
        "date range"
      ],
      "sources": [
        "ai-visibility",
        "rank-tracking"
      ],
      "reports": [
        "ai-visibility-report"
      ],
      "skills": [
        "aeo-audit",
        "ai-prompt-coverage-gaps",
        "quattr-iq"
      ],
      "verbs": [
        "ai_visibility_drilldown"
      ],
      "rungs": [
        "R3"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "Which prompts carry most of our AI voice?",
        "Where does the weighting change the ranking versus raw citations?"
      ],
      "interpretation": "The weighting encodes an editorial position, a citation is worth more than a mention because it is the earned-source signal, and it is the same weighting the semantic layer applies in its own presence score, so the prompt score is a grain of an existing product quantity rather than a verb invention. Use it to order prompts, not to state a level.",
      "caveats": [
        "The 1.25 weight is a product constant, not an engine-reported quantity. It matches the semantic layer's presence score, so the two agree by construction rather than by coincidence.",
        "The prompt tab reads the market-share rank and brand-mention datasets. If the tracker has no market-share segment for the requested engine the tab returns no rows with a stated reason.",
        "Every figure is scoped to a tracked prompt basket, a sample, not a census, so the basket's coverage belongs beside the number it produced.",
        "Engines are non-deterministic: the same prompt can answer differently twice, so a prompt's score is an observation total over repeated runs."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Comparing scores between two segments or two periods whose baskets differ.",
        "Reading the score as a percentage, it is an unbounded points total."
      ],
      "notSameAs": [
        {
          "slug": "prompt-share-of-voice-share",
          "why": "The score is your weighted points total on the prompt; the percentage is that total over every domain's weighted total on the same prompt. Both are well defined and neither is derived from the other by summing prompts."
        },
        {
          "slug": "ai-share-of-voice",
          "why": "The same weights at two grains: this is computed in the verb from one prompt's counts, while the grid and competitor tabs read a semantic-layer measure over the whole slice."
        }
      ],
      "related": [
        "prompt-share-of-voice-share",
        "prompt-citation-share",
        "prompt-mention-share",
        "ai-share-of-voice"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-competitive-rank",
      "name": "Your rank in AI answers",
      "aliases": [
        "AI standing",
        "Rank vs tracked rivals in AI answers"
      ],
      "definition": "Where you place among the named competitors tracked on a segment when they are ordered by share of voice in answer-engine responses.",
      "category": "AI visibility",
      "type": "rank",
      "unit": "position among named tracked competitors (1 is first)",
      "direction": "lower-better",
      "verification": "verified",
      "calculation": "Competitor rows are de-duplicated to one row per domain, keeping the highest share of voice, ordered by share of voice descending; the aggregate \"Other\" bucket is removed and your position in what remains is your rank. The leader is the first named rival in the same ordering, excluding both \"Other\" and yourself.",
      "aggregation": "A position, never summed or averaged. Recomputed per slice, a rank on one answer engine or intent does not carry to another.",
      "grain": "One tracked segment, optionally narrowed to one answer engine, intent or brand bucket, over one date range.",
      "dimensions": [
        "competitor domain",
        "answer engine",
        "intent",
        "branded vs non-branded"
      ],
      "requiredFilters": [
        "tracker (unified segment id)",
        "date range"
      ],
      "sources": [
        "ai-visibility"
      ],
      "reports": [
        "ai-visibility-report"
      ],
      "skills": [
        "aeo-audit",
        "competitor-deep-dive",
        "quattr-iq"
      ],
      "verbs": [
        "ai_visibility_competitors",
        "ai_visibility_drilldown"
      ],
      "rungs": [
        "R3"
      ],
      "levers": [
        "L7"
      ],
      "questions": [
        "Where do we rank in AI answers against our rivals?",
        "Who leads AI share of voice on this tracker?",
        "Did we pass anyone this month?"
      ],
      "interpretation": "A standing among the brands the segment tracks, ordered by a blended share-of-voice measure. Because the ordering is by share of voice, a rank change can come from either the citation or the mention half, the columns beneath say which.",
      "caveats": [
        "The denominator is the tracked roster, not the market, a position of 3 means third among the domains this segment tracks for this answer engine.",
        "Roster changes move the position without anything changing in the answers. The AI-visibility sources were widened from ten competitor slots to twelve; the extra two stay empty until the underlying table is rebuilt at the wider setting, and when it is, ranks will shift for reasons that are not performance.",
        "The aggregate \"Other\" bucket is deliberately excluded from the leader and the rank. It remains in the competitor table, so the table can show a higher-share row above you while your rank is still first among named rivals.",
        "A rank value also arrives on each competitor row from the semantic layer, but it is the configured slot index on the source table, roster position, not an ordering by share of voice. It will disagree with the computed standing routinely, and it is not a competitive rank.",
        "Absence from the standings means untracked, not absent, a segment that does not track a rival cannot see them.",
        "Search competitors are whoever takes the answer's citation and mention slots, which is often not the organisation chart's rival list."
      ],
      "freshness": "~1 day behind, Daily prompt runs, available the following day.",
      "failureModes": [
        "Quoting the row-level slot index and the computed standing interchangeably.",
        "Reporting a rank drop caused by a newly tracked competitor entering the segment or by the slot count widening.",
        "Averaging positions across weeks, which discards the share distances that made them."
      ],
      "notSameAs": [
        {
          "slug": "ai-share-of-voice",
          "why": "A position and the quantity it was ordered by. Share of voice can fall while the rank holds, and the rank can fall on a share-of-voice gain if a rival gained more, or if the roster changed."
        }
      ],
      "related": [
        "ai-share-of-voice",
        "ai-citation-rate",
        "ai-mention-share"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "best-competitor-rank",
      "name": "Best competitor rank",
      "aliases": [
        "Leader rank on a keyword",
        "Top rival position"
      ],
      "definition": "The best position any tracked competitor holds on a keyword, together with which domain holds it.",
      "category": "Competitive keywords",
      "type": "rank",
      "unit": "results-page position (1 = top)",
      "direction": "lower-better",
      "verification": "verified",
      "calculation": "For each keyword, the lowest average rank among all tracked domains other than yours, rounded to one decimal, with the winning domain returned beside it. Keywords where no tracked competitor ranks are skipped from the comparison entirely.",
      "aggregation": "A per-keyword minimum over the competitor rows; it is not an average of competitors and does not describe the field as a whole.",
      "grain": "One keyword × the date range, inside one tracked segment.",
      "dimensions": [
        "query",
        "competitor domain",
        "segment"
      ],
      "requiredFilters": [
        "segment_id",
        "date range"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "competitor-search-report"
      ],
      "skills": [
        "keyword-gap-audit",
        "competitor-deep-dive"
      ],
      "verbs": [
        "seo_keyword_gap_analysis",
        "competitive_keyword_ranking"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2"
      ],
      "questions": [
        "Who outranks us on this keyword?",
        "Which competitor wins the most of our target keywords?"
      ],
      "interpretation": "The bar to clear on each keyword, and the name attached to it. Because it is a minimum, one strong rival sets the bar for the whole keyword, which is what makes it a useful target and a poor description of the competitive field.",
      "caveats": [
        "Best means best among tracked domains. A rival the segment does not track cannot appear, so absence from the standings means untracked, not absent.",
        "Search competitors are whoever occupies the results-page slots, which is often an aggregator rather than a business rival.",
        "Both reads are capped, the client's own ranks at 5,000 rows, sized to be non-binding on a busy segment, and the competitors' at 10,000 for warehouse cost, so a very long-tail keyword can carry your rank with no competitor row and be skipped from the comparison.",
        "The underlying rank measure floors to zero rather than null when its impression denominator is empty, so a competitor row with no impressions comes back as rank 0 and wins the minimum. A best-competitor rank of 0 is that artifact, not a result above position 1."
      ],
      "freshness": "~1 day behind, daily observation, available the following day.",
      "failureModes": [
        "Reading a missing competitor row as no competition rather than as outside the fetched window.",
        "Treating the best-rank domain as the market leader across the segment.",
        "Taking a zero best-competitor rank at face value."
      ],
      "notSameAs": [],
      "related": [
        "our-rank",
        "keyword-rank-gap",
        "losing-keywords"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "keyword-rank-gap",
      "name": "Keyword rank gap",
      "aliases": [
        "Rank gap",
        "Gap to best competitor"
      ],
      "definition": "How many positions separate you from the best-ranked tracked competitor on a keyword.",
      "category": "Competitive keywords",
      "type": "derived metric",
      "unit": "positions (positive means the competitor sits above you)",
      "direction": "lower-better",
      "verification": "verified",
      "calculation": "gap = our rank − best competitor rank, rounded to one decimal, and null when we do not rank at all. A positive gap means the best tracked competitor sits above you; zero or negative means you are level or ahead.",
      "aggregation": "Per keyword. Gaps are not averaged into a segment-level gap, the bucket counts and the share metrics carry that job.",
      "grain": "One keyword × the date range, inside one tracked segment.",
      "dimensions": [
        "query",
        "competitor domain",
        "segment"
      ],
      "requiredFilters": [
        "segment_id",
        "date range"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "competitor-search-report",
        "search-opportunity-report"
      ],
      "skills": [
        "keyword-gap-audit",
        "competitor-deep-dive",
        "striking-distance-sprint"
      ],
      "verbs": [
        "seo_keyword_gap_analysis"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2",
        "L5"
      ],
      "questions": [
        "How far behind are we on the keywords we lose?",
        "Which losing keywords have the smallest gap to close?",
        "Where do competitors beat us by the most positions?"
      ],
      "interpretation": "The size of each battle, used to sort the losing list from widest gap down. A small gap is a nearer target, not a cheaper one, the effort behind a position is not in this number, and neither is the demand behind the keyword.",
      "caveats": [
        "Both sides are impression-weighted averages over the window, so a gap under a position is inside the noise of the averaging rather than a visible difference on a results page.",
        "A gap is positions, not traffic, a wide gap on negligible demand outranks nothing worth having, which is why the worklist is weighted by demand before it is acted on.",
        "Null wherever we do not rank; those keywords belong to the not-ranked bucket instead and have no gap by definition."
      ],
      "freshness": "~1 day behind, daily observation, available the following day.",
      "failureModes": [
        "Prioritising by gap size alone and building a worklist of keywords nobody searches.",
        "Reading a sub-one-position gap as a real difference."
      ],
      "notSameAs": [
        {
          "slug": "search-market-share",
          "why": "A rank gap is a per-keyword position difference; search market share is a CTR-modeled share of tracked demand across the whole segment. Closing gaps on low-demand keywords can leave share unchanged, and share can move with no gap changing at all."
        }
      ],
      "related": [
        "our-rank",
        "best-competitor-rank",
        "losing-keywords"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "losing-keywords",
      "name": "Losing keywords",
      "aliases": [
        "Losing bucket",
        "Keywords where competitors beat us"
      ],
      "definition": "Tracked keywords where you rank but the best tracked competitor ranks above you.",
      "category": "Competitive keywords",
      "type": "raw measure",
      "unit": "keywords",
      "direction": "lower-better",
      "verification": "verified",
      "calculation": "A keyword falls into the losing bucket when your rank exists and the gap to the best tracked competitor is strictly greater than zero. The rows are sorted by gap descending and the top 25 are returned; the bucket total is reported separately and is not capped.",
      "aggregation": "A count of keywords. The three buckets partition every keyword on which at least one tracked competitor ranks.",
      "grain": "One tracked segment × the date range.",
      "dimensions": [
        "query",
        "competitor domain",
        "segment"
      ],
      "requiredFilters": [
        "segment_id",
        "date range"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "competitor-search-report",
        "search-opportunity-report"
      ],
      "skills": [
        "keyword-gap-audit",
        "competitor-deep-dive",
        "market-share-review"
      ],
      "verbs": [
        "seo_keyword_gap_analysis"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2",
        "L3",
        "L5"
      ],
      "questions": [
        "Where do competitors beat us?",
        "Which keywords are we losing to this rival?",
        "How many of our tracked keywords do we lose?"
      ],
      "interpretation": "The battle map's contested column: demand you are already in, held by someone else. It is the refresh-and-push list rather than the build list, because the page already exists and already ranks.",
      "caveats": [
        "The returned rows are the widest 25 gaps; the totals describe the whole bucket, so a list and a count answer different questions.",
        "Segment-scoped, so the bucket only covers demand the segment tracks.",
        "Rank comparisons are positions on tracked keywords, not promises of traffic, demand weighting comes before prioritisation."
      ],
      "freshness": "~1 day behind, daily observation, available the following day.",
      "failureModes": [
        "Reading the returned rows as the whole losing set.",
        "Prioritising the widest gaps rather than the ones with demand behind them."
      ],
      "notSameAs": [],
      "related": [
        "winning-keywords",
        "not-ranked-keywords",
        "keyword-rank-gap"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "not-ranked-keywords",
      "name": "Not-ranked keywords",
      "aliases": [
        "Not-ranked bucket",
        "Absent keywords"
      ],
      "definition": "Tracked keywords where at least one competitor ranks and you have no observed rank at all.",
      "category": "Competitive keywords",
      "type": "raw measure",
      "unit": "keywords",
      "direction": "lower-better",
      "verification": "verified",
      "calculation": "A keyword falls into the not-ranked bucket when a tracked competitor ranks on it and your own rank is null. Up to 25 rows are returned; the bucket total is reported separately and is not capped.",
      "aggregation": "A count of keywords, partitioning with the winning and losing buckets. Keywords on which no tracked competitor ranks never enter the comparison at all.",
      "grain": "One tracked segment × the date range.",
      "dimensions": [
        "query",
        "competitor domain",
        "segment"
      ],
      "requiredFilters": [
        "segment_id",
        "date range"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "competitor-search-report",
        "search-opportunity-report"
      ],
      "skills": [
        "keyword-gap-audit",
        "ai-prompt-coverage-gaps",
        "competitor-deep-dive"
      ],
      "verbs": [
        "seo_keyword_gap_analysis"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L5",
        "L2"
      ],
      "questions": [
        "Which keywords do competitors rank for that we do not?",
        "Where are we completely absent in this segment?",
        "What should we target next versus our rivals?"
      ],
      "interpretation": "Absence, which reads very differently from a poor position: there is nothing to nudge, so the lever is coverage rather than refinement. It feeds the net-new content conversation, which is the most expensive lever and the one that gets reviewed hardest before it is pulled.",
      "caveats": [
        "Not-ranked means no observed rank in this segment and window, it is not proof a page cannot rank, and it is not proof the page does not exist.",
        "Not-ranked is not a build order: intent alignment is reviewed before recommending new content, because coverage for its own sake is the named anti-pattern here.",
        "Because the client and competitor ranks are read separately, a bug in that split would inflate this bucket, the separate read exists precisely because a single combined read did.",
        "Segment-scoped: absence outside the tracked segment is not measured at all."
      ],
      "freshness": "~1 day behind, daily observation, available the following day.",
      "failureModes": [
        "Turning the bucket straight into a content brief without an intent review.",
        "Reading an inflated not-ranked count as a coverage collapse when it is a data-fetch artifact."
      ],
      "notSameAs": [],
      "related": [
        "losing-keywords",
        "winning-keywords",
        "our-rank"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "our-rank",
      "name": "Our rank on a tracked keyword",
      "aliases": [
        "Client rank",
        "Our position (tracked)"
      ],
      "definition": "Your own average ranking position for one keyword inside a tracked segment, taken from Quattr's daily results-page observation rather than from Search Console.",
      "category": "Competitive keywords",
      "type": "rank",
      "unit": "results-page position (1 = top)",
      "direction": "lower-better",
      "verification": "verified",
      "calculation": "`nvl(Σ(position × impressions) / Σ(impressions), 0)` on the tracked-rank table, computed per keyword and domain, the same impression-weighted average used for organic position, wrapped in a zero floor that fires when the impression denominator is empty. Your own domain is identified from the segment's competitor mapping, taking the first row flagged as the client.",
      "numerator": "Sum of position × impressions for that keyword and domain",
      "denominator": "Sum of impressions for that keyword and domain",
      "aggregation": "Impression-weighted per keyword and domain; ranks across keywords are never averaged into a site rank.",
      "grain": "One keyword × one domain × the date range, inside one tracked segment.",
      "dimensions": [
        "query",
        "competitor domain",
        "segment"
      ],
      "requiredFilters": [
        "segment_id",
        "date range"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "competitor-search-report"
      ],
      "skills": [
        "keyword-gap-audit",
        "competitor-deep-dive",
        "market-share-review"
      ],
      "verbs": [
        "seo_keyword_gap_analysis",
        "competitive_keyword_ranking"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2"
      ],
      "questions": [
        "Where do we rank for this keyword versus our competitors?",
        "Which tracked keywords do we rank for at all?",
        "How do our ranks compare in the buying-intent segment?"
      ],
      "interpretation": "The observed side of the competitive picture: not what your own reporting says about you, but where you were seen relative to everyone else competing for the same tracked demand. It is only defined inside a segment, because the competitor set is resolved per segment.",
      "caveats": [
        "Segment-scoped by construction: a keyword outside the tracked segment has no rank here, and a query without a segment filter returns meaningless cross-segment data.",
        "Your own ranks are read in a separate, domain-scoped query from the competitors'. A single combined read drops the client's own rows for most keywords and pushes almost everything into the not-ranked bucket.",
        "A missing row means no observed rank in this segment and window, not that the keyword has no demand.",
        "The measure never returns null. Where a row exists but carries no impressions, the zero floor returns a rank of 0, which sorts ahead of position 1, is carried into the winning bucket as a negative gap, and is not flagged anywhere in the response.",
        "This is an impression-weighted average over the window, not a discrete position observed on a given day."
      ],
      "freshness": "~1 day behind, daily observation, available the following day.",
      "failureModes": [
        "Reconciling this to the Search Console average position and treating the difference as an error.",
        "Reading a rank of 0 as the best possible position rather than as the measure's zero floor on a row with no impressions.",
        "Reading a null as a ranking of zero or as a page that cannot rank.",
        "Running the comparison without a segment and interpreting the blended result."
      ],
      "notSameAs": [
        {
          "slug": "avg-position",
          "why": "Search Console average position is your own reported position across every impression Google recorded; this is Quattr's observed position on one tracked keyword inside one segment, alongside competitors on the same keyword. Different sources, different keyword universes, and they are not built to reconcile."
        },
        {
          "slug": "search-market-share",
          "why": "A rank is an ordinal on a single keyword; search market share is a CTR-modeled share of the tracked demand aggregated across the segment. You can hold better ranks on more keywords and still hold less share, because share weights by the demand behind each keyword."
        }
      ],
      "related": [
        "best-competitor-rank",
        "keyword-rank-gap",
        "avg-position"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "winning-keywords",
      "name": "Winning keywords",
      "aliases": [
        "Winning bucket",
        "Keywords we lead on"
      ],
      "definition": "Tracked keywords where you rank at or above the best tracked competitor.",
      "category": "Competitive keywords",
      "type": "raw measure",
      "unit": "keywords",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "A keyword falls into the winning bucket when your rank exists and the gap to the best tracked competitor is zero or negative. Up to 25 rows are returned; the bucket total is reported separately and is not capped.",
      "aggregation": "A count of keywords, partitioning with the losing and not-ranked buckets.",
      "grain": "One tracked segment × the date range.",
      "dimensions": [
        "query",
        "competitor domain",
        "segment"
      ],
      "requiredFilters": [
        "segment_id",
        "date range"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "competitor-search-report"
      ],
      "skills": [
        "keyword-gap-audit",
        "competitor-deep-dive",
        "monthly-exec-review"
      ],
      "verbs": [
        "seo_keyword_gap_analysis"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2",
        "L3"
      ],
      "questions": [
        "Which keywords do we already win?",
        "Where are we ahead of this competitor?",
        "How much of the tracked set do we lead?"
      ],
      "interpretation": "Ground to defend, and the counterweight to a gap list that would otherwise read as an all-loss picture. A winning keyword is a position held on a given window, not a position secured.",
      "caveats": [
        "A tie is counted as winning: a gap of exactly zero falls on this side of the split.",
        "Winning means ahead of the best TRACKED competitor; an untracked rival above you both is invisible here.",
        "The returned rows are capped at 25 while the total is not, so the list under-describes the bucket by design.",
        "The rank measure floors to zero on a row with no impressions, and a zero rank produces a negative gap, so that artifact lands here rather than in the losing bucket."
      ],
      "freshness": "~1 day behind, daily observation, available the following day.",
      "failureModes": [
        "Reading a tie-heavy winning count as clear leadership.",
        "Presenting the winning count as a share of the market."
      ],
      "notSameAs": [],
      "related": [
        "losing-keywords",
        "not-ranked-keywords",
        "keyword-rank-gap"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-overview-daily-visibility",
      "name": "AI Overview average daily visibility",
      "aliases": [
        "AIO visibility",
        "Average daily visibility in AI Overviews"
      ],
      "definition": "The average daily number of AI Overview results pages in a segment on which a domain appears, the numerator of the AI Overview inclusion rate.",
      "category": "Competitive SERP",
      "type": "raw measure",
      "unit": "average daily count of AI Overview results pages the domain appears on",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "Read as the per-domain competitor column for the chosen domain, with your own leg selected by your rank in the tracked-competitor roster, under the AI Overview results-page feature filter. The semantic layer counts that domain's present rows and divides by the number of distinct observed days, so the value is a per-day average and not a period total. It is co-surfaced with the results-page count precisely because dividing the two reproduces the inclusion rate: a live reconciliation gives 33,721.5 over 98,007, which the product displays as 34.41%.",
      "aggregation": "A daily average, the count of distinct observed days is the divisor, so it is never summed across the period. Divide by the co-surfaced results-page count to recover the inclusion rate.",
      "grain": "One domain × segment × period × medium, segment-level only.",
      "dimensions": [
        "competitor domain",
        "intent",
        "brand",
        "country",
        "device"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "serp_feature_filter"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "ai-overview-report"
      ],
      "skills": [
        "serp-feature-watch",
        "competitor-deep-dive",
        "ai-vs-traditional-gap"
      ],
      "verbs": [
        "competitive_overview",
        "competitive_trends"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2",
        "L3"
      ],
      "questions": [
        "Did our AI Overview inclusion move because of us or because the surface changed?",
        "How does our AI Overview visibility compare with a rival's?"
      ],
      "interpretation": "The decomposition half of the inclusion rate. When inclusion falls, this tells you whether your own visibility fell or the count of AI Overview pages rose. Reporting the rate without at least glancing at both parts is how a surface change gets narrated as a performance change.",
      "caveats": [
        "It counts results pages, averaged per day. It is not a period total and not an impression count, so multiplying it by the number of days does not give a period figure.",
        "Its denominator is a per-day average on the same basis, which is what makes the ratio of the two a clean rate rather than a mixed one.",
        "It is scoped by the AI Overview results-page feature filter that the verbs inject on every read of this family.",
        "It describes Google's on-SERP answer box, not answer-engine citation."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Reporting the raw visibility figure on its own as though it were a rate.",
        "Comparing it across segments, whose observed page populations differ."
      ],
      "notSameAs": [
        {
          "slug": "ai-overview-inclusion",
          "why": "This is the rate's numerator, not the rate. On its own it cannot say how often you appear."
        }
      ],
      "related": [
        "ai-overview-inclusion",
        "ai-overview-serp-count",
        "ai-overview-page-impressions"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-overview-inclusion",
      "name": "AI Overview inclusion",
      "aliases": [
        "AIO inclusion %",
        "On-SERP AI Overview presence"
      ],
      "definition": "The share of observed AI Overview results pages in a segment that include your domain, measured on Google's own results page.",
      "category": "Competitive SERP",
      "type": "rate",
      "unit": "0 to 1 fraction of observed AI Overview results pages (the product multiplies it by 100 for display)",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "A ratio of two co-surfaced measures on the same read: your average daily AI Overview visibility over the average daily count of results pages carrying an AI Overview. Your own leg is your own domain's per-domain competitor column, identified from the tracked-competitor roster; every read injects a results-page feature filter pinned to the AI Overview feature, which is what scopes the population to AI Overview pages rather than all results pages. The semantic layer divides the two measures and applies no hundred-fold scaling and no display format, so the value on the wire is a fraction between zero and one: reconciled against the product on a live tenant, 33,721.5 over 98,007 gives 0.3441, which the product renders as 34.41%. Because it is a ratio, the numerator and denominator are returned alongside it so a period move can be decomposed.",
      "numerator": "average daily AI Overview visibility for the domain",
      "denominator": "average daily count of observed results pages carrying an AI Overview",
      "aggregation": "Never averaged across slices, recompute from the numerator and denominator, which are returned for exactly this reason.",
      "grain": "One segment × period × medium, segment-level only.",
      "dimensions": [
        "competitor domain",
        "intent",
        "brand",
        "country",
        "device"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "serp_feature_filter"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "ai-overview-report",
        "ctr-opportunity-report",
        "search-opportunity-report"
      ],
      "skills": [
        "serp-feature-watch",
        "ai-vs-traditional-gap",
        "competitor-deep-dive",
        "aeo-audit"
      ],
      "verbs": [
        "competitive_overview",
        "competitive_trends"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2",
        "L3"
      ],
      "questions": [
        "How often do we appear in Google's AI Overviews for this segment?",
        "Which rivals appear in more AI Overviews than we do?",
        "Is our AI Overview presence trending up?"
      ],
      "interpretation": "This is presence in Google's on-page answer box for tracked demand, a results-page feature, measured on the same observation as the rest of the competitive family. It says nothing about whether an answer engine cites you, and the two should never be added, averaged, or described in one sentence without naming both surfaces.",
      "caveats": [
        "The value on the wire is a fraction between zero and one with no display format attached. Anything that prints it as a percentage without multiplying by a hundred understates it a hundredfold.",
        "The layer that decides units classifies metrics by name and files this one with the already-0 to 100 percentage family, so a 0.3441 fraction currently renders as 0.34%. Read the fraction, not the rendered figure, until that classification is corrected.",
        "Both sides of the ratio are per-day averages, so this is a ratio of averages rather than a period total over a period total.",
        "Google's on-SERP AI Overview is a different surface from answer-engine citation, measured on a different dataset. The product keeps them apart deliberately and so must any report.",
        "Without the results-page feature filter the read spans all results pages and returns a materially different, wrong figure; the verbs inject it on every AI Overview read.",
        "On this family the competitive verbs apply intent and brand as plain dimension filters, not through the re-weighting filter parameters the market-share verbs use, so a filtered AI Overview read and a filtered share read are not filtered the same way.",
        "Segment-level only: keyword, page and category drills are refused rather than approximated.",
        "Both sides of the ratio move over a period, so a percentage move is not attributable until the numerator and denominator are read separately."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Publishing the raw fraction as though it were already a percentage, or quoting the rendered figure as the rate.",
        "Presenting it as an AI-citation figure, or blending it into an AI-visibility headline.",
        "Comparing periods on the rate alone when the count of AI Overview pages itself changed."
      ],
      "notSameAs": [
        {
          "slug": "ai-citation-rate",
          "why": "This is Google's on-SERP answer box, observed on the competitive results-page explore; that is an answer engine citing a URL, observed by prompting the engines. Different surfaces, different explores, different mechanics, the sharpest boundary in the product, and neither substitutes for the other."
        },
        {
          "slug": "ai-overview-serp-count",
          "why": "That count is this rate's denominator, a per-day average of the results-page population, not a presence rate."
        },
        {
          "slug": "ai-citation-count",
          "why": "A citation is an answer engine sourcing your URL; AI Overview inclusion is presence in Google's on-SERP answer box on a different dataset. The two are named separately every time they could be confused.",
          "mirroredFrom": "ai-citation-count"
        },
        {
          "slug": "ai-share-of-voice",
          "why": "Share of voice is measured on answer-engine responses; AI Overview inclusion is Google's on-SERP feature on a different dataset. Neither is folded into the other.",
          "mirroredFrom": "ai-share-of-voice"
        },
        {
          "slug": "cited-page-citation-count",
          "why": "A cited page is a URL an answer engine sourced; AI Overview inclusion is presence in Google's on-SERP answer box, measured on a different dataset. The verb descriptions open by disclaiming the swap.",
          "mirroredFrom": "cited-page-citation-count"
        },
        {
          "slug": "ai-overview-page-impressions",
          "why": "Inclusion is a presence rate over observed AI Overview pages; this is an average daily page count and is not that rate's numerator.",
          "mirroredFrom": "ai-overview-page-impressions"
        },
        {
          "slug": "ai-overview-daily-visibility",
          "why": "This is the rate's numerator, not the rate. On its own it cannot say how often you appear.",
          "mirroredFrom": "ai-overview-daily-visibility"
        },
        {
          "slug": "featured-snippet-ownership",
          "why": "Both sit above the blue links on Google's results page, but a featured snippet is an extracted passage from one ranked page while an AI Overview is a generated answer; they are separate measures on separate contracts.",
          "mirroredFrom": "featured-snippet-ownership"
        }
      ],
      "related": [
        "ai-overview-page-impressions",
        "ai-overview-daily-visibility",
        "ai-overview-serp-count",
        "featured-snippet-ownership"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-overview-page-impressions",
      "name": "AI Overview average daily page count",
      "aliases": [
        "Average daily page impressions in AI Overviews",
        "Average Daily Page Count in AI Overview"
      ],
      "definition": "The average daily number of your pages counted inside Google's AI Overview box across a segment's observed results pages, the product's fourth AI Overview metric.",
      "category": "Competitive SERP",
      "type": "raw measure",
      "unit": "average daily page count",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "Read as the per-domain competitor column for the chosen domain under the AI Overview results-page feature filter. The semantic layer sums that domain's per-row page column and divides by the number of distinct observed days, and its own label calls the result an average daily page count. Confirmed against the product's own display on a live tenant.",
      "aggregation": "Already a daily average, so it is not summed over the period; comparing two periods compares two averages.",
      "grain": "One domain × segment × period × medium, segment-level only.",
      "dimensions": [
        "competitor domain",
        "intent",
        "brand",
        "country",
        "device"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "serp_feature_filter"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "ai-overview-report"
      ],
      "skills": [
        "serp-feature-watch",
        "competitor-deep-dive",
        "ai-vs-traditional-gap"
      ],
      "verbs": [
        "competitive_overview",
        "competitive_trends"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2",
        "L3"
      ],
      "questions": [
        "How much exposure do our pages get inside AI Overviews?",
        "Which rival's pages carry the most AI Overview exposure?"
      ],
      "interpretation": "A volume companion to the inclusion rate: inclusion says how often you appear, this says how many of your pages the answer box carries on an average day. It is a count of pages, not of impressions or clicks, and the two readings differ by more than wording.",
      "caveats": [
        "It is a daily average, not a period total, multiplying it by the number of days is not the period figure.",
        "The semantic layer labels it a page COUNT. The word impressions in its name predates that reading and overstates what it measures.",
        "Requires the AI Overview results-page feature filter, which the verbs inject; without it the population is all results pages.",
        "Google's on-SERP AI Overview is not answer-engine citation; this metric describes the results page only."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Summing the daily average across the period.",
        "Reporting it as traffic or as exposure volume, it counts pages present in the answer box, not views of them."
      ],
      "notSameAs": [
        {
          "slug": "ai-overview-inclusion",
          "why": "Inclusion is a presence rate over observed AI Overview pages; this is an average daily page count and is not that rate's numerator."
        }
      ],
      "related": [
        "ai-overview-inclusion",
        "ai-overview-daily-visibility",
        "ai-overview-serp-count"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-overview-serp-count",
      "name": "AI Overview average daily results-page count",
      "aliases": [
        "Average daily count of SERPs with an AI Overview",
        "AIO results-page denominator"
      ],
      "definition": "The average daily number of a segment's observed results pages that carried an AI Overview, the denominator of the AI Overview inclusion rate, and the same number for every domain.",
      "category": "Competitive SERP",
      "type": "raw measure",
      "unit": "average daily count of observed results pages carrying an AI Overview",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "Read as a player-independent measure on the same dataset, it belongs to the results-page population, not to any domain, so it is selected once and returned with an empty competitor list. The semantic layer counts the distinct observed results pages and divides by the number of distinct observed days, so it is a per-day average rather than a period population size. Live-verified at 98,007 on the tenant used for the inclusion reconciliation, where 33,721.5 over 98,007 reproduces the displayed 34.41%.",
      "aggregation": "A per-day average: the count of distinct observed days is the divisor. Comparing two periods compares two daily averages, which is still the right way to watch the surface itself move, but multiplying it by the number of days does not give a period count.",
      "grain": "One segment × period × medium.",
      "dimensions": [
        "intent",
        "brand",
        "country",
        "device"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "serp_feature_filter"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "ai-overview-report"
      ],
      "skills": [
        "serp-feature-watch",
        "ai-vs-traditional-gap",
        "anomaly-investigator"
      ],
      "verbs": [
        "competitive_overview",
        "competitive_trends"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2"
      ],
      "questions": [
        "Is Google showing AI Overviews on more of our tracked demand than before?",
        "Did the AI Overview population change between these two periods?"
      ],
      "interpretation": "A read on the surface itself rather than on your performance. A rising daily average with flat visibility means the answer box spread across more of your demand while your presence stood still, a market change, not a site change, and the most common reason an inclusion rate falls without anything going wrong.",
      "caveats": [
        "It is a per-day average, not a period population. The measure divides by the count of distinct observed days, so it answers \"how many AI Overview pages on a typical day\", never \"how many over the period\".",
        "It is player-independent: it is identical for you and for every tracked rival, so it never belongs in a competitive comparison column.",
        "It counts observed results pages in the tracked segment, not all results pages on the web.",
        "It is scoped by the AI Overview results-page feature filter the verbs inject."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Reporting it as \"the number of results pages that carried an AI Overview this period\", it is a daily average, and the period figure is larger.",
        "Presenting it per competitor, which implies a difference that cannot exist.",
        "Ignoring it when narrating an inclusion-rate move."
      ],
      "notSameAs": [
        {
          "slug": "ai-overview-inclusion",
          "why": "This is the denominator, a per-day average count of pages carrying the feature, while inclusion is your presence rate within that population."
        }
      ],
      "related": [
        "ai-overview-inclusion",
        "ai-overview-daily-visibility"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "avg-rank-vs-competitors",
      "name": "Average SERP rank vs competitors",
      "aliases": [
        "Average rank",
        "avg_rank",
        "Weighted position"
      ],
      "definition": "The impression-weighted average results-page position your site holds on a tracked keyword, read side by side with the same figure for tracked competitors.",
      "category": "Competitive SERP",
      "type": "rank",
      "unit": "results-page position (1 is best; higher is worse)",
      "direction": "lower-better",
      "verification": "verified",
      "calculation": "One read of the rank-tracking dataset returns keyword, competitor domain and average rank for every tracked domain in the segment; the roster marks which of those domains is yours. Rows are split by domain into per-keyword maps and sorted ascending, so the best positions lead. The verb states the contract in its own payload: average rank is impression-weighted position, lower is better, and it is distinct from share of voice. The semantic layer defines the position itself as the sum of position weighted by impressions over total impressions, wrapped so that a keyword with no impressions returns zero rather than null.",
      "aggregation": "Never summed. Averaging across keywords discards the demand behind each one, see the separate overall figure and its caveats.",
      "grain": "One keyword × domain × segment × period × medium.",
      "dimensions": [
        "keyword",
        "competitor domain",
        "device",
        "country",
        "brand"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "competitor-search-report"
      ],
      "skills": [
        "keyword-gap-audit",
        "competitor-deep-dive",
        "rank-movement-review"
      ],
      "verbs": [
        "competitive_keyword_ranking",
        "competitive_trends"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2",
        "L3"
      ],
      "questions": [
        "Where do we rank against rivals on these keywords?",
        "Which keywords do we hold the best positions on?",
        "Which of our positions are worst on mobile?"
      ],
      "interpretation": "The plainest competitive read available: one number per keyword per domain, on the same observation for everyone. Impression weighting means a keyword's figure is dominated by the device, geography and day mix that actually generated impressions, so a position that moves without any ranking change is usually a mix shift.",
      "caveats": [
        "A keyword with no impressions in the period comes back as rank zero, not null: the semantic layer wraps the ratio in a zero default. Zero is not a position, and an ascending sort puts it first, so a raw row carrying 0 is an absence of data dressed as best-in-class.",
        "The underlying read is capped at five thousand keyword-and-domain rows across every tracked domain in the segment, so a wide segment or a long roster truncates the keyword set before any of these figures are computed.",
        "Positions come from the rank-tracking dataset, which is a different surface from the share family, a domain can hold good positions and little share, and the reverse.",
        "Only tracked keywords and tracked domains appear; a keyword outside the segment has no row rather than a bad position.",
        "Rows with no position are excluded before the best and worst lists are built, so an empty list means no ranked rows, but that filter protects only those lists, not the raw rows.",
        "Device and country filters change the impression mix and therefore the weighted value; comparing across filter settings compares different populations."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Reading a position improvement as a traffic gain without checking the demand behind the keyword.",
        "Comparing a filtered read with an unfiltered one and narrating the mix shift as movement."
      ],
      "notSameAs": [
        {
          "slug": "search-market-share",
          "why": "Impression-weighted position on a keyword versus CTR-modeled share of tracked demand, different explores, different denominators, and they move independently."
        },
        {
          "slug": "overall-average-rank",
          "why": "This is per keyword; the overall figure averages those per-keyword values without re-weighting by demand."
        },
        {
          "slug": "market-share-standings-rank",
          "why": "That is a search-results position on keywords; this is a position in a share league table. Different explores, different meaning of the number one.",
          "mirroredFrom": "market-share-standings-rank"
        },
        {
          "slug": "competitor-share-by-rank-bucket",
          "why": "Average rank is one number per keyword; this distributes share across ranking bands. Position is the axis here, not the measurement.",
          "mirroredFrom": "competitor-share-by-rank-bucket"
        }
      ],
      "related": [
        "overall-average-rank",
        "head-to-head-rank-gap",
        "ranked-keyword-coverage"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "serp-brand-coverage",
      "name": "Brand coverage",
      "aliases": [
        "brand_coverage"
      ],
      "definition": "A coverage measure on the brand-mention dataset describing how widely a brand appears across a segment's observed results pages.",
      "category": "Competitive SERP",
      "type": "raw measure",
      "unit": "not established",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "Not established.",
      "grain": "One domain × segment × period × medium.",
      "dimensions": [
        "competitor domain",
        "intent",
        "brand"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "ai-overview-report"
      ],
      "skills": [
        "serp-feature-watch",
        "competitor-deep-dive"
      ],
      "verbs": [
        "competitive_overview",
        "competitive_trends"
      ],
      "rungs": [
        "R4"
      ],
      "levers": [
        "L6"
      ],
      "questions": [
        "How widely does our brand appear across these results pages?"
      ],
      "caveats": [
        "Neither the unit nor the direction can be established. The field name is all that is pinned, and a search of every semantic-layer file finds no measure of that name at all.",
        "The only unit it would receive today comes from name matching in the formatting layer, which files anything containing the word coverage with the already-0 to 100 percentage family. That is a naming rule, not evidence of a scale.",
        "It is a non-default sub-metric of a family the verbs gate before any read.",
        "The type recorded here is provisional and may change once the measure is reconciled."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Rendering it as a percentage on the strength of the word coverage.",
        "Comparing it across domains before the scale is known."
      ],
      "notSameAs": [
        {
          "slug": "serp-brand-mentions",
          "why": "Mentions are a count of occurrences; coverage claims to describe spread across pages, and the two cannot be derived from each other until the coverage scale is defined."
        }
      ],
      "related": [
        "serp-brand-mentions",
        "serp-sentiment-share"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "serp-brand-mentions",
      "name": "Brand mentions on the results page",
      "aliases": [
        "Total SERP mentions",
        "Brand mention count"
      ],
      "definition": "How often a brand is mentioned across a segment's observed results pages, counted per domain from the brand-mention dataset.",
      "category": "Competitive SERP",
      "type": "raw measure",
      "unit": "mentions",
      "direction": "higher-better",
      "verification": "review",
      "aggregation": "Would be a count summed across the segment's observed results pages for one domain at a time.",
      "grain": "One domain × segment × period × medium.",
      "dimensions": [
        "competitor domain",
        "intent",
        "brand",
        "country",
        "device"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [],
      "skills": [
        "serp-feature-watch",
        "competitor-deep-dive"
      ],
      "verbs": [
        "competitive_overview",
        "competitive_trends"
      ],
      "rungs": [
        "R2",
        "R4"
      ],
      "levers": [
        "L6"
      ],
      "questions": [
        "How often is our brand mentioned across these results pages?",
        "Is a rival mentioned more than we are?"
      ],
      "caveats": [
        "The family is gated in code: both verbs throw a not-yet-supported error before any read.",
        "The dataset, the mention measure and the per-competitor domain dimension all resolve in the semantic layer, so what is missing is the reconciliation against the product, not the fields, and a check found the figures several times off.",
        "The measure is defined as a sum of a validated-visible mention column that falls back to a legacy machine-generated count, so two periods can be counted on different bases without saying so.",
        "The customer-side measure name is carried in the registry as a hypothesis.",
        "The tenant used to confirm the fields returned no rows for this family, so field validity was established without data volume behind it."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Publishing a mention count that has not been reconciled, which reads as authoritative because the field resolves.",
        "Treating a results-page mention as an answer-engine mention, different surfaces entirely."
      ],
      "notSameAs": [
        {
          "slug": "serp-mention-polarity",
          "why": "This is the total; polarity counts split the same population by tone and are separate measures with their own reconciliation status."
        },
        {
          "slug": "ai-mention-count",
          "why": "On-SERP brand mentions are observed in Google search results. AI-answer mentions are counted inside answer-engine responses. A brand can be mentioned constantly on the SERP and never inside an answer."
        },
        {
          "slug": "serp-brand-coverage",
          "why": "Mentions are a count of occurrences; coverage claims to describe spread across pages, and the two cannot be derived from each other until the coverage scale is defined.",
          "mirroredFrom": "serp-brand-coverage"
        }
      ],
      "related": [
        "serp-mention-polarity",
        "serp-sentiment-share",
        "serp-brand-coverage"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "featured-snippet-ownership",
      "name": "Featured-snippet ownership",
      "aliases": [
        "Snippet owner count",
        "Who owns the answer box"
      ],
      "definition": "Which domain holds the featured snippet on a tracked results page, and how many snippets each domain holds across a segment.",
      "category": "Competitive SERP",
      "type": "raw measure",
      "unit": "featured snippets held",
      "direction": "higher-better",
      "verification": "review",
      "aggregation": "Would be a count across the segment's observed results pages, were the per-domain split available.",
      "grain": "One segment × period × medium; a per-domain grain does not currently exist.",
      "dimensions": [
        "intent",
        "brand",
        "country",
        "device"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "ai-overview-report"
      ],
      "skills": [
        "serp-feature-watch",
        "competitor-deep-dive"
      ],
      "verbs": [
        "competitive_overview",
        "competitive_trends"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L3"
      ],
      "questions": [
        "Who owns the featured snippets on our tracked demand?",
        "Are we losing snippets to a rival?"
      ],
      "caveats": [
        "The family is gated in code: both competitive verbs throw a not-yet-supported error before any read rather than returning an aggregate figure dressed as a competitive one.",
        "The owner-count field exists on the results-page dataset only as an aggregate. It counts distinct owner-and-page pairs across every owner, with no per-competitor domain dimension anywhere that was found, so it can never be split into yours and theirs.",
        "The second field name that would have carried per-domain snippet totals is recorded in the registry as a phantom. It does exist in the semantic layer, but on the customer-category dataset, which carries neither an owner dimension nor competitor columns, so it is a phantom for the dataset this family actually reads.",
        "The per-competitor split most likely needs a semantic-layer addition rather than a query change."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Reporting the aggregate owner count as \"our snippets\".",
        "Inferring a rival's snippet holdings from an aggregate that has no owner dimension."
      ],
      "notSameAs": [
        {
          "slug": "ai-overview-inclusion",
          "why": "Both sit above the blue links on Google's results page, but a featured snippet is an extracted passage from one ranked page while an AI Overview is a generated answer; they are separate measures on separate contracts."
        }
      ],
      "related": [
        "ai-overview-inclusion",
        "serp-brand-mentions"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "head-to-head-rank-gap",
      "name": "Head-to-head rank gap",
      "aliases": [
        "Position gap vs a rival",
        "Rank difference"
      ],
      "definition": "The difference in average results-page position between your site and one named competitor on the same tracked keyword.",
      "category": "Competitive SERP",
      "type": "derived metric",
      "unit": "rank positions (positive means we rank worse than the rival)",
      "direction": "lower-better",
      "verification": "verified",
      "calculation": "Your average rank minus the named competitor's average rank on the same keyword, rounded to two decimal places, computed only where BOTH sides hold a position above zero, otherwise null. The competitor is resolved from the roster by domain or label before the read. A row is kept when either side has a position, ordered so that the keywords YOU rank on come first and ascending by your own position within them; the ordering looks only at your side, not at whether the rival also ranks. Capped at one hundred rows.",
      "aggregation": "Not summable. It is a per-keyword difference; a portfolio view is the distribution of gaps, not their total.",
      "grain": "One keyword × your domain × one competitor domain × segment × period.",
      "dimensions": [
        "keyword",
        "device",
        "country",
        "brand"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium",
        "competitor"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "competitor-search-report"
      ],
      "skills": [
        "keyword-gap-audit",
        "competitor-deep-dive",
        "striking-distance-sprint"
      ],
      "verbs": [
        "competitive_keyword_ranking"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2",
        "L3",
        "L5"
      ],
      "questions": [
        "On which keywords does this rival outrank us, and by how much?",
        "Where are we close enough to overtake them?"
      ],
      "interpretation": "The sign carries the meaning: positive means the rival is ahead of you on that keyword. Small positive gaps on keywords with real demand are the most actionable rows in the family; large gaps usually reflect a different kind of page rather than a small optimisation.",
      "caveats": [
        "Null where either side has no position, that is a coverage fact, not a tie.",
        "Where you hold no position the row still reports your rank as zero rather than null: the semantic layer defaults a no-impressions ratio to zero and the verb defaults a missing keyword to zero as well. A zero in that column means \"no position\", never \"position zero\".",
        "A rival name is resolved by substring against the roster's domains and labels, and an unmatched name falls through as a literal domain, which can return an empty comparison.",
        "The row set is capped at one hundred and the ordering is driven by your own position, so a wide keyword portfolio is truncated by where YOU rank, not by where the gap is largest.",
        "A gap is a position difference, not a traffic difference; nothing here says what either position earns."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Treating a null gap as parity.",
        "Reading a zero in your own rank column as a position rather than an absence.",
        "Ranking work by gap size alone, which puts the hardest keywords at the top of the list."
      ],
      "notSameAs": [
        {
          "slug": "gap-to-leader",
          "why": "That gap is a difference in CTR-modeled share of tracked demand against the segment leader; this one is a difference in ranking positions against a named rival."
        }
      ],
      "related": [
        "avg-rank-vs-competitors",
        "overall-average-rank"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "serp-mention-polarity",
      "name": "Mention polarity counts",
      "aliases": [
        "Positive, negative and neutral mentions"
      ],
      "definition": "The split of a brand's results-page mentions into positive, negative and neutral counts.",
      "category": "Competitive SERP",
      "type": "raw measure",
      "unit": "mentions in each polarity class",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "Would be three counts that together account for the total mention count for one domain and period.",
      "grain": "One domain × polarity class × segment × period × medium.",
      "dimensions": [
        "competitor domain",
        "intent",
        "brand",
        "country",
        "device"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [],
      "skills": [
        "serp-feature-watch",
        "competitor-deep-dive"
      ],
      "verbs": [
        "competitive_overview",
        "competitive_trends"
      ],
      "rungs": [
        "R4"
      ],
      "levers": [
        "L6"
      ],
      "questions": [
        "How much of what is said about us on these results pages is negative?",
        "Did negative mentions rise this period?"
      ],
      "caveats": [
        "Direction is class-dependent, more positive mentions is not the same kind of good as more negative mentions is bad, so a single direction cannot be stamped on the family.",
        "The three counts are opt-in sub-metrics of a gated family; both verbs refuse the whole family before any read.",
        "Each measure name is carried in the registry as a hypothesis, unreconciled against the product. The semantic layer does define all three as sums of the corresponding mention columns, so the open question is the reconciliation, not whether the fields exist.",
        "The three classes are summed from a validated-visible column with a legacy fallback, and they are not guaranteed to add up to the separately defined total-mentions measure."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Summing the three classes and presenting the total as the mention count without checking they reconcile.",
        "Reading a zero class as an absence of sentiment rather than an absence of data."
      ],
      "notSameAs": [
        {
          "slug": "serp-sentiment-share",
          "why": "Counts are volumes; the sentiment percentages are proportions of the same population, and one cannot be inferred from the other without the total."
        },
        {
          "slug": "serp-brand-mentions",
          "why": "This is the total; polarity counts split the same population by tone and are separate measures with their own reconciliation status.",
          "mirroredFrom": "serp-brand-mentions"
        }
      ],
      "related": [
        "serp-brand-mentions",
        "serp-sentiment-share"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "serp-sentiment-share",
      "name": "Mention sentiment percentages",
      "aliases": [
        "Positive SERP sentiment %",
        "Negative SERP sentiment %",
        "Neutral SERP sentiment %"
      ],
      "definition": "The proportion of a brand's results-page mentions falling into each sentiment class.",
      "category": "Competitive SERP",
      "type": "rate",
      "unit": "% of that brand's sentiment-classified mentions in the class",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "Would be a proportion per domain and period; proportions are never averaged across slices without their underlying counts.",
      "grain": "One domain × sentiment class × segment × period × medium.",
      "dimensions": [
        "competitor domain",
        "intent",
        "brand",
        "country",
        "device"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [],
      "skills": [
        "serp-feature-watch",
        "competitor-deep-dive"
      ],
      "verbs": [
        "competitive_overview",
        "competitive_trends"
      ],
      "rungs": [
        "R4"
      ],
      "levers": [
        "L6"
      ],
      "questions": [
        "What share of our results-page mentions read as positive?",
        "How does our sentiment mix compare with a rival's?"
      ],
      "caveats": [
        "The denominator is NOT the brand's total mentions. The semantic layer divides by a separate sentiment-classified mention total, so the three classes sum to a hundred per cent of the classified subset and not of everything counted as a mention.",
        "When that denominator is zero the measure returns zero rather than null, so a 0% class can mean no classified mentions at all rather than no sentiment of that kind.",
        "Percentages at low mention volumes swing hard; without the underlying counts a sentiment mix is not interpretable.",
        "The family is gated before any read, and the measure names are recorded in the registry as hypotheses.",
        "Direction is class-dependent, so no single higher-is-better claim holds for the family."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Quoting a sentiment percentage without the classified mention count behind it.",
        "Reading the percentages as a share of all mentions rather than of the classified subset.",
        "Comparing sentiment mixes between domains with very different mention volumes."
      ],
      "notSameAs": [
        {
          "slug": "serp-mention-polarity",
          "why": "These are proportions of a domain's own mentions; the polarity counts are the volumes those proportions are computed from."
        },
        {
          "slug": "ai-positive-sentiment-rate",
          "why": "Sentiment measured on SERP brand mentions is a different corpus from sentiment measured in answer-engine text. They are collected separately, on different cadences, and are not comparable."
        }
      ],
      "related": [
        "serp-brand-mentions",
        "serp-mention-polarity",
        "serp-brand-coverage"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "overall-average-rank",
      "name": "Overall average rank",
      "aliases": [
        "Site average position across tracked keywords"
      ],
      "definition": "The mean of your per-keyword average ranks across every tracked keyword where your site holds a position, as a single headline figure.",
      "category": "Competitive SERP",
      "type": "derived metric",
      "unit": "results-page position (1 is best; higher is worse)",
      "direction": "lower-better",
      "verification": "verified",
      "calculation": "Each keyword's impression-weighted average rank is collected, rows without a position are dropped, and the remaining values are summed and divided by the number of keywords, rounded to two decimal places. Computed in the MCP over the returned rows. Note the weighting boundary: each keyword's own value is impression-weighted, but this mean over keywords is not, every keyword counts once.",
      "numerator": "sum of the per-keyword average ranks",
      "denominator": "count of tracked keywords with a position",
      "aggregation": "Already an aggregate. Do not average it again across periods or segments; recompute from the keyword rows.",
      "grain": "One segment × period × medium, across the segment's tracked keywords.",
      "dimensions": [
        "device",
        "country",
        "brand"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "competitor-search-report",
        "keyword-ranking-report",
        "serp-volatility-report"
      ],
      "skills": [
        "rank-movement-review",
        "market-share-review",
        "competitor-deep-dive"
      ],
      "verbs": [
        "competitive_keyword_ranking"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2",
        "L3"
      ],
      "questions": [
        "What is our average position across tracked keywords?",
        "Did our overall ranking improve this period?"
      ],
      "interpretation": "A directional headline only. Because every keyword counts equally, a long tail of low-demand keywords can move it while the keywords that matter sit still. Treat a move as a prompt to look at the keyword rows, not as a result.",
      "caveats": [
        "Unweighted across keywords: the demand behind each keyword is discarded at this step, even though it shaped each keyword's own value.",
        "The keyword rows it averages come from a single five-thousand-row read spanning every tracked domain in the segment, so a wide segment or a long roster silently truncates the set the mean is taken over.",
        "Keywords whose position resolves to zero are dropped before the mean. That filter is load-bearing: the semantic layer defaults a keyword with no impressions to zero, and counting those rows would drag the average toward one.",
        "The denominator is the count of keywords with a position, so keywords entering or leaving the tracked set move the figure by themselves.",
        "It is scoped to one segment's tracked keywords, never to the whole site."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Reporting it as \"our average position\" without the tracked-keyword scope.",
        "Comparing it across periods in which the tracked keyword set changed."
      ],
      "notSameAs": [
        {
          "slug": "avg-rank-vs-competitors",
          "why": "The per-keyword figure is impression-weighted; this mean over keywords is not, so the two answer different questions and can move in opposite directions."
        }
      ],
      "related": [
        "avg-rank-vs-competitors",
        "ranked-keyword-coverage",
        "head-to-head-rank-gap"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ranked-keyword-count",
      "name": "Ranked keywords per competitor",
      "aliases": [
        "Competitor ranked-keyword count"
      ],
      "definition": "How many tracked keywords a given domain holds a ranking for, counted per competitor on the rank-tracking dataset.",
      "category": "Competitive SERP",
      "type": "raw measure",
      "unit": "tracked keywords",
      "direction": "higher-better",
      "verification": "review",
      "aggregation": "Would be a count per domain and period; not summable across domains, since the same keyword is counted for each domain that ranks on it.",
      "grain": "One domain × segment × period × medium.",
      "dimensions": [
        "competitor domain",
        "intent",
        "brand",
        "country",
        "device"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "competitor-search-report"
      ],
      "skills": [
        "serp-feature-watch",
        "keyword-gap-audit",
        "competitor-deep-dive"
      ],
      "verbs": [
        "competitive_overview",
        "competitive_trends"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2",
        "L5"
      ],
      "questions": [
        "How many tracked keywords does this rival rank for?",
        "Is a competitor's ranked footprint growing faster than ours?"
      ],
      "caveats": [
        "The per-competitor rows were recovered and confirmed live on the rank-tracking dataset, so the data exists; it is the customer-side measure that is unreconciled, and the family is gated in both verbs because of it.",
        "The measure counts DISTINCT keywords on the rank-tracking dataset's rows. The position predicate that would restrict it to keywords actually holding a rank is written into the semantic layer but commented out, so what it counts is row coverage rather than ranked coverage.",
        "The customer-side measure name is carried in the registry as a hypothesis.",
        "A different, verified count of your own ranked keywords is available from the keyword ranking verb, do not treat the two as the same number."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Comparing your own computed ranked-keyword coverage against this per-competitor measure as if they shared a definition.",
        "Reading a larger ranked footprint as a larger share of demand."
      ],
      "notSameAs": [
        {
          "slug": "ranked-keyword-coverage",
          "why": "Coverage is computed in the MCP from your own returned rows and is published; this is a per-competitor measure on the ranking explore that is currently withheld. Same words, different numbers."
        },
        {
          "slug": "ranked-page-count",
          "why": "One counts keywords a domain ranks on, the other counts that domain's ranking URLs; a single page can carry many keywords."
        }
      ],
      "related": [
        "ranked-page-count",
        "ranked-keyword-coverage",
        "avg-rank-vs-competitors"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ranked-page-count",
      "name": "Ranked pages per competitor",
      "aliases": [
        "Competitor ranked-page count"
      ],
      "definition": "How many distinct URLs a given domain has ranking on a segment's tracked keywords.",
      "category": "Competitive SERP",
      "type": "raw measure",
      "unit": "ranking URLs",
      "direction": "higher-better",
      "verification": "review",
      "aggregation": "Would be a count per domain and period; not summable across domains.",
      "grain": "One domain × segment × period × medium.",
      "dimensions": [
        "competitor domain",
        "intent",
        "brand",
        "country",
        "device"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "competitor-search-report"
      ],
      "skills": [
        "serp-feature-watch",
        "competitor-deep-dive",
        "keyword-gap-audit"
      ],
      "verbs": [
        "competitive_overview",
        "competitive_trends"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2",
        "L5"
      ],
      "questions": [
        "How many pages does this rival have ranking on our tracked demand?",
        "Do they win with a few strong pages or a wide estate?"
      ],
      "caveats": [
        "Per-competitor rows are live-confirmed on the rank-tracking dataset, but the customer-side measure is unreconciled and the family is gated in both verbs.",
        "The measure counts DISTINCT competitor page URLs on the dataset's rows, with the same commented-out position predicate as its keyword sibling, so it counts URLs present in the row set, not URLs holding a rank.",
        "The customer-side measure name is carried in the registry as a hypothesis.",
        "A wide ranking estate is not a strong one; read it beside average rank rather than alone."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Inferring content strategy from page counts without the positions behind them.",
        "Comparing it against your own ranked-keyword coverage, which counts keywords and is a different measure."
      ],
      "notSameAs": [
        {
          "slug": "ranked-keyword-count",
          "why": "Pages and keywords are different units on the same explore, one URL can rank on many keywords, so the two counts never track each other."
        }
      ],
      "related": [
        "ranked-keyword-count",
        "avg-rank-vs-competitors",
        "page-market-share"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ranked-keyword-coverage",
      "name": "Ranked-keyword coverage",
      "aliases": [
        "Tracked keywords with a position",
        "rankedKeywordCount"
      ],
      "definition": "How many of a segment's tracked keywords your site holds any average position on during the period.",
      "category": "Competitive SERP",
      "type": "derived metric",
      "unit": "tracked keywords",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "The count of your own keyword rows whose average rank is greater than zero, taken after the ranking read is split by domain. The greater-than-zero test is load-bearing rather than cosmetic: the semantic layer defaults a keyword with no impressions to rank zero rather than null, so counting rows instead of positions would count absences as coverage. Computed in the MCP from the returned rows, not read as a measure.",
      "aggregation": "A count over one period's rows; not summable across periods, since the same keyword recurs.",
      "grain": "One segment × period × medium.",
      "dimensions": [
        "device",
        "country",
        "brand"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "keyword-ranking-report",
        "monthly-executive-search-report",
        "search-market-share-report",
        "serp-volatility-report"
      ],
      "skills": [
        "keyword-gap-audit",
        "rank-movement-review",
        "market-share-review"
      ],
      "verbs": [
        "competitive_keyword_ranking"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2",
        "L5"
      ],
      "questions": [
        "How many tracked keywords do we hold a position on?",
        "Are we appearing on more of the tracked demand than last month?"
      ],
      "interpretation": "A coverage read on the consideration-set question: not how well you rank, but on how much of the tracked demand you appear at all. Read it beside the overall average position, coverage growing while the average worsens usually means new, weaker entries rather than a decline.",
      "caveats": [
        "The denominator is the segment's tracked keyword set, so growth can come from tracking more keywords rather than from ranking on more of them.",
        "Rows without a position are excluded, so the count is presence, not entitlement, and the exclusion is what keeps the semantic layer's zero default out of the count.",
        "The rows are drawn from one five-thousand-row read covering every tracked domain in the segment, so on a wide segment the count is bounded by the read rather than by your coverage.",
        "This is computed in the MCP from returned rows and is a different quantity from the deferred per-competitor ranked-keyword measure."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Comparing it against a rival's ranked-keyword figure, which comes from a different and currently withheld measure.",
        "Narrating coverage growth as demand growth."
      ],
      "notSameAs": [
        {
          "slug": "ranked-keyword-count",
          "why": "That is a per-competitor measure on the ranking explore, currently withheld pending reconciliation; this is a count the MCP computes from your own returned rows."
        }
      ],
      "related": [
        "avg-rank-vs-competitors",
        "overall-average-rank",
        "ranked-keyword-count"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "actual-ctr",
      "name": "Actual CTR (keyword and page)",
      "aliases": [
        "Observed CTR",
        "Row CTR"
      ],
      "definition": "The click-through rate one keyword-and-page row actually earned in the window: its clicks divided by its impressions.",
      "category": "Content opportunity",
      "type": "rate",
      "unit": "share of impressions that clicked (0 to 1)",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "actualCtr = clicks / impressions for the single keyword-and-page row, rounded to four decimals. Rows with no impressions, non-positive impressions or no position are skipped rather than counted as zero.",
      "numerator": "The row's clicks",
      "denominator": "The row's impressions",
      "aggregation": "Row-level only. Rolling it up means re-pooling the clicks and impressions, not averaging the rates.",
      "grain": "One keyword × one page × the window.",
      "dimensions": [
        "query",
        "page",
        "brand",
        "intent",
        "device",
        "position"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "ctr-opportunity-report",
        "search-opportunity-report"
      ],
      "skills": [
        "ctr-opportunity-audit",
        "cannibalization-check"
      ],
      "verbs": [
        "ctr_curve_model"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L3"
      ],
      "questions": [
        "Which query and page combinations underperform their expected CTR?",
        "What CTR does this page get for this query?"
      ],
      "interpretation": "The measured half of the expectation gap. On its own it says little, a high rate at position 1 and a high rate at position 15 mean different things, which is why it is only ever read against the fitted expectation for the same cell.",
      "caveats": [
        "Expressed as a 0 to 1 fraction, unlike the Search Console average CTR measure, which is already a percentage.",
        "The position it is read against is an impression-weighted average over the window, so a row that moved between positions is measured against a blend.",
        "Rounded to four decimals, which flattens differences on very low-rate rows."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Comparing it to the percentage-scaled average CTR and reporting a hundredfold difference.",
        "Interpreting it without the position it was earned at."
      ],
      "notSameAs": [
        {
          "slug": "ctr",
          "why": "Average CTR is a warehouse measure on a 0 to 100 scale computed over whatever slice was queried; actual CTR is a 0 to 1 fraction computed in our own pass for one keyword-and-page row. They are different scales at different grains and cannot be substituted for each other."
        }
      ],
      "related": [
        "expected-ctr",
        "ctr-delta",
        "ctr-impact"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "aio-haircut",
      "name": "AI-Overview haircut",
      "aliases": [
        "AIO haircut",
        "AI Overview discount"
      ],
      "definition": "The flat discount applied to modeled click upside to account for an AI Overview absorbing clicks that would otherwise reach an organic result.",
      "category": "Content opportunity",
      "type": "rate",
      "unit": "share of the modeled gain discounted (0 to 1); the shipped default is 0.3",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "A single setting applied uniformly to every candidate in a run; it is not derived from the data being analysed.",
      "grain": "One run of the striking-distance analysis.",
      "dimensions": [],
      "requiredFilters": [],
      "sources": [
        "search-console"
      ],
      "reports": [
        "content-decay-report",
        "ctr-opportunity-report",
        "search-opportunity-report"
      ],
      "skills": [
        "striking-distance-sprint",
        "ai-vs-traditional-gap"
      ],
      "verbs": [
        "striking_distance"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L3",
        "L7"
      ],
      "questions": [
        "How much do AI Overviews reduce the upside on these keywords?",
        "What discount is applied to striking-distance estimates?"
      ],
      "caveats": [
        "Caller-settable anywhere between 0 and 1, so two runs of the same worklist can disagree entirely on magnitude while agreeing on order.",
        "Applied uniformly because there is no per-keyword AI Overview flag on this data; it is a stated approximation in the code, not a measurement.",
        "AI Overview presence measured elsewhere in the product is on-results-page inclusion, a different surface from answer-engine citation, neither of them feeds this discount."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Quoting the default as an observed AI Overview effect for a specific site.",
        "Tuning the discount until a worklist reaches a desired total."
      ],
      "notSameAs": [],
      "related": [
        "potential-clicks-adjusted",
        "potential-clicks-raw"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ctr-delta",
      "name": "CTR delta versus the curve",
      "aliases": [
        "Expectation gap",
        "CTR over/under-performance"
      ],
      "definition": "How far a keyword-and-page row's actual click-through rate sits above or below what this site's own fitted curve expects at that row's position.",
      "category": "Content opportunity",
      "type": "derived metric",
      "unit": "CTR points as a 0 to 1 fraction (positive means over-performing)",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "deltaCtr = actualCtr − expectedCtr, where the expectation comes from the fitted curve for that row's own branded × intent × device cell, evaluated at the row's average position. Rounded to four decimals.",
      "aggregation": "Row-level. A cell-level or site-level expectation gap would need both sides re-pooled, not the deltas averaged.",
      "grain": "One keyword × one page × the window.",
      "dimensions": [
        "query",
        "page",
        "brand",
        "intent",
        "device",
        "position"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "content-decay-report",
        "ctr-opportunity-report"
      ],
      "skills": [
        "ctr-opportunity-audit",
        "content-decay-refresh"
      ],
      "verbs": [
        "ctr_curve_model"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L3"
      ],
      "questions": [
        "Which pages earn fewer clicks than their position deserves?",
        "Where are we over-performing our own CTR curve?",
        "Which titles should we rewrite first?"
      ],
      "interpretation": "Both tails are useful and they are used differently: the negative tail is a rewrite worklist, the positive tail is a set of patterns worth copying. Either way it is a hypothesis about the snippet, and a rewrite is measured at day 7, 14 and 30 rather than credited on the spot.",
      "caveats": [
        "A negative gap is a candidate, not a diagnosis: mixed intent inside one query, a blended position, and results-page features all move it without the snippet being at fault.",
        "Rows whose position bucket is flagged low-confidence have an unreliable expectation, so their gap is unreliable too.",
        "When the row's exact cell had no fit, the gap is measured against a substituted curve and the substitution is reported on the row."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Treating the under-performer list as a set of copywriting failures rather than as candidates to test.",
        "Ranking the worklist by gap size and filling it with tiny-impression rows, that is what the impact figure is for."
      ],
      "notSameAs": [],
      "related": [
        "actual-ctr",
        "expected-ctr",
        "ctr-impact"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ctr-impact",
      "name": "CTR impact",
      "aliases": [
        "Expectation-gap impact",
        "Weighted CTR gap"
      ],
      "definition": "How material a row's expectation gap is, expressed in clicks: the size of the gap multiplied by the impressions it applies to.",
      "category": "Content opportunity",
      "type": "derived metric",
      "unit": "clicks over the window (modeled)",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "impact = |actualCtr − expectedCtr| × impressions, rounded to two decimals. It is the ranking key for both the over-performer and the under-performer lists.",
      "aggregation": "Row-level, and deliberately unsigned, direction lives in the CTR delta, magnitude lives here.",
      "grain": "One keyword × one page × the window.",
      "dimensions": [
        "query",
        "page",
        "brand",
        "intent",
        "device"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "ctr-opportunity-report"
      ],
      "skills": [
        "ctr-opportunity-audit"
      ],
      "verbs": [
        "ctr_curve_model"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L3"
      ],
      "questions": [
        "Which CTR gaps are actually worth fixing?",
        "Rank our snippet opportunities by clicks at stake"
      ],
      "interpretation": "The reason the worklist is ordered the way it is: a large gap on a rarely-seen query is worth less than a small gap on a heavily-seen one. It sizes materiality, and it should never be read as clicks that were lost, the expectation is modeled, not observed.",
      "caveats": [
        "Absolute value: a large impact figure can belong to an over-performer, so it is only interpretable beside the sign of the gap.",
        "Modeled against a fitted expectation, so it inherits every caveat on that curve, including its non-stationarity.",
        "Holds impressions constant at their observed level, a rewrite that changes ranking changes the impressions too."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Reporting the impact figure as clicks lost to a bad title.",
        "Summing impact across a worklist and presenting the total as a recoverable number."
      ],
      "notSameAs": [],
      "related": [
        "ctr-delta",
        "potential-clicks-raw"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "expected-ctr",
      "name": "Expected CTR at position",
      "aliases": [
        "Modeled CTR",
        "Fitted CTR",
        "Curve CTR"
      ],
      "definition": "What this site's own history says a result should earn at a given results-page position, for a given branded, intent and device cell.",
      "category": "Content opportunity",
      "type": "derived metric",
      "unit": "share of impressions expected to click (0 to 1)",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "The bucket weighted CTRs are fitted with a pool-adjacent-violators isotonic regression constrained monotone-DECREASING and weighted by each bucket's impressions, fitted once per branded × intent × device cell. Expected CTR at a non-integer position is linearly interpolated between the fitted bucket knots.",
      "aggregation": "One fit per segment cell; cells are never pooled into a single global curve.",
      "grain": "One position, evaluated on one cell's fitted curve.",
      "dimensions": [
        "position",
        "brand",
        "intent",
        "device"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "ctr-opportunity-report",
        "search-opportunity-report"
      ],
      "skills": [
        "ctr-opportunity-audit",
        "striking-distance-sprint",
        "content-decay-refresh"
      ],
      "verbs": [
        "ctr_curve_model",
        "striking_distance"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L3"
      ],
      "questions": [
        "What CTR should we expect at position 4?",
        "What does our own click curve look like for non-brand demand?",
        "How much CTR would we gain moving from position 9 to 5?"
      ],
      "interpretation": "The benchmark this product uses instead of a published industry table: the site's own past behaviour, made monotone so that a better position never predicts a worse rate. It is the expectation a page is measured against, not a target it is promised.",
      "caveats": [
        "One blended global curve is refused by design, the branded and non-branded gap dominates click-through, so a blend would flatter one half and libel the other.",
        "The curve is non-stationary: it drifts with results-page layout and with seasonality, so a fit from one window does not describe another.",
        "When a row's exact cell has no fit, the substitute is the same-brand curve carrying the most impressions and, failing that, the most-data cell overall, proximity in intent or device does not enter the choice. The match kind is reported per row so a substituted curve is visible.",
        "Buckets fitted from few instances are flagged low-confidence and the expectation drawn from them is weak.",
        "Never an industry benchmark. Quoting a published CTR table beside this number defeats the reason it exists."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Presenting the fitted curve as an industry benchmark or a target.",
        "Applying a curve fitted on branded demand to a non-branded worklist without noticing the substituted cell.",
        "Carrying a curve across a layout change and reading the drift as performance."
      ],
      "notSameAs": [],
      "related": [
        "weighted-ctr",
        "actual-ctr",
        "ctr-delta",
        "ctr-gain",
        "fallback-ctr-prior"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "fallback-ctr-prior",
      "name": "Fallback CTR prior",
      "aliases": [
        "Generic prior",
        "Fallback curve"
      ],
      "definition": "The generic position-to-click-rate table used only when no curve can be fitted from the site's own data, so a worklist can still be sized, labelled in the output as not this site's curve.",
      "category": "Content opportunity",
      "type": "rate",
      "unit": "expected share of impressions that clicked, per position (0 to 1)",
      "direction": "higher-better",
      "verification": "review",
      "aggregation": "A lookup by rounded position, clamped to positions 1 through 20. It is not fitted and does not vary by segment cell.",
      "grain": "One position, globally.",
      "dimensions": [
        "position"
      ],
      "requiredFilters": [],
      "sources": [
        "search-console"
      ],
      "reports": [
        "content-decay-report",
        "ctr-opportunity-report",
        "search-opportunity-report"
      ],
      "skills": [
        "striking-distance-sprint"
      ],
      "verbs": [
        "striking_distance"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L3"
      ],
      "questions": [
        "What happens when there is not enough data to fit our own CTR curve?",
        "Why is this worklist marked as using a fallback?"
      ],
      "caveats": [
        "It fires only when the site's own fit fails; every affected row is marked, and the response carries an explicit fallback warning.",
        "Any upside sized from it is not this site's modeled upside, and the difference is not a rounding matter.",
        "The rest of this product line refuses published click-rate tables on the grounds that they do not describe today's results pages, which makes the presence of this one a contradiction to resolve, not a convenience to document."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Presenting fallback-sized upside as the site's own modeled upside.",
        "Comparing a fallback-sized worklist to a fitted one across periods."
      ],
      "notSameAs": [],
      "related": [
        "expected-ctr",
        "potential-clicks-adjusted",
        "ctr-bucket-support"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ctr-gain",
      "name": "Modeled CTR gain to a target position",
      "aliases": [
        "CTR uplift",
        "Curve gain"
      ],
      "definition": "The extra click-through rate this site's own curve predicts for a keyword if it moved from where it ranks now to a target position.",
      "category": "Content opportunity",
      "type": "derived metric",
      "unit": "CTR points as a 0 to 1 fraction",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "ctrGain = max(0, expectedCtr(target) − expectedCtr(current)) evaluated on the row's own fitted curve. The floor at zero is safe because the fit is monotone-decreasing, so a target above the current position can never predict a loss.",
      "aggregation": "Row-level; it is an input to the upside figures rather than something to aggregate on its own.",
      "grain": "One keyword × one page × the current-to-target pair.",
      "dimensions": [
        "query",
        "page",
        "brand",
        "intent",
        "device",
        "position"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "ctr-opportunity-report",
        "search-opportunity-report"
      ],
      "skills": [
        "striking-distance-sprint"
      ],
      "verbs": [
        "striking_distance"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L3",
        "L4"
      ],
      "questions": [
        "How much CTR would we gain moving this keyword from 11 to 5?",
        "What is the click-rate upside of reaching page 1?"
      ],
      "interpretation": "The per-impression part of the upside story. It says nothing about how hard the move is, the curve models what happens if a position changes, never whether it will.",
      "caveats": [
        "The target position is a default (5) and a knob. Changing it changes every number in the worklist, so the target belongs beside the result.",
        "Rows already at or above the target are excluded from the candidate set rather than modeled at a gain of zero.",
        "Both ends of the gain come from the same fitted curve, so a low-confidence cell makes the gain unreliable at both ends at once."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Comparing two worklists built with different target positions.",
        "Reading a gain as achievable without any assessment of ranking difficulty."
      ],
      "notSameAs": [],
      "related": [
        "expected-ctr",
        "potential-clicks-raw",
        "striking-distance-candidates"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ctr-bucket-support",
      "name": "Position-bucket support",
      "aliases": [
        "Bucket instances",
        "Low-confidence bucket flag"
      ],
      "definition": "How many keyword-and-page instances a position bucket's click rate was fitted from, and the flag raised when that count falls below the reliability floor.",
      "category": "Content opportunity",
      "type": "raw measure",
      "unit": "keyword-and-page instances per position bucket",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "instances = COUNT(*) of the keyword-and-page rows grouped into that branded × intent × device × position bucket. A bucket fitted from fewer instances than the reliability floor (default 5) is flagged low-confidence; flagged buckets are kept in the fit rather than dropped.",
      "aggregation": "A count per bucket. A cell in which no bucket clears the floor is reported as a sparse cell, its entire curve is weak, not just one point of it.",
      "grain": "One position bucket inside one branded × intent × device cell.",
      "dimensions": [
        "position bucket",
        "brand",
        "intent",
        "device"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "ctr-opportunity-report",
        "search-opportunity-report"
      ],
      "skills": [
        "ctr-opportunity-audit",
        "striking-distance-sprint"
      ],
      "verbs": [
        "ctr_curve_model",
        "striking_distance"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L3"
      ],
      "questions": [
        "How reliable is our CTR curve at these positions?",
        "Which segments do not have enough data to model?"
      ],
      "interpretation": "The reason a curve is trustworthy or is not. Where support is thin, the expected CTR, the gap and every upside figure derived from it are thin too, and the affected rows are labelled rather than dropped, so a worklist never quietly loses its weakest half.",
      "caveats": [
        "The floor is a caller-settable convention, not a power calculation, it does not correspond to a confidence level.",
        "Support counts instances, not impressions, so a bucket can clear the floor on many tiny rows.",
        "Widening the fitted window raises support but ages the curve, and the curve drifts."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Dropping low-confidence rows from a worklist instead of labelling them.",
        "Reading a high instance count as high impression volume."
      ],
      "notSameAs": [],
      "related": [
        "weighted-ctr",
        "expected-ctr",
        "fallback-ctr-prior"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "potential-clicks-adjusted",
      "name": "Potential clicks, AI-Overview-adjusted",
      "aliases": [
        "Adjusted upside clicks",
        "Haircut upside"
      ],
      "definition": "The modeled click upside of a rank nudge after a flat discount is applied for AI Overviews absorbing clicks, the figure the striking-distance worklist is ranked on.",
      "category": "Content opportunity",
      "type": "derived metric",
      "unit": "clicks over the window (modeled, discounted)",
      "direction": "higher-better",
      "verification": "review",
      "aggregation": "Row-level, and the sort key for the returned candidate list.",
      "grain": "One keyword × one page × the window.",
      "dimensions": [
        "query",
        "page",
        "brand",
        "intent",
        "device"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "content-decay-report",
        "search-opportunity-report"
      ],
      "skills": [
        "striking-distance-sprint"
      ],
      "verbs": [
        "striking_distance"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L3",
        "L7"
      ],
      "questions": [
        "What should we push next for the fastest click wins?",
        "Rank our striking-distance keywords by realistic upside"
      ],
      "caveats": [
        "The discount is uniform across candidates because the underlying data carries no per-keyword AI Overview flag, the code states this rather than implying it.",
        "The ordering of the worklist is unaffected by a flat discount; only the magnitudes move. Two runs with different discount settings produce the same order and different numbers.",
        "An AI Overview can erase the modeled gain entirely on a results page it dominates, which a percentage discount cannot express."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Presenting the adjusted number as a forecast of traffic.",
        "Comparing adjusted figures across runs that used different discount settings.",
        "Reading the discount as a measured AI Overview effect for this site."
      ],
      "notSameAs": [],
      "related": [
        "potential-clicks-raw",
        "aio-haircut",
        "ctr-gain"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "potential-clicks-raw",
      "name": "Potential clicks, before the AI-Overview discount",
      "aliases": [
        "Raw upside clicks",
        "Modeled upside"
      ],
      "definition": "The clicks a keyword would have earned over the same window if it had ranked at the target position instead of where it ranks now, at this site's own modeled click rates.",
      "category": "Content opportunity",
      "type": "derived metric",
      "unit": "clicks over the window (modeled)",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "rawUpside = impressions × ctrGain, the row's observed impressions carried at the modeled click-rate gain from its current position to the target. Rounded to two decimals.",
      "aggregation": "Row-level. A worklist total assumes every candidate is nudged in the same period, which is a scenario rather than a forecast.",
      "grain": "One keyword × one page × the window.",
      "dimensions": [
        "query",
        "page",
        "brand",
        "intent",
        "device"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "content-decay-report",
        "ctr-opportunity-report",
        "search-opportunity-report"
      ],
      "skills": [
        "striking-distance-sprint",
        "content-decay-refresh"
      ],
      "verbs": [
        "striking_distance"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L3",
        "L4"
      ],
      "questions": [
        "How many clicks are our striking-distance keywords worth?",
        "What is the upside if we get these keywords onto page 1?"
      ],
      "interpretation": "A sizing device for prioritisation, and the word modeled belongs wherever it is shown. Its job is to order a worklist, not to enter a forecast, the ordering is far more reliable than the magnitude.",
      "caveats": [
        "Impressions are held at their current level, but a ranking change usually changes impressions too, in either direction.",
        "Every number inherits the fitted curve's caveats: non-stationary, segment-specific, and weak wherever a bucket is flagged low-confidence.",
        "It is the pre-discount figure, the worklist ranks on the AI-Overview-adjusted number instead, and the two should never be quoted interchangeably."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Rounding a modeled upside into a commitment.",
        "Summing the whole worklist and presenting the total as expected traffic.",
        "Quoting the raw figure where the adjusted one is the number the product ranked on."
      ],
      "notSameAs": [],
      "related": [
        "ctr-gain",
        "potential-clicks-adjusted",
        "striking-distance-candidates"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "striking-distance-candidates",
      "name": "Striking-distance candidates",
      "aliases": [
        "Striking distance keywords",
        "Near-page-1 keywords"
      ],
      "definition": "The keywords sitting inside the near-page-1 band that still rank below the target position, the rows where a small ranking nudge is the lever.",
      "category": "Content opportunity",
      "type": "raw measure",
      "unit": "candidate keyword-and-page rows",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "A keyword-and-page row qualifies when its impression-weighted average position falls inside the band (default 8 to 20 inclusive), is strictly below the target position (default 5), and the row has positive impressions. Qualifying rows are ranked by adjusted upside and cut to the requested top N.",
      "aggregation": "A count of qualifying rows; the returned list is the top N of them and not the whole set.",
      "grain": "One keyword × one page × the window.",
      "dimensions": [
        "query",
        "page",
        "brand",
        "intent",
        "device"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "search-opportunity-report"
      ],
      "skills": [
        "striking-distance-sprint",
        "content-decay-refresh"
      ],
      "verbs": [
        "striking_distance"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L3",
        "L4"
      ],
      "questions": [
        "Which keywords are closest to page 1?",
        "What are our quick wins this week?",
        "Show me positions 8 to 20 for non-brand demand"
      ],
      "interpretation": "The candidate pool, not the plan. Membership is a position fact; whether a candidate is worth working depends on the modeled upside beside it and on business value the data does not carry.",
      "caveats": [
        "The band and the target are defaults rather than findings, widening the band changes both the count and the ranking.",
        "Position is the window's impression-weighted average, so a keyword that swung between position 4 and position 25 can average into the band without ever having sat there.",
        "Rows already at or above the target are excluded rather than shown with zero upside.",
        "Windows stretched far enough back to cross Google's September 2025 reporting change carry that artifact into the band membership."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Treating band membership as a difficulty assessment.",
        "Comparing candidate counts across runs that used different bands or targets."
      ],
      "notSameAs": [],
      "related": [
        "potential-clicks-adjusted",
        "ctr-gain",
        "avg-position"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "weighted-ctr",
      "name": "Weighted CTR at a position bucket",
      "aliases": [
        "Bucket CTR",
        "Pooled CTR"
      ],
      "definition": "The click-through rate of a whole results-page position, pooled across every keyword-and-page row that landed at that position: total clicks over total impressions.",
      "category": "Content opportunity",
      "type": "rate",
      "unit": "share of impressions that clicked (0 to 1)",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "Each row's average position is rounded to an integer and clamped to the range 1 to 20. Rows are grouped by branded flag × intent × device × bucket, and the bucket's rate is SUM(clicks) / SUM(impressions), never the mean of the per-row rates, which would let a two-impression row weigh as much as a two-million-impression one.",
      "numerator": "Clicks summed across the bucket's rows",
      "denominator": "Impressions summed across the bucket's rows",
      "aggregation": "Recompute from the summed columns at every level. A mean of bucket rates is not a curve.",
      "grain": "One position bucket inside one branded × intent × device cell, for the fitted window.",
      "dimensions": [
        "position bucket",
        "brand",
        "intent",
        "device"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "ctr-opportunity-report"
      ],
      "skills": [
        "ctr-opportunity-audit",
        "striking-distance-sprint",
        "content-decay-refresh"
      ],
      "verbs": [
        "ctr_curve_model"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L3"
      ],
      "questions": [
        "What CTR do we actually get at position 5?",
        "How does our click-through rate fall off by position?",
        "Is branded CTR different from non-branded at the same position?"
      ],
      "interpretation": "The raw observed shape of this site's own curve, before any smoothing. It is where the branded and non-branded gap becomes visible, which is the reason the model refuses to emit one blended curve for the whole site.",
      "caveats": [
        "Only positions 1 through 20 are bucketed; anything deeper is clamped into the last bucket rather than fitted.",
        "Rows without positive impressions or without a position are dropped before bucketing rather than counted as zero.",
        "The window is pinned to organic web search, so image, video and news rows never enter the fit.",
        "A bucket's rate is only as reliable as the number of rows behind it, the support count and its low-confidence flag travel with each bucket."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Averaging per-row CTRs into a bucket and getting a curve dominated by tiny rows.",
        "Reading one blended curve across branded and non-branded demand."
      ],
      "notSameAs": [
        {
          "slug": "ctr",
          "why": "Search Console's average CTR is a warehouse measure returned on a 0 to 100 scale for whatever slice was queried; weighted CTR is computed in our own compute pass as a 0 to 1 fraction for one position bucket inside one segment cell. Same arithmetic, different scale and a completely different grain."
        }
      ],
      "related": [
        "expected-ctr",
        "actual-ctr",
        "ctr-bucket-support"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "bot-hits",
      "name": "Bot hits",
      "aliases": [
        "Crawl hits",
        "Bot requests",
        "Crawl volume"
      ],
      "definition": "The number of requests a named crawler made to your origin in the period, counted from server logs.",
      "category": "Crawl and logs",
      "type": "raw measure",
      "unit": "log requests",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "A row count over the server-log records matching the bot filter and date range. In the semantic layer it is a plain count measure over the log table.",
      "aggregation": "Sums across rows. One page fetched twice contributes two.",
      "grain": "One count per bot per date range, or one count per bot per day, week or month when a granularity is requested.",
      "dimensions": [
        "bot_type",
        "date"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "server-logs"
      ],
      "reports": [
        "ai-bot-activity-report",
        "crawl-log-report",
        "internal-linking-report",
        "technical-seo-audit-report"
      ],
      "skills": [
        "ai-crawler-readiness",
        "crawl-efficiency-review",
        "technical-health-audit"
      ],
      "verbs": [
        "ai_crawler_analysis"
      ],
      "rungs": [
        "R1"
      ],
      "levers": [
        "L1"
      ],
      "questions": [
        "Are AI crawlers reaching our content?",
        "Which bots crawl us most?",
        "Has GPTBot activity changed?"
      ],
      "interpretation": "Evidence of what your origin actually served, which no other source can supply, everything else infers crawling. It counts requests, not pages and not coverage, so a rising number can mean broader reach or the same handful of pages fetched more often.",
      "caveats": [
        "Requests, not pages. Read it beside the unique-pages figure before calling it coverage.",
        "The answer-engine bot list is a hardcoded user-agent token set covering GPTBot, ChatGPT-User, PerplexityBot, ClaudeBot, Claude-Web, Google-Extended, CCBot and Bytespider. It is documented in code as drifting on a timescale of months, so a bot that renamed or launched since will be missing.",
        "Matching is on the declared user agent. Only Googlebot has an IP verification path; there is no address verification for any AI bot, so an AI-bot count includes anything that claimed the name.",
        "Logs record what your origin served, so a request answered by a CDN edge may never appear. Absence of a bot is evidence your logs do not have it, which is a weaker claim than it never came.",
        "Crawl activity is not visibility: fetch counts are never presented as citations.",
        "The tool checks the log feed is populated before reading and returns a plain note when it is not, rather than an empty result."
      ],
      "freshness": "hours to nightly, depends on how logs are shipped; the card carries the ingestion time.",
      "failureModes": [
        "Presenting fetch counts as AI visibility or as citations.",
        "Concluding a bot is blocked because it is absent from the logs.",
        "Reading a hit count as pages reached."
      ],
      "notSameAs": [
        {
          "slug": "crawler-readiness",
          "why": "Observed visits are what was fetched. Readiness is whether the pages you want cited are reachable, indexable and linked, a composition that is not implemented; no tool crosses log hits with indexability and orphan status."
        },
        {
          "slug": "unique-pages-crawled-by-bots",
          "why": "Hits count requests; unique pages count distinct URLs. A large hit count over a small page set is a crawl-budget finding, not a coverage one."
        },
        {
          "slug": "verified-vs-spoofed-googlebot",
          "why": "Hit counts are matched on the declared user agent alone. Only the verification split establishes whether a requester was who it claimed to be, and it does so for Googlebot only.",
          "mirroredFrom": "verified-vs-spoofed-googlebot"
        },
        {
          "slug": "crawl-depth",
          "why": "Depth is what the crawl graph says is reachable; hits are what a bot actually fetched. Conflating the two is how a team concludes a page is fine because it could in principle be crawled.",
          "mirroredFrom": "crawl-depth"
        }
      ],
      "related": [
        "unique-pages-crawled-by-bots",
        "status-code-hits",
        "verified-vs-spoofed-googlebot",
        "crawler-readiness"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "crawl-depth",
      "name": "Crawl depth",
      "aliases": [
        "Click depth",
        "Distance from homepage"
      ],
      "definition": "How many link steps from the homepage the crawler needed to reach a URL.",
      "category": "Crawl and logs",
      "type": "raw measure",
      "unit": "link steps",
      "direction": "lower-better",
      "verification": "inferred",
      "aggregation": "A per-URL attribute, not an aggregate. The crawl-budget tool filters to URLs at or beyond a depth threshold, five by default, and sorts deepest first.",
      "grain": "One value per crawled URL.",
      "dimensions": [
        "url"
      ],
      "requiredFilters": [],
      "sources": [
        "site-crawl"
      ],
      "reports": [
        "ai-bot-activity-report",
        "crawl-log-report",
        "internal-linking-report",
        "technical-seo-audit-report"
      ],
      "skills": [
        "crawl-efficiency-review",
        "technical-health-audit",
        "linking-opportunity-review"
      ],
      "verbs": [
        "crawl_budget_waste",
        "internal_link_flow"
      ],
      "rungs": [
        "R1"
      ],
      "levers": [
        "L1",
        "L4"
      ],
      "questions": [
        "Which pages are buried deep in the site?",
        "Where is crawl budget going?"
      ],
      "interpretation": "An architecture signal: pages that earn should not sit five clicks from the homepage. It is a property of the link graph as the crawl found it, so it responds to internal linking work rather than to content work.",
      "caveats": [
        "The value is a passthrough of a column the crawler produces; the derivation lives in the crawler and is not readable in the semantic layer, so the exact traversal rules are not documented here.",
        "The depth threshold is a caller-chosen parameter defaulting to five, so a waste list is not comparable across calls that used different thresholds.",
        "A crawl is a snapshot on its own schedule and can disagree with a page changed since.",
        "It reports what is REACHABLE, never what was actually fetched, that is the server logs' job.",
        "The tool checks the crawl feed is populated first and returns a plain note when it is not."
      ],
      "freshness": "per crawl schedule, cadence is set per site; the card names the crawl it read.",
      "failureModes": [
        "Reading depth as importance.",
        "Comparing waste lists produced with different depth thresholds.",
        "Concluding a deep page is not crawled, depth is reachability, not fetch evidence."
      ],
      "notSameAs": [
        {
          "slug": "bot-hits",
          "why": "Depth is what the crawl graph says is reachable; hits are what a bot actually fetched. Conflating the two is how a team concludes a page is fine because it could in principle be crawled."
        }
      ],
      "related": [
        "incoming-internal-links",
        "outgoing-internal-links",
        "indexability-flags"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "crawler-readiness",
      "name": "Crawler readiness",
      "aliases": [
        "AI crawler readiness",
        "Crawl-to-citation readiness"
      ],
      "definition": "Whether the pages you want cited are both fetchable in practice and fit to be indexed, log-observed crawling crossed with indexability and orphan status on the same URLs.",
      "category": "Crawl and logs",
      "type": "derived metric",
      "unit": "not defined, the composition does not exist",
      "direction": "neutral",
      "verification": "review",
      "grain": "Would be one judgment per URL if it existed.",
      "dimensions": [
        "url"
      ],
      "requiredFilters": [],
      "sources": [
        "server-logs",
        "site-crawl"
      ],
      "reports": [
        "ai-bot-activity-report"
      ],
      "skills": [
        "ai-crawler-readiness"
      ],
      "verbs": [],
      "rungs": [
        "R1"
      ],
      "levers": [
        "L1",
        "L4"
      ],
      "questions": [
        "Are AI crawlers reaching the content we want cited?",
        "Which citation targets are unreachable?"
      ],
      "caveats": [
        "There is no single readiness number: nothing crosses log hits with indexability and orphan status for you.",
        "Answering a readiness question means running the underlying reads separately and presenting them as separate sections, saying that the per-URL join is not available rather than implying a composed judgment.",
        "The two contributing sources are on different clocks: logs arrive hours to nightly, the crawl runs on its own per-site schedule. Even a manual cross-read compares observations taken at different times.",
        "Absence of a bot in the logs is evidence your logs do not have it, not proof it never came, a weaker claim, and it is made as the weaker one.",
        "No answer-engine crawler has address verification, so the log side of any manual cross-read rests on user-agent strings."
      ],
      "freshness": "per crawl schedule, cadence is set per site; the card names the crawl it read.",
      "failureModes": [
        "Presenting bot fetch counts as readiness or as AI visibility.",
        "Simulating the join by pairing rows from separate tool results and presenting the pairing as a product output.",
        "Reading a page as ready because it is indexable, without log evidence that anything fetched it."
      ],
      "notSameAs": [
        {
          "slug": "bot-hits",
          "why": "Observed bot visits are what was fetched, from server logs. Readiness is a composed judgment over fetching, indexability and orphan status, and that composition is not implemented, so the two must never be presented as the same claim."
        },
        {
          "slug": "incoming-internal-links",
          "why": "Orphan status is one input readiness would need, not readiness itself."
        }
      ],
      "related": [
        "bot-hits",
        "unique-pages-crawled-by-bots",
        "indexability-flags",
        "incoming-internal-links"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "crawler-response-time",
      "name": "Crawler response time",
      "aliases": [
        "Crawler TTFB",
        "Average time taken"
      ],
      "definition": "How long your server took on average to answer a crawler's request.",
      "category": "Crawl and logs",
      "type": "raw measure",
      "unit": "not established",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "An average of the per-request time-taken field across the matching log records, grouped by bot.",
      "grain": "One average per bot per date range.",
      "dimensions": [
        "bot_type"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "server-logs"
      ],
      "reports": [
        "ai-bot-activity-report",
        "core-web-vitals-report",
        "crawl-log-report",
        "technical-seo-audit-report"
      ],
      "skills": [
        "crawl-efficiency-review",
        "technical-health-audit"
      ],
      "verbs": [
        "ttfb_crawl_impact"
      ],
      "rungs": [
        "R1"
      ],
      "levers": [
        "L1"
      ],
      "questions": [
        "How fast do we respond to Googlebot?",
        "Are crawlers being slowed down?"
      ],
      "caveats": [
        "Unit and direction are not established for this metric.",
        "The tool labels it explicitly: this is per-request server-hit latency, not a per-crawl-session measure, and the label rides on every response.",
        "Available on the internal tool surface only today.",
        "It is an unweighted average across requests, so a burst of fast static asset fetches will pull it down.",
        "Same origin-only caveat as all log reads."
      ],
      "freshness": "hours to nightly, depends on how logs are shipped; the card carries the ingestion time.",
      "failureModes": [
        "Reading it as time to first byte for a page load as a visitor would experience it.",
        "Rendering it with a unit taken from a name-based formatter, which will not agree with the field name.",
        "Painting a rise as an improvement because the direction oracles default it to higher-is-better."
      ],
      "notSameAs": [
        {
          "slug": "largest-contentful-paint",
          "why": "Server response latency to a crawler is not page-render speed for a visitor. They are different measurements from different sources and neither predicts the other."
        }
      ],
      "related": [
        "bot-hits",
        "status-code-hits"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "incoming-internal-links",
      "name": "Incoming internal links",
      "aliases": [
        "Inlinks",
        "Internal links to a page",
        "Orphan test"
      ],
      "definition": "How many internal links point at a URL, and, where that count is zero, the test that marks the page an orphan.",
      "category": "Crawl and logs",
      "type": "raw measure",
      "unit": "internal links",
      "direction": "higher-better",
      "verification": "inferred",
      "aggregation": "A per-URL attribute from the crawl graph. The orphan list is the same field filtered to exactly zero; the link-distribution list sorts by it, least-linked first by default.",
      "grain": "One value per crawled URL.",
      "dimensions": [
        "url"
      ],
      "requiredFilters": [],
      "sources": [
        "site-crawl"
      ],
      "reports": [
        "ai-bot-activity-report",
        "crawl-log-report",
        "internal-linking-report",
        "technical-seo-audit-report"
      ],
      "skills": [
        "linking-opportunity-review",
        "technical-health-audit",
        "ai-crawler-readiness"
      ],
      "verbs": [
        "orphan_pages",
        "internal_link_flow"
      ],
      "rungs": [
        "R1",
        "R2"
      ],
      "levers": [
        "L4"
      ],
      "questions": [
        "Which pages have no internal links?",
        "Which important pages are under-linked?"
      ],
      "interpretation": "The cheapest lever's measurement. A page with few incoming links and real search value is a linking opportunity; a page with none is an orphan, hard for crawlers and people to reach. Link counts are graph facts as of the last recompute, so they do not move day to day.",
      "caveats": [
        "The count is a passthrough of a crawler-produced column; the crawler's rules for what counts as a link are not readable in the semantic layer.",
        "The orphan test is an exact zero on this field, so a page reachable only through a redirect or a script-driven link may be counted as an orphan or missed, depending on the crawler's rules.",
        "Both lists are capped, so they are the top or bottom of the distribution rather than the whole graph.",
        "A crawl is a snapshot on its own schedule; do not narrate day-level link changes.",
        "An orphan is not automatically a problem, an intentionally unlinked page is a different case from a starved one."
      ],
      "freshness": "per crawl schedule, cadence is set per site; the card names the crawl it read.",
      "failureModes": [
        "Treating every orphan as a defect worth fixing.",
        "Reading the capped list as the complete orphan set.",
        "Reporting a link-count change between two crawls run at different cadences as a trend."
      ],
      "notSameAs": [
        {
          "slug": "outgoing-internal-links",
          "why": "One counts links arriving at a page, the other counts links leaving it. Both come from the crawl graph and they move for entirely different reasons."
        },
        {
          "slug": "crawler-readiness",
          "why": "Orphan status is one input to readiness, not readiness itself. No tool crosses it with log hits and indexability, so the composed judgment does not exist."
        }
      ],
      "related": [
        "outgoing-internal-links",
        "crawl-depth",
        "indexability-flags",
        "crawler-readiness"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "indexability-flags",
      "name": "Indexability flags",
      "aliases": [
        "Indexable status",
        "Indexation reason"
      ],
      "definition": "Whether the crawler judged a URL indexable, and the reason when it did not, the noindex directive, the canonical state and the HTTP status it was served.",
      "category": "Crawl and logs",
      "type": "raw measure",
      "unit": "flag values and reason labels per URL",
      "direction": "neutral",
      "verification": "inferred",
      "aggregation": "Per-URL attributes, not aggregates. The diagnosis tool filters to URLs judged not indexable and returns the reason fields beside each one.",
      "grain": "One set of flags per crawled URL.",
      "dimensions": [
        "url"
      ],
      "requiredFilters": [],
      "sources": [
        "site-crawl"
      ],
      "reports": [
        "ai-bot-activity-report",
        "crawl-log-report",
        "internal-linking-report",
        "technical-seo-audit-report"
      ],
      "skills": [
        "technical-health-audit",
        "ai-crawler-readiness",
        "linking-opportunity-review"
      ],
      "verbs": [
        "indexation_gap_diagnosis",
        "orphan_pages"
      ],
      "rungs": [
        "R1"
      ],
      "levers": [
        "L1"
      ],
      "questions": [
        "What pages are blocked from indexing?",
        "Why is this page not indexed?"
      ],
      "interpretation": "The reason column that turns an indexation problem into a task. Read the indexable judgment and the reason together, a page can be non-indexable by directive, by canonical, or by status, and each has a different owner and a different fix.",
      "caveats": [
        "These are passthroughs of crawler-produced columns. The crawler's rules for deciding indexability are not readable in the semantic layer, so the flag is reported as the crawl's judgment rather than as a derived formula.",
        "The judgment is what the crawl found; it is not confirmation of what the search engine did. Crawl reachability and actual indexing are different claims.",
        "The list is capped, so it is the top non-indexable URLs rather than every one.",
        "A crawl is a snapshot on its own schedule and can disagree with a page changed since."
      ],
      "freshness": "per crawl schedule, cadence is set per site; the card names the crawl it read.",
      "failureModes": [
        "Reading a non-indexable flag as proof a page is absent from the index.",
        "Reporting the capped list as the complete set of blocked pages.",
        "Acting on a stale crawl for a page that was fixed after it ran."
      ],
      "notSameAs": [
        {
          "slug": "status-code-hits",
          "why": "Indexability flags are the crawl's assessment of a page; status-code hits are what your server actually returned to a real crawler. Assessment and observation, from different sources."
        }
      ],
      "related": [
        "incoming-internal-links",
        "crawl-depth",
        "status-code-hits",
        "crawler-readiness"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "outgoing-internal-links",
      "name": "Outgoing internal links",
      "aliases": [
        "Outlinks",
        "Canonical links from a page"
      ],
      "definition": "How many internal links a URL points at.",
      "category": "Crawl and logs",
      "type": "raw measure",
      "unit": "internal links",
      "direction": "neutral",
      "verification": "inferred",
      "aggregation": "A per-URL attribute from the crawl graph, returned alongside the incoming count so the two sides of a page's linking position can be read together.",
      "grain": "One value per crawled URL.",
      "dimensions": [
        "url"
      ],
      "requiredFilters": [],
      "sources": [
        "site-crawl"
      ],
      "reports": [
        "internal-linking-report",
        "technical-seo-audit-report"
      ],
      "skills": [
        "linking-opportunity-review",
        "technical-health-audit"
      ],
      "verbs": [
        "internal_link_flow"
      ],
      "rungs": [
        "R1",
        "R2"
      ],
      "levers": [
        "L4"
      ],
      "questions": [
        "Which pages distribute the most internal links?",
        "Where does link equity pool?"
      ],
      "interpretation": "The supply side of internal linking: which pages are handing out links, as opposed to receiving them. Pages with many outgoing links and few incoming ones are usually hubs; the reverse pattern is usually a destination that nothing routes onward from.",
      "caveats": [
        "A passthrough of a crawler-produced column; the crawler's link-counting rules are not readable in the semantic layer.",
        "It is a count, not a weighting, it says nothing about where the links point or how prominent they are on the page.",
        "The list is capped and sorted by the INCOMING count, so it is not a ranking of the biggest link sources.",
        "A crawl is a snapshot on its own schedule."
      ],
      "freshness": "per crawl schedule, cadence is set per site; the card names the crawl it read.",
      "failureModes": [
        "Reading a high outgoing count as authority distribution without knowing the targets.",
        "Assuming the returned list is sorted by this field, it is sorted by incoming links."
      ],
      "notSameAs": [
        {
          "slug": "incoming-internal-links",
          "why": "Outgoing counts links a page gives; incoming counts links it receives. Only the incoming count drives the orphan test."
        }
      ],
      "related": [
        "incoming-internal-links",
        "crawl-depth"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "status-code-hits",
      "name": "Status-code hits",
      "aliases": [
        "Crawl errors",
        "Error responses to crawlers"
      ],
      "definition": "How many times each URL returned a given HTTP status to a crawler in the period.",
      "category": "Crawl and logs",
      "type": "raw measure",
      "unit": "log requests per URL and status",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "Sums across rows within a URL and status.",
      "grain": "One count per URL and status code.",
      "dimensions": [
        "url",
        "status_code",
        "bot_type"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "server-logs"
      ],
      "reports": [
        "ai-bot-activity-report",
        "crawl-log-report",
        "technical-seo-audit-report"
      ],
      "skills": [
        "crawl-efficiency-review",
        "technical-health-audit",
        "anomaly-investigator"
      ],
      "verbs": [
        "status_error_analysis"
      ],
      "rungs": [
        "R1"
      ],
      "levers": [
        "L1"
      ],
      "questions": [
        "What pages are erroring for Googlebot?",
        "Are we serving server errors to AI bots?"
      ],
      "caveats": [
        "The error-class filter does not match the data it is applied to. Treat an empty result from this read as a filter defect, not as evidence that nothing errored.",
        "This read is available on the internal tool surface only; it is not exposed to external callers today.",
        "The status field is a labelled band, not a numeric code: statuses are collapsed into named buckets, and unusual codes inside a class fall into an other-response bucket rather than being reported individually.",
        "The bot is a filter on this read, not a returned column, so a result cannot be split by which crawler received the status without re-running it per bot.",
        "The list is capped, so it is the top erroring URLs by volume rather than every erroring URL.",
        "Same origin-only caveat as all log reads: a status served from a CDN edge may never reach the log."
      ],
      "freshness": "hours to nightly, depends on how logs are shipped; the card carries the ingestion time.",
      "failureModes": [
        "Reading an empty result as a clean bill of health.",
        "Reading the capped list as the complete set of errors.",
        "Treating a high count on one URL as severity without checking which bot received it."
      ],
      "notSameAs": [
        {
          "slug": "indexability-flags",
          "why": "Status-code hits are what the server actually returned to a crawler; indexability flags are what the crawl graph concluded about a page. One is observed, the other is assessed."
        }
      ],
      "related": [
        "bot-hits",
        "indexability-flags",
        "crawler-response-time"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "unique-pages-crawled-by-bots",
      "name": "Unique pages crawled",
      "aliases": [
        "Unique URLs fetched by bots",
        "Pages reached by bots"
      ],
      "definition": "The number of distinct URLs a named crawler fetched in the period, counted from server logs.",
      "category": "Crawl and logs",
      "type": "raw measure",
      "unit": "distinct URLs",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "A distinct count of the language-variant-normalised full URL over the matching log records.",
      "aggregation": "A distinct count, so it is never summed across bots or buckets, the same page fetched by two bots is one page for each of them and cannot be added.",
      "grain": "One count per bot per date range, or per bot per time bucket.",
      "dimensions": [
        "bot_type",
        "date"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "server-logs"
      ],
      "reports": [
        "ai-bot-activity-report",
        "crawl-log-report",
        "internal-linking-report",
        "technical-seo-audit-report"
      ],
      "skills": [
        "ai-crawler-readiness",
        "crawl-efficiency-review",
        "technical-health-audit"
      ],
      "verbs": [
        "ai_crawler_analysis"
      ],
      "rungs": [
        "R1"
      ],
      "levers": [
        "L1"
      ],
      "questions": [
        "How much of our site are AI crawlers reaching?",
        "Is crawl coverage growing?"
      ],
      "interpretation": "The coverage half of crawl activity. Read against the hit count it separates two different situations that look alike in a total: broad shallow crawling, and heavy repeat fetching of a small set.",
      "caveats": [
        "A distinct count, so bot-level or bucket-level values cannot be added into a site total.",
        "URLs are normalised across language variants before counting, so localised versions of one page collapse together.",
        "It counts what was fetched, not what exists, it is not a share of your site unless you separately know the site's page count.",
        "Same bot-identification and CDN caveats as the hit count: user-agent matching only, and origin-served requests only."
      ],
      "freshness": "hours to nightly, depends on how logs are shipped; the card carries the ingestion time.",
      "failureModes": [
        "Summing per-bot unique-page counts.",
        "Presenting it as a percentage of the site without a denominator from the crawl."
      ],
      "notSameAs": [
        {
          "slug": "bot-hits",
          "why": "One counts requests, the other counts distinct URLs. The ratio between them is the crawl-repetition signal and neither number carries it alone."
        }
      ],
      "related": [
        "bot-hits",
        "crawler-readiness",
        "crawl-depth"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "verified-vs-spoofed-googlebot",
      "name": "Verified versus spoofed Googlebot",
      "aliases": [
        "Bot verification",
        "Googlebot IP verification"
      ],
      "definition": "How many requests claiming to be Googlebot came from an address Google publishes, and how many did not.",
      "category": "Crawl and logs",
      "type": "raw measure",
      "unit": "log requests, split by verified and unverified",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "Log records whose declared bot type is Googlebot are joined to an address lookup that flags whether the requesting address is a Google one, and counted on each side of that flag. The join is an INNER one on the requesting address, so a request whose address is absent from the lookup table is dropped from the result entirely rather than landing on the unverified side.",
      "aggregation": "Counts per verification state. The two sides do NOT add to the total of declared-Googlebot requests, anything whose address the lookup does not know is excluded by the join, so the split describes only the addresses the lookup recognises.",
      "grain": "One count per verification state per date range.",
      "dimensions": [
        "bot_type",
        "is_googlebot_ip"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "server-logs"
      ],
      "reports": [
        "ai-bot-activity-report",
        "crawl-log-report",
        "technical-seo-audit-report"
      ],
      "skills": [
        "ai-crawler-readiness",
        "technical-health-audit",
        "crawl-efficiency-review"
      ],
      "verbs": [
        "bot_verification"
      ],
      "rungs": [
        "R1"
      ],
      "levers": [
        "L1"
      ],
      "questions": [
        "Are fake Googlebots hitting us?",
        "Can we trust our crawler traffic?"
      ],
      "interpretation": "The only claim in this set that separates what a client said it was from what it demonstrably is. The split itself is the finding, a large unverified share means the crawl numbers describing that bot are worth less than they look. Read it as a floor on spoofing rather than a measurement of it: the join keeps only requests from addresses the lookup already knows, so an impostor arriving from an address nobody has catalogued never reaches either column.",
      "caveats": [
        "The two sides do not reconcile to the declared-Googlebot total. The address lookup is joined INNER, so unknown addresses are dropped rather than counted as unverified, never compute one side by subtracting the other from a hit count.",
        "For the same reason the unverified figure UNDERSTATES spoofing, and by an unknown amount: the requests most likely to be missing from an address catalogue are exactly the ones least likely to be Google.",
        "Googlebot only. The tool filters to the declared Googlebot type and joins a Google-specific address lookup; there is no equivalent verification for any answer-engine crawler.",
        "That means AI-bot figures elsewhere in this set rest on user-agent strings alone, with no address check behind them.",
        "Verification is a per-request property, so a single source can appear on both sides of the split within a period.",
        "Same origin-only caveat as all log reads."
      ],
      "freshness": "hours to nightly, depends on how logs are shipped; the card carries the ingestion time.",
      "failureModes": [
        "Treating the two counts as a partition of declared-Googlebot traffic, or deriving one from the other.",
        "Quoting the unverified count as the amount of spoofing rather than as a lower bound on it.",
        "Assuming AI crawler counts are verified the same way, they are not.",
        "Including unverified traffic in a crawl-coverage verdict."
      ],
      "notSameAs": [
        {
          "slug": "bot-hits",
          "why": "Hit counts are matched on the declared user agent alone. Only this metric establishes whether the requester was who it claimed to be, and only for Googlebot."
        }
      ],
      "related": [
        "bot-hits",
        "status-code-hits"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "cumulative-layout-shift",
      "name": "Cumulative Layout Shift",
      "aliases": [
        "CLS"
      ],
      "definition": "How much the page content moves around unexpectedly while it loads.",
      "category": "Page experience",
      "type": "score",
      "unit": "unitless layout-shift score",
      "direction": "lower-better",
      "verification": "verified",
      "calculation": "Read from the product's weighted summary measure as a raw layout-shift value. Display rounds to three decimal places; grading buckets the raw value at 0.1 and 0.25. No vital is rescaled on the way out, the timing vitals are read and shown in seconds, and this one is read and shown as its native unitless score.",
      "aggregation": "The headline is the weighted summary measure read without a page dimension; page-level values feed distributions and worst-page evidence.",
      "grain": "One number per date range, optionally split by device, or one row per page.",
      "dimensions": [
        "page",
        "device"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "lighthouse"
      ],
      "reports": [
        "core-web-vitals-report"
      ],
      "skills": [
        "cwv-regression-watch",
        "technical-health-audit"
      ],
      "verbs": [
        "site_health_cwv_check"
      ],
      "rungs": [
        "R1"
      ],
      "levers": [
        "L1"
      ],
      "questions": [
        "What is our CLS?",
        "Which pages shift while loading?"
      ],
      "interpretation": "Visual stability. Its numbers are orders of magnitude smaller than the timing vitals', which makes it the one most easily mistaken for the best of the three when they are compared naively, the weakest-vital logic exists precisely because a raw minimum across them would always pick this one.",
      "caveats": [
        "Its numeric scale is orders of magnitude below the timing vitals, so raw numeric comparison across vitals is meaningless, comparison is done on grades instead.",
        "Unitless. It carries no unit at all, where the timing vitals carry seconds, so a value quoted without its vital name is unreadable.",
        "These are lab measurements, not field data from real visitors.",
        "Collection cadence varies by site and by page."
      ],
      "freshness": "varies by site, priority URLs can run nightly; most pages far less often. The collection date rides on the card rather than being assumed.",
      "failureModes": [
        "Comparing a layout-shift value numerically against a timing vital to find the worst one."
      ],
      "notSameAs": [
        {
          "slug": "cwv-vital-grade",
          "why": "The number is a weighted average; the grade is the band. Score and verdict stay separate on every vital."
        }
      ],
      "related": [
        "largest-contentful-paint",
        "interaction-to-next-paint",
        "cwv-weakest-vital"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "interaction-to-next-paint",
      "name": "Interaction to Next Paint",
      "aliases": [
        "INP"
      ],
      "definition": "How long a page takes to respond visibly after a visitor interacts with it.",
      "category": "Page experience",
      "type": "score",
      "unit": "seconds",
      "direction": "lower-better",
      "verification": "verified",
      "calculation": "Read from the product's weighted summary measure, which is already expressed in SECONDS, the semantic layer divides the underlying millisecond measurement by a thousand before exposing it, and the product renders that value unchanged with a seconds suffix. There is no further conversion anywhere: the display projection only rounds to two decimal places, and grading is applied to the same seconds value, bucketing at 0.2 and 0.5 seconds.",
      "aggregation": "The headline is the weighted summary measure read without a page dimension; page-level values are used only for distributions and worst-page evidence.",
      "grain": "One number per date range, optionally split by device, or one row per page.",
      "dimensions": [
        "page",
        "device"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "lighthouse"
      ],
      "reports": [
        "core-web-vitals-report"
      ],
      "skills": [
        "cwv-regression-watch",
        "technical-health-audit"
      ],
      "verbs": [
        "site_health_cwv_check"
      ],
      "rungs": [
        "R1"
      ],
      "levers": [
        "L1"
      ],
      "questions": [
        "What is our INP?",
        "Are pages responsive to interaction?"
      ],
      "interpretation": "Responsiveness rather than load speed. Read it against the 0.2 and 0.5 second bands, the standard Core Web Vitals thresholds, expressed in the same seconds the value arrives in, and read the grade beside the number. The threshold VALUES are recorded in code as pending confirmation for this product specifically, this vital most of all, with a note that observed pages have tended to land in the poor band.",
      "caveats": [
        "Seconds, end to end. The value is not a Lighthouse sub-score and is not milliseconds: a reading of 0.62 is 0.62 seconds, and multiplying or dividing it by a hundred anywhere is a hundredfold error. An earlier version of this product treated the same value as an internal hundredths-of-a-second score and labelled the result milliseconds; that is the bug the current scale replaces.",
        "The grading thresholds are the standard Core Web Vitals bands and are flagged in code as pending product-specific confirmation, this vital most of all.",
        "These are lab measurements, not field data from real visitors.",
        "Collection cadence varies by site and by page.",
        "In trend mode the per-bucket values are returned ungraded, the good, needs-improvement and poor bands are not applied to a time series."
      ],
      "freshness": "varies by site, priority URLs can run nightly; most pages far less often. The collection date rides on the card rather than being assumed.",
      "failureModes": [
        "Rescaling the value before grading or quoting it, it is already in the unit the thresholds are expressed in.",
        "Reporting it in milliseconds, which invites a hundredfold slip in either direction.",
        "Reading a poor grade as a confirmed product problem when the thresholds are still pending confirmation."
      ],
      "notSameAs": [
        {
          "slug": "cwv-vital-grade",
          "why": "The number is a weighted average; the grade is the band it lands in. Score and verdict stay separate on every vital."
        }
      ],
      "related": [
        "largest-contentful-paint",
        "cumulative-layout-shift",
        "cwv-vital-grade"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "largest-contentful-paint",
      "name": "Largest Contentful Paint",
      "aliases": [
        "LCP"
      ],
      "definition": "How long it takes for the largest visible element on a page to render.",
      "category": "Page experience",
      "type": "score",
      "unit": "seconds",
      "direction": "lower-better",
      "verification": "verified",
      "calculation": "Read from the product's weighted summary measure, which is already expressed in SECONDS, the semantic layer divides the underlying millisecond measurement by a thousand before exposing it, and the product renders that value unchanged with a seconds suffix. The display projection only rounds to two decimal places; grading is applied to the same seconds value, bucketing at 2.5 and 4 seconds.",
      "aggregation": "The headline number is read from the product's own weighted summary measure with no page dimension. Averaging page-level values a second time would give every page equal weight and is the documented cause of a past mismatch against the product UI.",
      "grain": "One number per date range, optionally split by device, or one row per page.",
      "dimensions": [
        "page",
        "device"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "lighthouse"
      ],
      "reports": [
        "core-web-vitals-report"
      ],
      "skills": [
        "cwv-regression-watch",
        "technical-health-audit",
        "cross-domain-correlator"
      ],
      "verbs": [
        "site_health_cwv_check",
        "correlate_domains",
        "significance_check"
      ],
      "rungs": [
        "R1"
      ],
      "levers": [
        "L1"
      ],
      "questions": [
        "What is our LCP?",
        "Which pages are slowest to render?"
      ],
      "interpretation": "Rendering speed, in the same seconds the thresholds are written in, read it against 2.5 and 4 seconds and quote the grade beside it. It is also the field the page evidence is ranked by: the worst-pages list is the slowest-rendering pages, so this vital, not the performance score, decides which pages get looked at.",
      "caveats": [
        "Seconds, end to end. It is not a Lighthouse sub-score and not milliseconds: a reading of 5.72 is 5.72 seconds. An earlier version of this product treated the same value as an internal hundredths-of-a-second score, multiplied it by a hundred and labelled the result milliseconds, turning 5.72 seconds into 572 milliseconds, that is the bug the current scale replaces, and it is why any figure here quoted in milliseconds should be distrusted.",
        "The grading thresholds are the standard Core Web Vitals bands, and the threshold VALUES are recorded in code as pending product-specific confirmation.",
        "These are lab measurements, not field data from real visitors.",
        "Collection cadence varies by site and by page, so a vital measured three weeks ago is reported as three weeks old rather than as current.",
        "When results are split by device the page rows become page-by-device observations, so a worst-page figure is a single device's measurement and can sit well above the device-blended value the product UI shows for the same page and window."
      ],
      "freshness": "varies by site, priority URLs can run nightly; most pages far less often. The collection date rides on the card rather than being assumed.",
      "failureModes": [
        "Treating the value as a zero-to-one Lighthouse sub-score, or rescaling it by a hundred in either direction.",
        "Quoting a device-split worst-page figure as that page's blended value.",
        "Averaging page-level values to produce a site headline."
      ],
      "notSameAs": [
        {
          "slug": "cwv-vital-grade",
          "why": "One is a numeric average, the other is the graded bucket that average falls into. Score and verdict are kept separate on every vital."
        },
        {
          "slug": "crawler-response-time",
          "why": "Server response latency to a crawler is not page-render speed for a visitor. Different measurements from different sources, and neither predicts its counterpart.",
          "mirroredFrom": "crawler-response-time"
        }
      ],
      "related": [
        "interaction-to-next-paint",
        "cumulative-layout-shift",
        "performance-score",
        "cwv-vital-grade"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "lighthouse-category-scores",
      "name": "Lighthouse category scores",
      "aliases": [
        "Non-CWV Lighthouse scores",
        "SEO and accessibility scores"
      ],
      "definition": "The eight further Lighthouse figures collected alongside the Core Web Vitals: SEO, accessibility, best practices, Time to Interactive, Total Blocking Time, First Contentful Paint, Speed Index, and the mobile score.",
      "category": "Page experience",
      "type": "score",
      "unit": "two scales: SEO, accessibility, best practices and the mobile score are 0-to-1 score fractions; Time to Interactive, Total Blocking Time, First Contentful Paint and Speed Index are seconds",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "Each figure is read straight from its own summary measure over the pages in scope, with no derivation on top. The four score-type figures arrive as fractions between nought and one and carry an explicit display contract: multiply by a hundred and round to a whole score point, presented without a percent sign, so 0.925 is shown as 93. The four timing figures arrive in seconds. None of the eight is graded.",
      "aggregation": "Seven of the eight are plain averages of their per-row values across the pages in scope. The mobile score is the exception: it is impression-weighted in the semantic layer, dividing the sum of score times impressions by the sum of impressions.",
      "grain": "One number per figure per date range.",
      "dimensions": [
        "device"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "lighthouse"
      ],
      "reports": [
        "core-web-vitals-report"
      ],
      "skills": [
        "technical-health-audit"
      ],
      "verbs": [
        "site_health_cwv_check"
      ],
      "rungs": [
        "R1"
      ],
      "levers": [
        "L1"
      ],
      "questions": [
        "What is our accessibility score?",
        "How does our SEO audit score look?"
      ],
      "interpretation": "The wider audit that sits beside page experience without being part of it. None of the eight is graded and none feeds the page-experience verdict, so they are context for a conversation rather than inputs to one, and because the set spans two scales, a figure quoted without naming which of the eight it is cannot be read at all.",
      "caveats": [
        "Returned as raw averages and deliberately NOT graded. There is no good, needs-improvement or poor band for any of the eight; assigning one invents a threshold the product does not have.",
        "Two scales in one set. Four are score fractions between nought and one, four are seconds, they are never comparable to each other as numbers.",
        "The score-type figures must be shown as whole score points, not as percentages: the raw fraction is multiplied by a hundred and rounded, with no percent sign. Rendering 0.93 as 0.93% or as 93% are both wrong.",
        "Opt-in: they are only fetched when explicitly requested, and are absent from a default page-experience read.",
        "The mobile score is aggregated differently from the other seven, impression-weighted rather than a plain average, so the set is internally inconsistent in how it rolls up.",
        "First Contentful Paint's direction is still contested between the two shared oracles: one reads a rise as a regression, the other as an improvement. Do not paint a movement in it green or red.",
        "These are lab measurements, not field data from real visitors; collection cadence varies by site and by page."
      ],
      "freshness": "varies by site, priority URLs can run nightly; most pages far less often. The collection date rides on the card rather than being assumed.",
      "failureModes": [
        "Grading these against Core Web Vitals bands, or presenting one as good or poor.",
        "Rendering a score fraction as a decimal percentage instead of a whole score point.",
        "Comparing the mobile score against the other seven as if aggregated the same way, or comparing a score against a timing figure.",
        "Treating a movement in one of these as a Core Web Vitals regression."
      ],
      "notSameAs": [
        {
          "slug": "performance-score",
          "why": "The performance score is graded and drives the overall verdict; these eight are ungraded and drive nothing. The performance score also shares the 0-to-1 scale of four of them, which is exactly why the two are confused."
        },
        {
          "slug": "cwv-vital-grade",
          "why": "There is no grade for any of these eight. Presenting one as good or poor invents a band the product does not have."
        }
      ],
      "related": [
        "performance-score",
        "largest-contentful-paint"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "cwv-overall-verdict",
      "name": "Overall page-experience verdict",
      "aliases": [
        "Overall CWV grade"
      ],
      "definition": "A single good, needs improvement or poor verdict presented for page experience as a whole.",
      "category": "Page experience",
      "type": "derived metric",
      "unit": "one of good, needs-improvement, poor",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "Set to the grade of the performance vital, and nothing else. In code the overall field is assigned directly from the performance vital's bucket, both in the base scoring pass and again after the summary values replace the page-derived ones.",
      "aggregation": "Not an aggregation across vitals. Rendering time, responsiveness and layout shift do not enter it at all.",
      "grain": "One verdict per date range, optionally one per device.",
      "dimensions": [
        "device"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "lighthouse"
      ],
      "reports": [
        "core-web-vitals-report"
      ],
      "skills": [
        "cwv-regression-watch",
        "technical-health-audit"
      ],
      "verbs": [
        "site_health_cwv_check"
      ],
      "rungs": [
        "R1"
      ],
      "levers": [
        "L1"
      ],
      "questions": [
        "Is our page experience healthy?",
        "What is our overall Core Web Vitals grade?"
      ],
      "interpretation": "Read it as the performance vital's grade under a broader name, because that is what it is. A site can be graded good overall while failing responsiveness or layout shift outright, so the per-vital grades belong beside it whenever the verdict is quoted.",
      "caveats": [
        "The name says overall; the derivation uses the performance vital alone. Rendering time, responsiveness and layout shift are graded separately and are excluded from this verdict.",
        "That makes a good overall verdict compatible with a failing Core Web Vital, which is the opposite of what the label suggests.",
        "Never present this as a Core Web Vitals pass or fail, pair it with the per-vital grades.",
        "It inherits the performance vital's caveats, including that vital's own snapshot rule: the verdict follows the latest day on which the product's four score families were all populated, so it can be anchored to a different day from the three Core Web Vitals sitting beside it, which stay on period aggregates.",
        "It inherits the rest too: lab measurement, varying collection cadence, thresholds pending product-specific confirmation."
      ],
      "freshness": "varies by site, priority URLs can run nightly; most pages far less often. The collection date rides on the card rather than being assumed.",
      "failureModes": [
        "Quoting the overall verdict as a Core Web Vitals summary and missing a failing vital underneath it.",
        "Reporting an improvement in the overall verdict when only the performance score moved."
      ],
      "notSameAs": [
        {
          "slug": "performance-score",
          "why": "Score versus verdict: one is the numeric average, the other is its band. They are the same underlying vital, which is precisely why the verdict must not be read as covering the others."
        },
        {
          "slug": "cwv-vital-grade",
          "why": "The per-vital grade covers whichever vital it names; the overall verdict covers performance only despite its name."
        }
      ],
      "related": [
        "performance-score",
        "cwv-vital-grade",
        "cwv-weakest-vital"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "performance-score",
      "name": "Performance score",
      "aliases": [
        "Lighthouse performance score"
      ],
      "definition": "The Lighthouse performance score for your pages, averaged across the pages in scope.",
      "category": "Page experience",
      "type": "score",
      "unit": "score between 0 and 1",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "Read from the product's weighted summary measure, which averages the per-page weighted performance score. Unlike the three Core Web Vitals, the headline prefers the product's own latest-daily snapshot, the most recent day on which its four score families were all populated, and falls back to the period summary when no such day exists. Display rounds to three decimal places; grading buckets at 0.9 and 0.5, with the comparison reversed because higher is better here.",
      "aggregation": "The headline is the weighted summary measure read without a page dimension, or the latest fully populated daily value where one exists. Averaging page-level values again would give every page equal weight.",
      "grain": "One number per date range, optionally split by device, or one row per page.",
      "dimensions": [
        "page",
        "device"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "lighthouse"
      ],
      "reports": [
        "core-web-vitals-report"
      ],
      "skills": [
        "cwv-regression-watch",
        "technical-health-audit"
      ],
      "verbs": [
        "site_health_cwv_check"
      ],
      "rungs": [
        "R1"
      ],
      "levers": [
        "L1"
      ],
      "questions": [
        "What is our performance score?",
        "Which pages score worst on performance?"
      ],
      "interpretation": "The one figure in this set on a true zero-to-one Lighthouse scale, and, on its own, the input to the overall page-experience verdict, which is worth knowing before quoting that verdict. It is NOT what the worst-pages list is ranked by; that ranking is by slowest rendering time.",
      "caveats": [
        "Stored zero to one, not zero to a hundred. A score of 0.62 is presented as 62, multiplied by a hundred and rounded to a whole score point, without a percent sign.",
        "It sits on a different scale from the timing vitals, which are in seconds, so the four page-experience numbers can never be compared to each other as numbers.",
        "Its headline can be anchored to a different day from the other three vitals: it prefers the latest day on which the product's four score families were all populated, while they stay on period aggregates.",
        "The overall page-experience verdict is derived from this vital alone.",
        "These are lab measurements, not field data from real visitors; collection cadence varies by site and by page."
      ],
      "freshness": "varies by site, priority URLs can run nightly; most pages far less often. The collection date rides on the card rather than being assumed.",
      "failureModes": [
        "Comparing a zero-to-one score against a seconds-based vital as if they shared a scale.",
        "Rendering it as a decimal percentage rather than a whole score point.",
        "Assuming the worst-pages list is ranked by this score, it is ranked by rendering time.",
        "Quoting the overall verdict without knowing it comes from this vital only."
      ],
      "notSameAs": [
        {
          "slug": "cwv-overall-verdict",
          "why": "One is a numeric average, the other is the graded bucket presented as a site-wide verdict. Score and verdict are kept separate, and in this case the verdict is derived from this score alone."
        },
        {
          "slug": "lighthouse-category-scores",
          "why": "The performance score is graded and drives the overall verdict; those eight are ungraded and drive nothing. The performance score also shares the 0-to-1 scale of four of them, which is exactly why the two are confused.",
          "mirroredFrom": "lighthouse-category-scores"
        }
      ],
      "related": [
        "cwv-overall-verdict",
        "cwv-vital-grade",
        "lighthouse-category-scores"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "cwv-vital-grade",
      "name": "Vital grade",
      "aliases": [
        "Per-vital grade",
        "Vital bucket"
      ],
      "definition": "The band a single page-experience vital falls into: good, needs improvement, or poor.",
      "category": "Page experience",
      "type": "derived metric",
      "unit": "one of good, needs-improvement, poor",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "Computed in our own code, not in the semantic layer, and applied to the RAW value as it arrives rather than to a rescaled one, there is no conversion step anywhere in the grading function. The bands are the standard Core Web Vitals ones, expressed in the units the values already carry: rendering at 2.5 and 4 seconds, responsiveness at 0.2 and 0.5 seconds, layout shift at 0.1 and 0.25, and performance at 0.9 and 0.5 with the comparison reversed because higher is better there.",
      "aggregation": "Applied to a single value, either the weighted headline average for the site grade, or a single page's value for a per-page grade. Grades are never averaged.",
      "grain": "One grade per vital per date range, optionally per device, or one grade per vital per page in the scorecard.",
      "dimensions": [
        "page",
        "device"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "lighthouse"
      ],
      "reports": [
        "core-web-vitals-report"
      ],
      "skills": [
        "cwv-regression-watch",
        "technical-health-audit"
      ],
      "verbs": [
        "site_health_cwv_check"
      ],
      "rungs": [
        "R1"
      ],
      "levers": [
        "L1"
      ],
      "questions": [
        "Is our LCP good or poor?",
        "Which vitals are failing?"
      ],
      "interpretation": "The band, not the number. It exists because the four vitals sit on three different scales, seconds, a unitless shift score, and a zero-to-one score, and cannot be compared numerically. Grading is the only common currency between them. Quote the grade beside the value, never instead of it.",
      "caveats": [
        "No rescaling happens at grading time. A band and the value it is applied to are always in the same unit, so a grade computed against a converted figure is wrong by whatever the conversion was.",
        "The threshold values are recorded in code as pending product-specific confirmation, responsiveness most of all, with a note that observed pages have tended to land in the poor band.",
        "The grade for the site is computed from the weighted headline average, so it is not the same as the most common per-page grade.",
        "A null value produces no grade rather than a poor grade.",
        "Trend mode returns ungraded per-bucket values, grading is not applied to a time series."
      ],
      "freshness": "varies by site, priority URLs can run nightly; most pages far less often. The collection date rides on the card rather than being assumed.",
      "failureModes": [
        "Restating a band in a unit the value is not in, the rendering and responsiveness bands are seconds, not milliseconds.",
        "Reading a site-level grade as a statement about most pages.",
        "Averaging grades, or treating an absent grade as a failure."
      ],
      "notSameAs": [
        {
          "slug": "largest-contentful-paint",
          "why": "Score versus verdict: the vital is a numeric average, the grade is the band it lands in. The two are kept as separate fields on every vital and neither substitutes for the other."
        },
        {
          "slug": "cwv-grade-distribution",
          "why": "This is one grade for one value; the distribution is the count of pages in each band. A good headline grade is compatible with a large poor bucket."
        },
        {
          "slug": "interaction-to-next-paint",
          "why": "The number is a weighted average; the grade is the band it lands in. Score and verdict stay separate on every vital.",
          "mirroredFrom": "interaction-to-next-paint"
        },
        {
          "slug": "cumulative-layout-shift",
          "why": "The number is a weighted average; the grade is the band. Score and verdict stay separate on every vital.",
          "mirroredFrom": "cumulative-layout-shift"
        },
        {
          "slug": "cwv-overall-verdict",
          "why": "The per-vital grade covers whichever vital it names; the overall verdict covers performance only despite its name.",
          "mirroredFrom": "cwv-overall-verdict"
        },
        {
          "slug": "cwv-weakest-vital",
          "why": "The grade tells you which band a named vital is in; the weakest vital tells you which vital sits in the worst band on a page. A value versus a selection.",
          "mirroredFrom": "cwv-weakest-vital"
        },
        {
          "slug": "lighthouse-category-scores",
          "why": "There is no grade for any of these eight. Presenting one as good or poor invents a band the product does not have.",
          "mirroredFrom": "lighthouse-category-scores"
        }
      ],
      "related": [
        "cwv-grade-distribution",
        "cwv-overall-verdict",
        "cwv-weakest-vital",
        "largest-contentful-paint"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "cwv-grade-distribution",
      "name": "Vital grade distribution",
      "aliases": [
        "Grade spread",
        "Pages by band"
      ],
      "definition": "How many of your pages fall into each grade band for a given vital.",
      "category": "Page experience",
      "type": "derived metric",
      "unit": "page counts per band",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "Every page row's raw value for the vital is graded individually and tallied into the three bands. Rows with a non-numeric value are excluded from the tally rather than counted as poor.",
      "aggregation": "Counts of pages, not of measurements. The three counts add to the number of pages with a numeric value for that vital, which can be fewer than the total page count.",
      "grain": "Three counts per vital per date range, optionally per device.",
      "dimensions": [
        "page",
        "device"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "lighthouse"
      ],
      "reports": [
        "core-web-vitals-report"
      ],
      "skills": [
        "cwv-regression-watch",
        "technical-health-audit"
      ],
      "verbs": [
        "site_health_cwv_check"
      ],
      "rungs": [
        "R1"
      ],
      "levers": [
        "L1"
      ],
      "questions": [
        "How many pages fail LCP?",
        "Is the problem site-wide or a handful of pages?"
      ],
      "interpretation": "The shape behind the headline. A good weighted average with a heavy poor bucket is a template problem on a minority of pages; a middling average with everything bunched in the middle band is a site-wide one. The two call for different work, and only the distribution tells them apart.",
      "caveats": [
        "The page rows are capped, so the distribution describes the pages that were read, not every page on the site. A response that lands exactly on the cap says so, and must not then be described as covering the whole site.",
        "The distribution is built from per-page values while the headline grade is built from the product's summary measure, the two can disagree, and that disagreement is informative rather than a defect.",
        "With results split by device the rows are page-by-device observations rather than pages, so the band counts count measurements, not pages.",
        "Pages without a numeric value for a vital are excluded from its tally, so the three bands can sum to different totals across vitals.",
        "Collection cadence varies by page, so a distribution mixes measurements taken at different times."
      ],
      "freshness": "varies by site, priority URLs can run nightly; most pages far less often. The collection date rides on the card rather than being assumed.",
      "failureModes": [
        "Reading the band counts as a share of all site pages.",
        "Expecting the distribution's modal band to match the headline grade."
      ],
      "notSameAs": [
        {
          "slug": "cwv-vital-grade",
          "why": "One grade describes one value; the distribution describes how the pages spread across bands. A site graded good can still have a large poor bucket."
        }
      ],
      "related": [
        "cwv-vital-grade",
        "cwv-weakest-vital"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "cwv-weakest-vital",
      "name": "Weakest vital",
      "aliases": [
        "Worst vital per page"
      ],
      "definition": "For each of the slowest-rendering pages, which of the three Core Web Vitals is graded worst.",
      "category": "Page experience",
      "type": "derived metric",
      "unit": "the name of one vital, or none when no vital has a value",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "Among rendering time, layout shift and responsiveness, each vital with a numeric value on the page is graded and the worst grade wins, with ties resolved by the order the vitals are checked. Deliberately chosen by GRADE severity, not by the smallest number, because the three vitals sit on scales orders of magnitude apart and a raw minimum would always pick layout shift.",
      "aggregation": "Computed per page, on the up-to-ten SLOWEST-RENDERING pages. The page rows are read sorted by descending rendering time, rows with no rendering time are dropped before the ranking, and the top ten of what remains are kept.",
      "grain": "One vital name per listed page.",
      "dimensions": [
        "page"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "lighthouse"
      ],
      "reports": [
        "core-web-vitals-report"
      ],
      "skills": [
        "cwv-regression-watch",
        "technical-health-audit"
      ],
      "verbs": [
        "site_health_cwv_check"
      ],
      "rungs": [
        "R1"
      ],
      "levers": [
        "L1"
      ],
      "questions": [
        "What is the biggest page-experience problem on this page?",
        "Where should engineering start?"
      ],
      "interpretation": "The routing hint on a fix list: it names which vital to open first on a given page. It answers what is worst, not how bad, pair it with that vital's own value and grade before scoping any work. And because the list of pages was chosen on rendering time, it is a fix list for slow pages, not a survey of where the site's page-experience problems are.",
      "caveats": [
        "The selection and the verdict use different vitals. Which PAGES are considered is decided by rendering time alone, the slowest ten, while which VITAL is named on each of them is decided by grade severity across all three. A page whose only failing vital is layout shift or responsiveness will not appear at all unless its rendering time is also among the worst.",
        "The performance score is excluded from the candidates; only the three Core Web Vitals are considered. It does not decide the page ranking either, despite being the score the page-experience verdict is built from.",
        "A page with no rendering time is dropped before the ranking, so absence from the list is not evidence of health.",
        "Ties are broken by check order rather than by magnitude, so two vitals in the same band will always resolve the same way.",
        "It reports severity band, not distance from the threshold: a page barely over the line and one far past it both read the same.",
        "With results split by device the entries are page-by-device observations, so an entry names the worst vital for one device's measurement of that page, not for the page overall."
      ],
      "freshness": "varies by site, priority URLs can run nightly; most pages far less often. The collection date rides on the card rather than being assumed.",
      "failureModes": [
        "Describing the list as the worst-scoring pages, it is the slowest-rendering pages.",
        "Reading the named vital as the largest opportunity rather than the worst band.",
        "Assuming a page absent from the list is healthy when it may simply have no rendering measurement."
      ],
      "notSameAs": [
        {
          "slug": "cwv-vital-grade",
          "why": "The grade tells you which band a named vital is in; the weakest vital tells you which vital is in the worst band on a page. One is a value, the other is a selection."
        }
      ],
      "related": [
        "cwv-vital-grade",
        "cwv-grade-distribution",
        "largest-contentful-paint"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "paid-organic-keyword-overlap",
      "name": "Paid and organic keyword overlap",
      "aliases": [
        "Overlap count",
        "Paid and organic keyword intersection"
      ],
      "definition": "How many keywords you both bid on in Google Ads and already rank for in organic search over the same period.",
      "category": "Paid and organic",
      "type": "derived metric",
      "unit": "keywords",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "Three governed reads, then a join. The paid keyword set with its cost, clicks and conversions is read whole-domain and capped at five thousand rows by cost. The organic click set is read separately at keyword grain and capped at five thousand rows by clicks. The paid-cost-ranked intersection of those two is cut to the requested row cap, and only those keywords get a third read for impression-weighted average position, deliberately from a different dataset than the clicks came from, so the position formula is the parity one. The frames are joined on the exact keyword string in the compute engine; the overlap count is the number of joined rows, and the response also reports how many keywords each side contributed.",
      "numerator": "Keywords present in both the paid and the organic result sets",
      "denominator": "Reported alongside as the paid keyword count and the organic keyword count, never collapsed into a single ratio",
      "aggregation": "A count of joined rows. Each side is capped before the join, so the count is a bounded sample of the overlap, not a census.",
      "grain": "One count per date range, plus one row per overlapping keyword ranked by paid cost.",
      "dimensions": [
        "keyword"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "google-ads",
        "search-console"
      ],
      "reports": [
        "paid-organic-overlap-report"
      ],
      "skills": [
        "paid-organic-balance"
      ],
      "verbs": [
        "paid_organic_overlap"
      ],
      "rungs": [
        "R5",
        "R2"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "Are we paying for keywords we already rank for?",
        "Which terms do we buy and earn at the same time?"
      ],
      "interpretation": "The size of the surface where paid and organic meet. It is the input to a spend conversation, not the answer to one: overlap says the two channels touch the same demand, and nothing about whether either is redundant.",
      "caveats": [
        "The join is on the exact keyword string. Match-type differences, casing and near-variants will under-count the true overlap.",
        "The paid side is the search term that triggered the ad, not the bidded keyword, the two are separate fields.",
        "Both sides are capped at five thousand keywords before joining and the overlap is returned ranked by paid cost, so the count reflects the top of each list rather than the whole tail.",
        "Organic clicks and organic average position come from two different reads on two different datasets, and the position read covers only the paid-cost-ranked overlap candidates up to the row cap. A keyword outside that cap joins with no position at all.",
        "Whole-domain only.",
        "Slowest contributing source is Google Search Console, so the freshness shown is the organic side's.",
        "The result is stamped observational in the payload itself."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Reading overlap as wasted spend.",
        "Comparing overlap counts between periods where the caps bound different fractions of each list."
      ],
      "notSameAs": [
        {
          "slug": "paying-for-owned-term",
          "why": "The overlap count is every keyword present on both sides; the owned-term flag is the subset of those that also clear an organic rank threshold. One is a set size, the other is a filtered condition on its rows."
        }
      ],
      "related": [
        "paying-for-owned-term",
        "total-search-share",
        "paid-clicks"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "paying-for-owned-term",
      "name": "Paying for an owned term",
      "aliases": [
        "Wasted-spend candidate",
        "Paid on owned keyword"
      ],
      "definition": "A per-keyword flag marking an overlapping keyword whose organic average position is already at or better than the chosen rank threshold.",
      "category": "Paid and organic",
      "type": "derived metric",
      "unit": "flag per keyword, plus a count of flagged keywords",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "For each keyword in the paid-and-organic join, the flag is true when the organic average position is a positive number at or better than the rank threshold, which defaults to the top three. The response also carries the count of flagged keywords.",
      "aggregation": "A per-row boolean and its count. It is analysis on top of the joined frames, computed in the tool rather than defined in the semantic layer, and it is labelled as such.",
      "grain": "One flag per overlapping keyword.",
      "dimensions": [
        "keyword"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "google-ads",
        "search-console"
      ],
      "reports": [
        "paid-organic-overlap-report"
      ],
      "skills": [
        "paid-organic-balance"
      ],
      "verbs": [
        "paid_organic_overlap"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "Which keywords are we buying that we already rank top-3 for?",
        "Where might paid spend be redundant?"
      ],
      "interpretation": "A candidate list, not a verdict. The tool ships its own caveat with the number: paying for a term you rank for does not prove the paid click would have arrived for free, and only a controlled pause test can settle that. The right output of this metric is a test design with day-7, day-14 and day-30 readouts.",
      "caveats": [
        "Overlap is not cannibalization, the payload states this in its own caveat field.",
        "The threshold is a caller-chosen parameter defaulting to the top three, so the flagged count moves with the parameter and is not comparable across calls that used different thresholds.",
        "Organic position is an impression-weighted average over the period, so a keyword that ranked well for part of the period can clear the threshold.",
        "The position lookup runs only for the paid-cost-ranked overlap candidates up to the row cap, so a keyword below that cut can never be flagged however well it ranks.",
        "A rank threshold says nothing about whether the paid and organic results appeared on the same result pages.",
        "Slowest contributing source is Google Search Console."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Pausing spend on the flagged list without a holdout and reading the resulting organic traffic as recovered clicks.",
        "Comparing flagged counts across periods that used different thresholds."
      ],
      "notSameAs": [
        {
          "slug": "paid-organic-keyword-overlap",
          "why": "Overlap is the whole intersection; this flag is the rank-qualified subset of it. Reporting the flagged count as the overlap overstates the spend at issue."
        }
      ],
      "related": [
        "paid-organic-keyword-overlap",
        "paid-ad-cost"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "total-search-share",
      "name": "Total search share",
      "aliases": [
        "Combined paid and organic share",
        "Total SERP share"
      ],
      "definition": "A single estimate of how much of a segment's results-page presence you hold once paid and organic are combined.",
      "category": "Paid and organic",
      "type": "derived metric",
      "unit": "percent of the segment's results-page presence (estimate)",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "Both legs are first normalised to a fraction between 0 and 1 using the shared unit contract, CTR-modeled search market share is stored 0 to 100 and divided by a hundred, paid impression share is already a fraction and is left alone. The two are then combined as a complement union: one minus the product of the two complements, times a hundred. Written out on the two fractions: `CASE WHEN organic IS NULL AND paid IS NULL THEN NULL ELSE (1 - (1 - COALESCE(organic,0)) * (1 - COALESCE(paid,0))) * 100 END`. A single missing leg is coalesced to zero presence; only when BOTH legs are missing is the result null rather than zero.",
      "numerator": "The combined presence probability from the two legs",
      "denominator": "One, by construction, the complement union is bounded at 100%",
      "aggregation": "Computed once over a single already-aggregated row. It is not summable, averageable, or decomposable back into its legs.",
      "grain": "One number per segment, medium and date range.",
      "dimensions": [
        "segment",
        "source_medium"
      ],
      "requiredFilters": [
        "segment_id",
        "date_range"
      ],
      "sources": [
        "google-ads",
        "search-console",
        "rank-tracking"
      ],
      "reports": [
        "paid-organic-overlap-report"
      ],
      "skills": [
        "paid-organic-balance",
        "monthly-exec-review"
      ],
      "verbs": [
        "total_search_share"
      ],
      "rungs": [
        "R2",
        "R5"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "What is our total share of the search results page?",
        "How much of search do we own once paid is counted?"
      ],
      "interpretation": "A labelled estimate of combined presence, useful for direction and for leadership framing, and not a measured share of the page. The complement union assumes the two presences are independent; on the same query they are not, so the estimate leans high where paid and organic compete for the same result pages. Present it as an estimate every time.",
      "caveats": [
        "Results-page geometry is approximated: paid and organic occupy different real estate, so this is not a measured share of the page. The tool carries this caveat in its own payload.",
        "The independence assumption is stated and known to be wrong on the same query, that is the estimate's main source of overstatement.",
        "The two legs live on different scales and are normalised by name before being combined; an earlier version divided both by a hundred and erased the paid leg roughly a hundredfold.",
        "If the client row cannot be identified in the segment's competitor mapping, the organic leg is unavailable and the total reflects paid presence only, the response says so.",
        "Search market share is always CTR-modeled search market share of tracked demand, directional and scoped to a tracked segment.",
        "Slowest contributing source is Google Search Console.",
        "The combined total and both legs ship in one payload under camel-case keys. The shared format contract classifies by name and its word-boundary rules do not fire across camel case, so all three fall through to the plain-count family: no percent sign, no scale correction, and the 0 to 100 organic leg and the 0 to 1 paid leg are indistinguishable to any consumer that formats by name."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Presenting the number as a measured share of the results page.",
        "Subtracting one leg from the total to recover the other, the union is not additive.",
        "Reading a paid-only total as a combined total when the client row was unresolved."
      ],
      "notSameAs": [
        {
          "slug": "search-impression-share",
          "why": "Impression share is paid auction coverage on its own scale; total search share is a combined estimate that includes the organic leg and is bounded differently."
        },
        {
          "slug": "total-search-share-organic-leg",
          "why": "The organic leg is one input to the combination, on its own 0 to 100 scale; the total is the union of both legs and cannot be decomposed back into them."
        }
      ],
      "related": [
        "total-search-share-organic-leg",
        "total-search-share-paid-leg",
        "search-impression-share"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "total-search-share-organic-leg",
      "name": "Total search share, organic leg",
      "aliases": [
        "Organic search market share input"
      ],
      "definition": "The CTR-modeled search market share of tracked demand that total search share uses as its organic input.",
      "category": "Paid and organic",
      "type": "share",
      "unit": "percent of tracked demand (stored 0 to 100)",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "Read from the market-share competitor column that the segment's competitor mapping resolves to your own domain, filtered to the segment, the medium, the date range and your canonical site URL. If the client row cannot be resolved, the leg is null and the response says so.",
      "aggregation": "A single-row read for the segment; not summed across segments.",
      "grain": "One number per segment, medium and date range.",
      "dimensions": [
        "segment",
        "source_medium"
      ],
      "requiredFilters": [
        "segment_id",
        "date_range"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "paid-organic-overlap-report"
      ],
      "skills": [
        "paid-organic-balance",
        "market-share-review"
      ],
      "verbs": [
        "total_search_share"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "What is the organic half of our total search share?"
      ],
      "interpretation": "Your organic standing inside a tracked segment, expressed on a 0 to 100 scale, before the paid leg is folded in. It is directional: absolute share levels are approximations by construction, and the gap to the leader is the more reliable read than the level itself.",
      "caveats": [
        "Always CTR-modeled search market share of tracked demand, directional, scoped to the keywords in a tracked segment, and never revenue share.",
        "Stored 0 to 100 while the paid leg is stored 0 to 1; the two are normalised by name before being combined.",
        "Requires a competitor mapping that identifies your own row for the segment and medium; without it the leg is null.",
        "A segment that does not track a competitor cannot see them, so absence from the standings means untracked, not absent.",
        "It ships beside the paid leg under a camel-case payload key the shared format contract cannot classify, so it renders as a bare number with no percent sign and no scale correction."
      ],
      "freshness": "~1 day behind, daily observation, available the following day.",
      "failureModes": [
        "Comparing this leg directly against paid impression share without normalising the scales.",
        "Reading an unresolved client row as zero share."
      ],
      "notSameAs": [
        {
          "slug": "total-search-share-paid-leg",
          "why": "The organic leg is a modelled share of tracked demand on a 0 to 100 scale; the paid leg is auction impression share on a 0 to 1 scale. They are not comparable until normalised."
        },
        {
          "slug": "total-search-share",
          "why": "The organic leg is one input to the combination, on its own 0 to 100 scale; the total is the union of both legs and cannot be decomposed back into them.",
          "mirroredFrom": "total-search-share"
        }
      ],
      "related": [
        "total-search-share",
        "total-search-share-paid-leg"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "total-search-share-paid-leg",
      "name": "Total search share, paid leg",
      "aliases": [
        "Paid presence input"
      ],
      "definition": "The segment-scoped search impression share that total search share uses as its paid input.",
      "category": "Paid and organic",
      "type": "share",
      "unit": "share of available auction impressions (stored 0 to 1)",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "A single-row read of the averaged search impression share measure on the keyword-grain impression-share dataset, filtered to the segment, the date range and your canonical site URL. It is the same measure the impression-share tool returns, read here without a breakdown.",
      "aggregation": "An unweighted average across keyword-day rows, read as one row for the segment.",
      "grain": "One number per segment and date range.",
      "dimensions": [
        "segment"
      ],
      "requiredFilters": [
        "segment_id",
        "date_range"
      ],
      "sources": [
        "google-ads"
      ],
      "reports": [
        "paid-organic-overlap-report"
      ],
      "skills": [
        "paid-organic-balance"
      ],
      "verbs": [
        "total_search_share"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "What is the paid half of our total search share?"
      ],
      "interpretation": "Auction coverage used as a stand-in for paid presence on the results page. It measures eligibility and exposure inside the ad auction, which is a narrower thing than occupying the page, part of why the combined total is labelled an estimate.",
      "caveats": [
        "Impression share is auction coverage, not page occupancy; using it as a presence probability is the approximation the combined total is labelled for.",
        "Stored as a fraction between 0 and 1 while the organic leg is stored 0 to 100.",
        "Unweighted average across keyword-day rows.",
        "Impression share lost to budget is not measured on this dataset. The budget-lost measures exist only on a campaign-grain dataset that no tool reads, so a budget-capped account looks smaller here without the reason being visible.",
        "It ships beside the organic leg under a camel-case payload key the shared format contract cannot classify, so it renders as a bare 0 to 1 number with no percent sign."
      ],
      "freshness": "~1 day behind, Ads reporting settles overnight; same-day spend is provisional.",
      "failureModes": [
        "Treating auction impression share as share of the results page.",
        "Comparing it directly to the organic leg without normalising."
      ],
      "notSameAs": [
        {
          "slug": "total-search-share-organic-leg",
          "why": "Different scales, different denominators: one is a modelled share of tracked demand, the other is a share of available auction impressions."
        }
      ],
      "related": [
        "total-search-share",
        "search-impression-share",
        "impression-share-lost-to-rank"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "absolute-top-impression-share",
      "name": "Absolute top impression share",
      "aliases": [
        "Abs top IS"
      ],
      "definition": "The share of available auction impressions where your ad occupied the very first ad slot.",
      "category": "Paid search",
      "type": "share",
      "unit": "share of available auction impressions (stored 0 to 1, shown as a percent)",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "The average of Google Ads' own per-row search absolute top impression share across the rows in scope.",
      "aggregation": "An unweighted average across keyword-day rows.",
      "grain": "One number per segment and date range, or one row per keyword or campaign.",
      "dimensions": [
        "keyword",
        "campaign_name"
      ],
      "requiredFilters": [
        "segment_id",
        "date_range"
      ],
      "sources": [
        "google-ads"
      ],
      "reports": [
        "paid-search-performance-report"
      ],
      "skills": [
        "paid-efficiency-review"
      ],
      "verbs": [
        "paid_impression_share"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "How often are we in the first ad slot?"
      ],
      "interpretation": "The narrowest and most competitive slice of auction coverage. Movement here responds to bid and ad-rank changes faster than the overall share does.",
      "caveats": [
        "Always per segment; called without one the verb returns the segment list.",
        "Unweighted average across rows.",
        "Stored as a fraction between 0 and 1."
      ],
      "freshness": "~1 day behind, Ads reporting settles overnight; same-day spend is provisional.",
      "failureModes": [
        "Comparing absolute top share to top share as if the difference were a loss reason, the reason columns are the rank-lost measures."
      ],
      "notSameAs": [
        {
          "slug": "top-impression-share",
          "why": "Absolute top is the first ad slot only; top is anywhere above the organic results."
        },
        {
          "slug": "absolute-top-impression-share-lost-to-rank",
          "why": "Absolute top impression share is the first-slot placement you won; the rank-lost measure is the first-slot placement you lost on rank. Separate averaged columns, not complements.",
          "mirroredFrom": "absolute-top-impression-share-lost-to-rank"
        }
      ],
      "related": [
        "search-impression-share",
        "top-impression-share",
        "absolute-top-impression-share-lost-to-rank"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "absolute-top-impression-share-lost-to-rank",
      "name": "Absolute top impression share lost to rank",
      "aliases": [
        "Rank-lost absolute top IS"
      ],
      "definition": "The share of available auction impressions in the first ad slot that you did not receive because your ad rank was too low.",
      "category": "Paid search",
      "type": "share",
      "unit": "share of available auction impressions (stored 0 to 1, shown as a percent)",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "An unweighted average across keyword-day rows.",
      "grain": "One number per segment and date range, or one row per keyword or campaign.",
      "dimensions": [
        "keyword",
        "campaign_name"
      ],
      "requiredFilters": [
        "segment_id",
        "date_range"
      ],
      "sources": [
        "google-ads"
      ],
      "reports": [],
      "skills": [
        "paid-efficiency-review"
      ],
      "verbs": [
        "paid_impression_share"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "Are we losing the first ad slot to rank?"
      ],
      "caveats": [
        "The semantic layer averages Google Ads' own per-row rank-lost absolute-top share; nothing is recomputed here.",
        "Rank-lost only, the budget-lost equivalent is not measured on this dataset.",
        "The response key drops the rank qualifier; carry it in the sentence.",
        "Always per segment; unweighted average across rows; stored as a fraction between 0 and 1."
      ],
      "freshness": "~1 day behind, Ads reporting settles overnight; same-day spend is provisional.",
      "failureModes": [
        "Treating this as total lost first-slot coverage.",
        "Reading a rise in this number as an improvement because a direction oracle painted it green."
      ],
      "notSameAs": [
        {
          "slug": "absolute-top-impression-share",
          "why": "One is the first slot you won; this is the first slot you lost on rank. Separate columns, not complements."
        }
      ],
      "related": [
        "impression-share-lost-to-rank",
        "absolute-top-impression-share"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "paid-ad-cost",
      "name": "Ad cost",
      "aliases": [
        "Ad spend",
        "Total cost",
        "Spend"
      ],
      "definition": "Total money spent on Google Ads search over the period, summed from the Ads cost column.",
      "category": "Paid search",
      "type": "monetary",
      "unit": "account currency",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "Sums across rows. Whole-domain only, the paid statistics dataset carries no segment dimension, so a segment argument is ignored and a note is returned.",
      "grain": "One number per date range, or one row per group_by value (search term, bidded keyword, page, ad group, campaign, campaign type, intent, category).",
      "dimensions": [
        "keyword",
        "campaign_keyword",
        "page",
        "adgroup_name",
        "campaign_name",
        "campaign_type",
        "intent",
        "category",
        "country",
        "device"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "google-ads"
      ],
      "reports": [
        "paid-organic-overlap-report",
        "paid-search-performance-report"
      ],
      "skills": [
        "paid-efficiency-review",
        "paid-organic-balance",
        "monthly-exec-review"
      ],
      "verbs": [
        "paid_search_overview"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "How much are we spending on Google Ads?",
        "Where is spend going by campaign?",
        "Which bidded keywords cost the most?"
      ],
      "caveats": [
        "Whole-domain only: the paid statistics dataset scopes by a whole-domain flag rather than by segment, so a segment argument is dropped and the read stays whole-domain.",
        "The search term that triggered an ad and the bidded keyword are different fields; a cost report grouped by one is not a report grouped by the other.",
        "Same-day spend is provisional until Ads reporting settles overnight."
      ],
      "freshness": "~1 day behind, Ads reporting settles overnight; same-day spend is provisional.",
      "failureModes": [
        "Reading a segment-scoped cost number: there is none, any segment passed is ignored.",
        "Summing cost across a group_by breakdown and expecting the whole-domain total; the breakdown is capped at top_n."
      ],
      "notSameAs": [
        {
          "slug": "paid-cost-per-conversion",
          "why": "Cost is the absolute amount spent; cost per conversion is that amount divided by the ad platform's own conversion count."
        }
      ],
      "related": [
        "paid-average-cpc",
        "paid-cost-per-conversion",
        "paid-clicks"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "paid-average-cpc",
      "name": "Average cost per click",
      "aliases": [
        "CPC",
        "Avg CPC"
      ],
      "definition": "What one paid click cost on average, total ad cost divided by paid clicks.",
      "category": "Paid search",
      "type": "monetary",
      "unit": "account currency per click",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "A ratio of two sums, it is recomputed at whatever grain is queried, never averaged across rows of a breakdown.",
      "grain": "One number per date range, or one row per group_by value.",
      "dimensions": [
        "keyword",
        "campaign_keyword",
        "page",
        "adgroup_name",
        "campaign_name",
        "campaign_type",
        "intent",
        "category",
        "country",
        "device"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "google-ads"
      ],
      "reports": [
        "paid-organic-overlap-report",
        "paid-search-performance-report"
      ],
      "skills": [
        "paid-efficiency-review",
        "paid-organic-balance"
      ],
      "verbs": [
        "paid_search_overview"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "What are our CPC trends by keyword?",
        "Which campaigns have the most expensive clicks?"
      ],
      "caveats": [
        "Averaging CPC across a breakdown is not the account CPC: the ratio must be recomputed from the summed cost and summed clicks.",
        "Whole-domain only; a segment argument is ignored.",
        "The denominator is the paid click count, which the formatter mistypes as money, see the paid clicks entry."
      ],
      "freshness": "~1 day behind, Ads reporting settles overnight; same-day spend is provisional.",
      "failureModes": [
        "Taking a mean of per-campaign CPCs and calling it the account CPC.",
        "Comparing CPC between two periods without checking whether the campaign mix changed."
      ],
      "notSameAs": [
        {
          "slug": "paid-cost-per-conversion",
          "why": "CPC prices a click; cost per conversion prices an outcome. A campaign can have a cheap CPC and an expensive cost per conversion at the same time."
        },
        {
          "slug": "paid-clicks",
          "why": "One is a count of clicks, the other is the price of a click. Their underlying field names look alike, which is why the two are kept as separate entries.",
          "mirroredFrom": "paid-clicks"
        },
        {
          "slug": "paid-cpm",
          "why": "CPM prices exposure and CPC prices a click. They are not interchangeable, and neither may stand in for the missing one.",
          "mirroredFrom": "paid-cpm"
        }
      ],
      "related": [
        "paid-ad-cost",
        "paid-clicks",
        "paid-cost-per-conversion"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "paid-cpm",
      "name": "Average cost per thousand impressions",
      "aliases": [
        "CPM",
        "Avg CPM"
      ],
      "definition": "The average cost of a thousand ad impressions, as reported by Google Ads.",
      "category": "Paid search",
      "type": "monetary",
      "unit": "account currency per thousand impressions",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "Defined in the semantic layer as an average of the ad platform's per-row CPM, but not reachable through any tool.",
      "grain": "Would be one number per date range if it were surfaced.",
      "dimensions": [],
      "requiredFilters": [],
      "sources": [
        "google-ads"
      ],
      "reports": [
        "paid-search-performance-report"
      ],
      "skills": [],
      "verbs": [],
      "rungs": [
        "R5"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "What is our CPM?"
      ],
      "caveats": [
        "Not available through any tool today.",
        "Requests for CPM should be answered with what is available, cost, cost per click and cost per conversion, rather than with a substitute number."
      ],
      "freshness": "~1 day behind, Ads reporting settles overnight; same-day spend is provisional.",
      "failureModes": [
        "Substituting cost divided by impressions and presenting it as CPM."
      ],
      "notSameAs": [
        {
          "slug": "paid-average-cpc",
          "why": "CPM prices exposure, CPC prices a click. They are not interchangeable and one cannot stand in for the other."
        }
      ],
      "related": [
        "paid-average-cpc",
        "paid-impressions"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "paid-cost-per-conversion",
      "name": "Cost per conversion",
      "aliases": [
        "CPA",
        "Cost per acquisition"
      ],
      "definition": "What one ad-platform conversion cost on average, total ad cost divided by the ad platform's conversion count.",
      "category": "Paid search",
      "type": "monetary",
      "unit": "account currency per conversion",
      "direction": "lower-better",
      "verification": "verified",
      "calculation": "Total ad cost divided by the ad-platform conversion count, with a null guard on the denominator so a zero-conversion period returns no rate rather than an error: `cost / NULLIF(conversions, 0)`.",
      "numerator": "Total ad cost over the period",
      "denominator": "Ad-platform conversions over the period",
      "aggregation": "A ratio of two sums, recomputed at the queried grain, never averaged across breakdown rows.",
      "grain": "One number per date range, or one row per group_by value.",
      "dimensions": [
        "keyword",
        "campaign_keyword",
        "page",
        "adgroup_name",
        "campaign_name",
        "campaign_type",
        "intent",
        "category",
        "country",
        "device"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "google-ads"
      ],
      "reports": [
        "paid-search-performance-report"
      ],
      "skills": [
        "paid-efficiency-review",
        "paid-organic-balance",
        "search-to-revenue"
      ],
      "verbs": [
        "paid_search_overview"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "What is our cost per conversion by campaign?",
        "Which ad groups are the least efficient?"
      ],
      "interpretation": "The price of an outcome, in the ad platform's own attribution. It is the paid efficiency number executives recognise, and it is only comparable across campaigns that count the same conversion actions. A rising cost per conversion with flat cost per click means the click quality changed, not the auction price.",
      "caveats": [
        "The conversions in the denominator are the ad platform's attributed conversions, not the analytics named goals. The two lenses are named whenever both appear and are never blended.",
        "Conversion rate for paid is read from the analytics source rather than derived as conversions over clicks, dividing one system's numerator by another's denominator produces a number that is wrong in a way nobody can see.",
        "Whole-domain only; a segment argument is ignored.",
        "This is the one cost-family metric whose direction both direction modules agree on."
      ],
      "freshness": "~1 day behind, Ads reporting settles overnight; same-day spend is provisional.",
      "failureModes": [
        "Comparing cost per conversion across campaigns that count different conversion actions.",
        "Reading a zero as good performance when it is really a null denominator (no conversions recorded)."
      ],
      "notSameAs": [
        {
          "slug": "conversion-rate",
          "why": "Cost per conversion is a price from the ad platform's attribution; conversion rate is a rate measured in the analytics source against your own named goals. They come from different systems and are never combined."
        },
        {
          "slug": "paid-ad-cost",
          "why": "Cost is the absolute amount spent; cost per conversion is that amount divided by the ad platform's own conversion count.",
          "mirroredFrom": "paid-ad-cost"
        },
        {
          "slug": "paid-average-cpc",
          "why": "CPC prices a click; cost per conversion prices an outcome. A campaign can have a cheap CPC and an expensive cost per conversion at the same time.",
          "mirroredFrom": "paid-average-cpc"
        }
      ],
      "related": [
        "paid-ad-cost",
        "paid-conversions",
        "paid-average-cpc"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "impression-share-lost-to-rank",
      "name": "Impression share lost to rank",
      "aliases": [
        "Rank-lost impression share",
        "Lost IS (rank)"
      ],
      "definition": "The share of available auction impressions you did not receive specifically because your ad rank was too low.",
      "category": "Paid search",
      "type": "share",
      "unit": "share of available auction impressions (stored 0 to 1, shown as a percent)",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "An unweighted average across keyword-day rows.",
      "grain": "One number per segment and date range, or one row per keyword or campaign.",
      "dimensions": [
        "keyword",
        "campaign_name"
      ],
      "requiredFilters": [
        "segment_id",
        "date_range"
      ],
      "sources": [
        "google-ads"
      ],
      "reports": [
        "paid-search-performance-report"
      ],
      "skills": [
        "paid-efficiency-review",
        "paid-organic-balance"
      ],
      "verbs": [
        "paid_impression_share"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "Where are we losing impression share to rank?",
        "Which keywords have fixable auction ground?"
      ],
      "caveats": [
        "The semantic layer averages Google Ads' own per-row rank-lost impression share; nothing is recomputed here.",
        "This is rank-lost only. Impression share lost to BUDGET is not measured anywhere in the product: the budget-lost measures exist in the semantic layer only on a campaign-grain dataset that no tool reads, and the keyword-grain dataset this tool uses has none. A rank-lost figure therefore does not account for the impressions a capped budget cost you.",
        "The tool's own response key drops the rank qualifier, so a consumer reading the raw payload cannot tell which loss reason it has. Always carry the qualifier in the sentence.",
        "Won share and rank-lost share do not sum to one, budget loss and ineligibility live outside both.",
        "Always per segment; unweighted average across rows; stored as a fraction between 0 and 1."
      ],
      "freshness": "~1 day behind, Ads reporting settles overnight; same-day spend is provisional.",
      "failureModes": [
        "Reading a rank-lost number as total lost impression share and concluding the budget is fine.",
        "Adding won share and rank-lost share and expecting 100%.",
        "Reading a rise in rank-lost share as an improvement because a direction oracle painted it green."
      ],
      "notSameAs": [
        {
          "slug": "search-impression-share",
          "why": "One is what you won; this is one named reason for part of what you lost. They are separate averaged columns and do not complement each other."
        }
      ],
      "related": [
        "top-impression-share-lost-to-rank",
        "absolute-top-impression-share-lost-to-rank",
        "search-impression-share"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "paid-ctr",
      "name": "Paid click-through rate",
      "aliases": [
        "Ad CTR"
      ],
      "definition": "The share of ad impressions that produced a click.",
      "category": "Paid search",
      "type": "rate",
      "unit": "percent (0 to 100)",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "Paid clicks divided by paid impressions, multiplied by 100 and rounded to one decimal place, with a null guard on the denominator and nulls read as zero: `nvl(ROUND(100.0 * clicks / NULLIF(impressions, 0), 1), 0)`.",
      "numerator": "Paid clicks over the period",
      "denominator": "Paid impressions over the period",
      "aggregation": "A ratio of two sums, recomputed at the queried grain. Averaging per-campaign rates does not reproduce the account rate.",
      "grain": "One number per date range, or one row per group_by value.",
      "dimensions": [
        "keyword",
        "campaign_keyword",
        "page",
        "adgroup_name",
        "campaign_name",
        "campaign_type",
        "intent",
        "category",
        "country",
        "device"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "google-ads"
      ],
      "reports": [
        "paid-search-performance-report"
      ],
      "skills": [
        "paid-efficiency-review"
      ],
      "verbs": [
        "paid_search_overview"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "What is our paid CTR by campaign?",
        "Are our ad creatives earning clicks?"
      ],
      "interpretation": "How well the ad earns the click it was shown for. It is stored on a 0 to 100 scale and rounded to one decimal place, so very small rates flatten, read low-volume rows from the underlying click and impression counts instead.",
      "caveats": [
        "Stored already as a percent, not as a fraction; a consumer that multiplies by 100 again will report a rate a hundred times too high.",
        "Rounded to one decimal place in the semantic layer, so sub-0.05% rates report as 0.0.",
        "A null denominator resolves to 0 rather than to no-value, so a zero can mean either no clicks or no impressions.",
        "Paid CTR and organic CTR are different surfaces and are not comparable as like for like."
      ],
      "freshness": "~1 day behind, Ads reporting settles overnight; same-day spend is provisional.",
      "failureModes": [
        "Treating a rounded 0.0 as no clicks.",
        "Re-scaling an already-percent value."
      ],
      "notSameAs": [
        {
          "slug": "search-impression-share",
          "why": "CTR measures what happened after the ad was shown; impression share measures how often it was shown at all."
        }
      ],
      "related": [
        "paid-clicks",
        "paid-impressions"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "paid-clicks",
      "name": "Paid clicks",
      "aliases": [
        "Ad clicks"
      ],
      "definition": "The number of clicks your search ads received over the period.",
      "category": "Paid search",
      "type": "raw measure",
      "unit": "clicks",
      "direction": "higher-better",
      "verification": "review",
      "aggregation": "Sums across rows.",
      "grain": "One number per date range, or one row per group_by value.",
      "dimensions": [
        "keyword",
        "campaign_keyword",
        "page",
        "adgroup_name",
        "campaign_name",
        "campaign_type",
        "intent",
        "category",
        "country",
        "device"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "google-ads"
      ],
      "reports": [
        "paid-organic-overlap-report",
        "paid-search-performance-report"
      ],
      "skills": [
        "paid-efficiency-review",
        "paid-organic-balance"
      ],
      "verbs": [
        "paid_search_overview",
        "paid_organic_overlap"
      ],
      "rungs": [
        "R5",
        "R2"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "How many paid clicks did we buy?",
        "Which keywords drive the most paid clicks?"
      ],
      "caveats": [
        "Paid clicks and organic clicks are different lenses and are never summed silently.",
        "Whole-domain only; a segment argument is ignored.",
        "The underlying field name carries a cost-per-click token even though the measure is a click count."
      ],
      "freshness": "~1 day behind, Ads reporting settles overnight; same-day spend is provisional.",
      "failureModes": [
        "Adding paid clicks to Search Console organic clicks to make a traffic total.",
        "Any consumer that formats this metric by name will render a click count with a currency symbol."
      ],
      "notSameAs": [
        {
          "slug": "paid-average-cpc",
          "why": "One is a count of clicks, the other is the price of a click. The underlying field names look alike, which is exactly why they are kept apart here."
        }
      ],
      "related": [
        "paid-average-cpc",
        "paid-impressions",
        "paid-ctr"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "paid-conversions",
      "name": "Paid conversions",
      "aliases": [
        "Ad conversions",
        "Google Ads conversions"
      ],
      "definition": "The number of conversions Google Ads attributed to your search ads over the period.",
      "category": "Paid search",
      "type": "raw measure",
      "unit": "conversions",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "A sum of the Ads conversions column over the rows in scope: `sum(conversions)`.",
      "aggregation": "Sums across rows. Fractional values are expected, the ad platform reports fractional attributed conversions.",
      "grain": "One number per date range, or one row per group_by value.",
      "dimensions": [
        "keyword",
        "campaign_keyword",
        "page",
        "adgroup_name",
        "campaign_name",
        "campaign_type",
        "intent",
        "category",
        "country",
        "device"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "google-ads"
      ],
      "reports": [
        "paid-organic-overlap-report",
        "paid-search-performance-report",
        "search-to-revenue-report"
      ],
      "skills": [
        "paid-efficiency-review",
        "paid-organic-balance",
        "search-to-revenue"
      ],
      "verbs": [
        "paid_search_overview",
        "paid_organic_overlap"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "How many conversions did paid search drive?",
        "Which campaigns convert?"
      ],
      "interpretation": "The ad platform's own count of attributed outcomes. It answers what the ads bought, in the ads system's terms, which is the right frame for bid and budget decisions and the wrong frame for a business conversion total.",
      "caveats": [
        "These are ad-platform attributed conversions, not the analytics named goals. Never blend the two lenses in one total.",
        "Attribution windows and conversion-action selection are configured in Google Ads and are not visible here.",
        "Whole-domain only; a segment argument is ignored."
      ],
      "freshness": "~1 day behind, Ads reporting settles overnight; same-day spend is provisional.",
      "failureModes": [
        "Adding paid conversions to analytics goal conversions to get a business total, different systems, overlapping events.",
        "Treating fractional conversion counts as a data error."
      ],
      "notSameAs": [
        {
          "slug": "conversions-count",
          "why": "Paid conversions are the ad platform's attribution; the analytics conversion count is measured against the goals you configured yourself. The skills name which lens they are using whenever both appear."
        }
      ],
      "related": [
        "paid-cost-per-conversion",
        "conversions-count"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "paid-impressions",
      "name": "Paid impressions",
      "aliases": [
        "Ad impressions"
      ],
      "definition": "The number of times your search ads were shown over the period.",
      "category": "Paid search",
      "type": "raw measure",
      "unit": "impressions",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "A sum of the Ads impressions column over the rows in scope, with nulls read as zero.",
      "aggregation": "Sums across rows.",
      "grain": "One number per date range, or one row per group_by value.",
      "dimensions": [
        "keyword",
        "campaign_keyword",
        "page",
        "adgroup_name",
        "campaign_name",
        "campaign_type",
        "intent",
        "category",
        "country",
        "device"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "google-ads"
      ],
      "reports": [
        "paid-search-performance-report"
      ],
      "skills": [
        "paid-efficiency-review"
      ],
      "verbs": [
        "paid_search_overview"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "How many times did our ads show?",
        "Did impressions fall or did we lose share?"
      ],
      "interpretation": "The volume side of paid exposure. Read it beside search impression share: impressions can fall because the market shrank or because you won less of it, and only the share number separates the two.",
      "caveats": [
        "Impressions and impression share answer different questions, a rise in one with a fall in the other means the auction grew faster than you did.",
        "Whole-domain only; a segment argument is ignored.",
        "Paid impressions and Search Console organic impressions are different surfaces and are never summed."
      ],
      "freshness": "~1 day behind, Ads reporting settles overnight; same-day spend is provisional.",
      "failureModes": [
        "Reading an impression drop as a coverage problem without checking impression share."
      ],
      "notSameAs": [
        {
          "slug": "search-impression-share",
          "why": "Impressions count what you got; impression share expresses that as a fraction of what was available in the auction. Neither can be derived from the other here."
        }
      ],
      "related": [
        "paid-clicks",
        "paid-ctr",
        "search-impression-share"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "search-impression-share",
      "name": "Search impression share",
      "aliases": [
        "Impression share",
        "IS"
      ],
      "definition": "The share of the paid impressions available to you in the auction that your ads actually received.",
      "category": "Paid search",
      "type": "share",
      "unit": "share of available auction impressions (stored 0 to 1, shown as a percent)",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "The average of Google Ads' own per-row search impression share across the rows in scope. The share itself is computed by Google Ads, not by Quattr; the semantic layer averages it.",
      "aggregation": "An unweighted average across keyword-day rows, not an impression-weighted one, a low-volume keyword counts the same as a high-volume one.",
      "grain": "One number per segment and date range, or one row per keyword or campaign.",
      "dimensions": [
        "keyword",
        "campaign_name"
      ],
      "requiredFilters": [
        "segment_id",
        "date_range"
      ],
      "sources": [
        "google-ads"
      ],
      "reports": [
        "paid-organic-overlap-report",
        "paid-search-performance-report"
      ],
      "skills": [
        "paid-efficiency-review",
        "paid-organic-balance"
      ],
      "verbs": [
        "paid_impression_share",
        "total_search_share"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "How much of the available auction are we winning?",
        "Is our impression share improving?"
      ],
      "interpretation": "The coverage half of paid: not how well the ads performed, but how often they were eligible and shown at all. Read it beside the rank-lost measures, the gap between what you won and what you lost to rank is the auction ground a bid or quality change can recover.",
      "caveats": [
        "Called without a segment, the verb returns the list of tracked segments rather than a number, this metric is always per segment.",
        "The averaging is unweighted across rows, so a keyword with a handful of impressions moves the number as much as a keyword with thousands.",
        "Stored as a fraction between 0 and 1 while search market share is stored 0 to 100; combining the two without normalising erases the paid side.",
        "Click share is not surfaced anywhere in the product, the underlying column exists only on a campaign-grain dataset that no tool reads. Do not present impression share as a click-share proxy.",
        "The dataset has no country or device columns, so this metric cannot be sliced by geography or device."
      ],
      "freshness": "~1 day behind, Ads reporting settles overnight; same-day spend is provisional.",
      "failureModes": [
        "Assuming impression share can be broken down by country or device.",
        "Comparing impression share to search market share as if they were on the same scale."
      ],
      "notSameAs": [
        {
          "slug": "impression-share-lost-to-rank",
          "why": "One is what you won, the other is a specific named reason for what you did not win. They are separate columns and do not sum to a whole."
        },
        {
          "slug": "total-search-share",
          "why": "Impression share is paid coverage inside the ad auction; total search share is a combined estimate of paid and organic presence on the results page."
        },
        {
          "slug": "paid-impressions",
          "why": "Impressions count what you got; impression share expresses that as a fraction of what was available in the auction. Neither is derivable from the other in this product.",
          "mirroredFrom": "paid-impressions"
        },
        {
          "slug": "paid-ctr",
          "why": "CTR measures what happened after the ad was shown; impression share measures how often it was shown at all.",
          "mirroredFrom": "paid-ctr"
        },
        {
          "slug": "ctr",
          "why": "CTR is the share of impressions you received that clicked; impression share is the share of an available paid auction you appeared in at all. They share no numerator and no denominator, and click share, the metric people reach for when they conflate the two, does not exist in the product.",
          "mirroredFrom": "ctr"
        }
      ],
      "related": [
        "top-impression-share",
        "absolute-top-impression-share",
        "impression-share-lost-to-rank",
        "total-search-share-paid-leg"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "top-impression-share",
      "name": "Top impression share",
      "aliases": [
        "Search top IS"
      ],
      "definition": "The share of available auction impressions where your ad appeared above the organic results.",
      "category": "Paid search",
      "type": "share",
      "unit": "share of available auction impressions (stored 0 to 1, shown as a percent)",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "The average of Google Ads' own per-row search top impression share across the rows in scope.",
      "aggregation": "An unweighted average across keyword-day rows.",
      "grain": "One number per segment and date range, or one row per keyword or campaign.",
      "dimensions": [
        "keyword",
        "campaign_name"
      ],
      "requiredFilters": [
        "segment_id",
        "date_range"
      ],
      "sources": [
        "google-ads"
      ],
      "reports": [],
      "skills": [
        "paid-efficiency-review",
        "paid-organic-balance"
      ],
      "verbs": [
        "paid_impression_share"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "How often do our ads show above the organic results?"
      ],
      "interpretation": "Position quality inside the auction. A healthy overall impression share with a weak top impression share means you are being shown, but low on the page.",
      "caveats": [
        "Always per segment; called without one the verb returns the segment list.",
        "Unweighted average across rows.",
        "Stored as a fraction between 0 and 1.",
        "\"Top\" here means above the organic results, which is not the same as the single highest ad slot, that is absolute top."
      ],
      "freshness": "~1 day behind, Ads reporting settles overnight; same-day spend is provisional.",
      "failureModes": [
        "Reading top impression share as the first-position rate."
      ],
      "notSameAs": [
        {
          "slug": "absolute-top-impression-share",
          "why": "Top means anywhere above the organic results; absolute top means the very first ad slot. They are separate measures with separate columns."
        },
        {
          "slug": "top-impression-share-lost-to-rank",
          "why": "Top impression share is the above-organic placement you won; the rank-lost measure is the above-organic placement you lost on rank. Separate averaged columns, not complements, they do not sum to a whole.",
          "mirroredFrom": "top-impression-share-lost-to-rank"
        }
      ],
      "related": [
        "search-impression-share",
        "absolute-top-impression-share",
        "top-impression-share-lost-to-rank"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "top-impression-share-lost-to-rank",
      "name": "Top impression share lost to rank",
      "aliases": [
        "Rank-lost top IS"
      ],
      "definition": "The share of available auction impressions above the organic results that you did not receive because your ad rank was too low.",
      "category": "Paid search",
      "type": "share",
      "unit": "share of available auction impressions (stored 0 to 1, shown as a percent)",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "An unweighted average across keyword-day rows.",
      "grain": "One number per segment and date range, or one row per keyword or campaign.",
      "dimensions": [
        "keyword",
        "campaign_name"
      ],
      "requiredFilters": [
        "segment_id",
        "date_range"
      ],
      "sources": [
        "google-ads"
      ],
      "reports": [
        "paid-search-performance-report"
      ],
      "skills": [
        "paid-efficiency-review"
      ],
      "verbs": [
        "paid_impression_share"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L8"
      ],
      "questions": [
        "Are we losing above-organic placement to rank?"
      ],
      "caveats": [
        "The semantic layer averages Google Ads' own per-row rank-lost top impression share; nothing is recomputed here.",
        "Rank-lost only, the budget-lost equivalent is not measured on this dataset.",
        "The response key drops the rank qualifier; carry it in the sentence.",
        "Always per segment; unweighted average across rows; stored as a fraction between 0 and 1."
      ],
      "freshness": "~1 day behind, Ads reporting settles overnight; same-day spend is provisional.",
      "failureModes": [
        "Treating this as total lost top-of-page coverage.",
        "Reading a rise in this number as an improvement because a direction oracle painted it green."
      ],
      "notSameAs": [
        {
          "slug": "top-impression-share",
          "why": "One is the top placement you won; this is the top placement you lost on rank. Separate columns, not complements."
        }
      ],
      "related": [
        "impression-share-lost-to-rank",
        "top-impression-share"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "competitor-share-by-rank-bucket",
      "name": "Competitor share by rank bucket",
      "aliases": [
        "Rival share by ranking band",
        "Share by SERP position band"
      ],
      "definition": "A named tracked competitor's share within each ranking band, bucketed from their observed results-page positions rather than from the share-of-voice columns.",
      "category": "Search market share",
      "type": "share",
      "unit": "% of the tracked search demand within the ranking band",
      "direction": "higher-better",
      "verification": "inferred",
      "aggregation": "Not summable across bands. Each band is read independently, and your own leg and the competitor leg are bucketed by two different position vocabularies.",
      "grain": "One ranking band × competitor × segment × period × medium.",
      "dimensions": [
        "rank_bucket"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium",
        "competitor label"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "competitor-search-report",
        "search-market-share-report",
        "serp-volatility-report"
      ],
      "skills": [
        "competitor-deep-dive",
        "market-share-review",
        "rank-movement-review"
      ],
      "verbs": [
        "market_share_breakdown"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2",
        "L3"
      ],
      "questions": [
        "Where in the rankings does this rival take their share?",
        "Are they winning from the top three, or from deeper positions?"
      ],
      "interpretation": "A shape read rather than a level read: it says where in the results a rival's presence sits. Because the competitor leg and your own leg are bucketed by different position vocabularies, compare each domain to itself across bands before comparing the two domains within a band.",
      "caveats": [
        "The competitor leg is bucketed independently by observed results-page position, while your own leg in the same table comes from the customer-category share measure, two vocabularies in one view.",
        "Both legs are now readable in the semantic layer and they are genuinely different measures: your band value is that category slice's daily demand over the period's category total, and the rival's is the competitor-pages share over its own total. Both are scaled to a percentage, but they do not share a denominator, which is why the row is not published as one verified measure.",
        "It needs the roster's own competitor label; where a roster row has no label the verb returns null instead of substituting a domain into the filter.",
        "It is unavailable together with a brand or intent filter, the competitor-pages source cannot apply that slice, and the column is returned null with the reason stated.",
        "Clicks in the same table come from a third source and are returned null on a tracked segment, because a whole-domain search-analytics read would overstate them."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Reading a null competitor column as zero presence when it is a stated capability gap.",
        "Comparing your band value with the rival's band value as if both came from the same measure."
      ],
      "notSameAs": [
        {
          "slug": "avg-rank-vs-competitors",
          "why": "Average rank is one number per keyword; this distributes share across ranking bands. Position is the axis here, not the measurement."
        }
      ],
      "related": [
        "search-market-share",
        "category-market-share",
        "avg-rank-vs-competitors"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "category-market-share",
      "name": "Content-category search market share",
      "aliases": [
        "market_share_category",
        "Share by content category"
      ],
      "definition": "Your own CTR-modeled share of the tracked search demand within one page-side content category, such as product pages or help content.",
      "category": "Search market share",
      "type": "share",
      "unit": "% of the tracked search demand within the category",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "One grouped read on the customer-category dataset: the page-side content category as the dimension and the category share measure as the metric, with brand and intent applied as re-weighting parameters rather than ordinary row filters. The semantic layer defines that measure as the category's summed daily demand share over the period's category total, scaled to a percentage on the same basis as the rest of the family. It is YOUR share within the category, that dataset carries no per-competitor columns at all, so no rival column can be selected beside it. Reconciled against the product's own category tab on a live tenant (32.6866 read against a displayed 32.69%, and 0.0344 against 0.03%).",
      "aggregation": "Not summable across categories, categories do not partition the tracked demand and each row is a share against its own slice.",
      "grain": "One content category × segment × period × medium.",
      "dimensions": [
        "category",
        "intent",
        "brand",
        "rank_bucket"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "search-market-share-report"
      ],
      "skills": [
        "market-share-review",
        "content-decay-refresh",
        "monthly-exec-review"
      ],
      "verbs": [
        "market_share_breakdown",
        "growth_vs_market_share"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2",
        "L3"
      ],
      "questions": [
        "Which content categories hold the most search market share?",
        "Is our product content losing ground faster than our editorial content?"
      ],
      "interpretation": "A read on where your content estate is strong, not a competitive standing. Because that dataset has no rival columns, the correct sentence is \"we hold X% of the tracked demand in this category\", never \"we lead this category\".",
      "caveats": [
        "This is your own share within the category, not share of voice against tracked rivals, the underlying dataset carries no competitor columns.",
        "Categories are PAGE-side content categories, not keyword groupings; a keyword-side category read is a different question.",
        "Category is a filter and a group-by only on this dataset: the category column on the keyword-and-page dataset is not selectable, so a category breakdown routes here and joins clicks from a separate read.",
        "The click leg switches source with the filter, a brand or intent filter routes it to the keyword-and-page combined table, an unfiltered read to the page combined table. That mirrors the product, but the two are different populations.",
        "Clicks come back null on a tracked segment: the whole-domain click read would overstate it and the segment's own filters cannot be reconstructed on that side. The share stays segment-scoped and correct.",
        "The union of the share rows and the click rows keeps one-sided rows, so a category can show share with no clicks, or clicks with near-zero share."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Presenting a category share as a competitive position.",
        "Requesting a category group-by together with competitor columns, which the verbs refuse with a steer rather than returning a plausible wrong number."
      ],
      "notSameAs": [
        {
          "slug": "search-market-share",
          "why": "Segment share is share of voice against tracked rivals; category share is your own share within a content category, on a member that has no competitor columns."
        }
      ],
      "related": [
        "search-market-share",
        "page-market-share",
        "competitor-share-by-rank-bucket"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "gap-to-leader",
      "name": "Gap to leader",
      "aliases": [
        "Leader gap",
        "Distance to the leader"
      ],
      "definition": "The distance in share points between the segment leader's CTR-modeled search market share and your own, for the same period and slice.",
      "category": "Search market share",
      "type": "derived metric",
      "unit": "share points (percentage points of tracked search demand)",
      "direction": "lower-better",
      "verification": "verified",
      "calculation": "The leader's share minus your own, both taken at FULL PRECISION from the same standings before any rounding, with the single difference then rounded to one decimal place. Null when either side is missing. Computed in the MCP, not in the semantic layer.",
      "numerator": "leader's share value for the slice",
      "denominator": "not a ratio, a difference in share points",
      "aggregation": "Not summable. Recompute per slice and per period; a gap across periods is a pair of gaps, not an average.",
      "grain": "One segment × period × medium.",
      "dimensions": [
        "intent",
        "brand",
        "keyword",
        "page",
        "country",
        "device"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "monthly-executive-search-report",
        "search-market-share-report"
      ],
      "skills": [
        "market-share-review",
        "competitor-deep-dive",
        "search-pulse",
        "monthly-exec-review"
      ],
      "verbs": [
        "market_share_overview",
        "market_share_query"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2"
      ],
      "questions": [
        "How far behind the leader are we?",
        "Is the gap closing or widening?",
        "Which intents carry the widest gap?"
      ],
      "interpretation": "The most usable number in the family, because it survives the modelling caveat: both sides are computed the same way from the same period, so the difference and its direction are meaningful even where the absolute levels are approximations. Zero means you are the leader.",
      "caveats": [
        "It is a difference in share points, not a percentage change, a gap that moves from 8 to 6 points closed by 2 points, not by 25%.",
        "The difference is taken before rounding while the two share figures are published after it, so subtracting the two published shares will not always reproduce the published gap.",
        "The gap is only against the leading TRACKED domain; an untracked domain ahead of both of you is invisible.",
        "When you lead, the gap is zero by construction rather than a measured advantage over the runner-up."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Quoting the gap as a percentage and mixing points with percent in the same sentence.",
        "Comparing gaps across segments, which have different tracked demand and different rosters."
      ],
      "notSameAs": [
        {
          "slug": "head-to-head-rank-gap",
          "why": "That gap is a difference in ranking positions on shared keywords; this one is a difference in CTR-modeled share of tracked demand."
        },
        {
          "slug": "search-market-share-change",
          "why": "The gap compares two domains in one period; this compares one domain across two periods.",
          "mirroredFrom": "search-market-share-change"
        }
      ],
      "related": [
        "search-market-share",
        "market-share-leader",
        "market-share-standings-rank"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "market-share-table-clicks",
      "name": "Market-share-table clicks",
      "aliases": [
        "total_clicks on the share table",
        "Tracked clicks"
      ],
      "definition": "The click count carried on the market-share family itself, covering only the scraped keyword and page rows that table holds.",
      "category": "Search market share",
      "type": "raw measure",
      "unit": "clicks",
      "direction": "higher-better",
      "verification": "review",
      "aggregation": "Summable within the table's own rows only; it does not reconcile to the search-analytics click total for the same period.",
      "grain": "One segment × period × medium, at the grain of the read.",
      "dimensions": [
        "intent",
        "brand",
        "keyword",
        "page",
        "country",
        "device"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium"
      ],
      "sources": [
        "rank-tracking",
        "search-console"
      ],
      "reports": [
        "monthly-executive-search-report",
        "search-market-share-report",
        "serp-volatility-report"
      ],
      "skills": [
        "market-share-review",
        "quattr-troubleshooter"
      ],
      "verbs": [
        "growth_vs_market_share",
        "market_share_breakdown",
        "market_share_query"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2"
      ],
      "questions": [
        "Why are the clicks next to our share smaller than the search-analytics number?",
        "Which click figure should a report use beside search market share?"
      ],
      "caveats": [
        "Live-verified as a material undercount against the certified whole-site total for the same week, roughly 58% of it, because the table covers only scraped keyword and page rows.",
        "It fails to compile at all at the coarser grains, so the verbs guard those combinations with a stated error rather than surfacing a warehouse fault, with one deliberate exemption: the default full-domain summary is allowed through, because its share read selects no clicks and the click figure comes from a separate search-analytics read.",
        "Whole-domain click reads are routed to the search-analytics source instead, and the payload states which source produced the number.",
        "On a tracked segment the whole-domain alternative would overstate, so those segments keep this segment-scoped figure, labelled, not silently swapped."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card. (The slower of the two sources this metric spans; the share side updates about a day behind.)",
      "failureModes": [
        "Pairing this figure with a whole-domain click total in the same table.",
        "Explaining the shortfall as a data outage rather than as the table's row coverage."
      ],
      "notSameAs": [],
      "related": [
        "search-market-share",
        "search-market-share-change"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "page-market-share",
      "name": "Page-level search market share",
      "aliases": [
        "page_market_share",
        "Share by URL"
      ],
      "definition": "Your own CTR-modeled share of tracked search demand attributed to one page, the share column a breakdown returns when it groups by URL, though not always from the same underlying measure.",
      "category": "Search market share",
      "type": "share",
      "unit": "% of the tracked search demand attributed to the page",
      "direction": "higher-better",
      "verification": "inferred",
      "aggregation": "Not summable across pages, each row is a share against its own demand, and the page rows do not partition the segment.",
      "grain": "One page × segment × period × medium.",
      "dimensions": [
        "page",
        "intent",
        "brand",
        "category"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "search-market-share-report"
      ],
      "skills": [
        "market-share-review",
        "competitor-deep-dive",
        "content-decay-refresh"
      ],
      "verbs": [
        "market_share_breakdown",
        "market_share_query"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2",
        "L3"
      ],
      "questions": [
        "Which of our pages hold the most share of tracked demand?",
        "Which URLs lost ground this month?"
      ],
      "interpretation": "Use it to rank your own pages against each other, not to compare a page against a competitor. It is a client-only measure: the page breakdown has no per-competitor equivalent, so a named rival's column is simply absent at this grain.",
      "caveats": [
        "TWO measures now answer to this name. The canonical full-domain page breakdown reads the customer-category share on the customer-category dataset and relabels it as page share in the response; the page measure of that name is read only on the retained path, tracked segments, click-ranked pages and comparison refills. Two page rows can carry the same column name from different definitions.",
        "Client-only. The page drill deliberately substitutes a client measure for the per-competitor columns, so page rows carry no rival share.",
        "The page measure itself is that page's share of the same daily denominator the rest of the family divides by, scaled to a percentage and carrying the same organic adjustment. The customer-category measure that stands in for it on the canonical route has its own denominator, so the two are not interchangeable at the row level.",
        "It resolves to zero rather than null where there is no presence, the semantic layer wraps it in a zero default, so a zero row is not evidence the page is untracked.",
        "Page filters are applied as a parameter rather than through the plain page dimension, because the backing column is only present when clicks are also selected."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Comparing a page's value against a competitor's segment-level share as if they shared a denominator.",
        "Comparing a canonical page row against a tracked-segment page row without noticing they came from different measures.",
        "Reading a zero as an absence of tracking rather than an absence of presence."
      ],
      "notSameAs": [
        {
          "slug": "search-market-share",
          "why": "Segment share is your own domain's share column; page share is a separate client-only measure with its own denominator and no competitor counterpart."
        }
      ],
      "related": [
        "search-market-share",
        "category-market-share"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "search-market-share",
      "name": "Search market share",
      "aliases": [
        "Share of voice in search",
        "Search SOV",
        "CTR-modeled search market share"
      ],
      "definition": "Your CTR-modeled share of the tracked search demand inside one segment, read from the share-of-voice competitor column that carries your own domain.",
      "category": "Search market share",
      "type": "share",
      "unit": "% of the tracked search demand in the segment",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "The tracked-competitor roster for the segment and medium is read first, and the row that is yours carries a rank; that rank picks out your own domain's share column on the dataset being read. That column is returned exactly as the semantic layer computes it, nothing downstream recomputes it. Each column is that domain's summed share over the tracked family's daily total, already expressed as a percentage. The figure you receive is final, nothing downstream re-scales it.",
      "aggregation": "Never summed. Each per-domain share value is already a share of its own slice's demand, so adding intents, pages or keywords together produces a number with no denominator. Compare like slices, or re-read at the grain you want.",
      "grain": "One segment × period × medium. Whole-segment is the default lens; site, keyword, page and category members are separate lenses with their own field sets.",
      "dimensions": [
        "intent",
        "brand",
        "keyword",
        "page",
        "category",
        "country",
        "device",
        "rank_bucket"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "ai-overview-report",
        "monthly-executive-search-report",
        "search-market-share-report",
        "serp-volatility-report"
      ],
      "skills": [
        "market-share-review",
        "competitor-deep-dive",
        "search-pulse",
        "weekly-search-report",
        "monthly-exec-review"
      ],
      "verbs": [
        "market_share_overview",
        "market_share_query",
        "market_share_breakdown",
        "growth_vs_market_share",
        "competitive_trends"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2"
      ],
      "questions": [
        "What is our search market share in this segment?",
        "Are we gaining or losing ground against tracked rivals?",
        "How does our share split between branded and non-branded demand?"
      ],
      "interpretation": "Read it as a direction and a distance, not as a precise level. It is modelled from click-through at observed positions over the keywords a segment tracks, so it answers \"how much of this demand are we plausibly taking, relative to the rivals we track\", not \"what fraction of a market we own\". Movement of the gap matters more than the absolute number.",
      "caveats": [
        "Always CTR-modeled search market share of tracked demand, directional, scoped to a segment's keywords, and never revenue share.",
        "Only roster ranks one to forty have a selectable share column. A roster row beyond forty is dropped from the standings, and if your own row sits there your share comes back unavailable even though your domain identity still resolves from the full roster.",
        "A competitor a segment does not track is invisible to this number, so absence from the standings means untracked, not absent.",
        "Without a segment the read spans segments and the result is meaningless; reads default to the primary whole-domain segment rather than running unscoped.",
        "Every read is also pinned to the canonical customer-site URL and, where the dataset exposes it, to web search, the same always-on scope the product applies. A read without them is not the product's number.",
        "Intent and brand are applied as parameters that re-weight the measure, not as ordinary row filters; filtering the plain intent or brand dimension instead returns a materially different number."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Reading a segment total and a keyword-grain total as the same quantity, they are different reads with different denominators.",
        "Summing shares across a breakdown to reach a segment total.",
        "Treating a rival's absence from the standings as evidence they are not competing."
      ],
      "notSameAs": [
        {
          "slug": "total-daily-market-share",
          "why": "That measure is the share-of-voice denominator, documented in code as a decoy and never returned as anyone's share; this is your own SOV-adjusted column."
        },
        {
          "slug": "avg-rank-vs-competitors",
          "why": "Rank is impression-weighted position on a keyword; this is CTR-modeled share of tracked demand. The two live on different explores and can move in opposite directions."
        },
        {
          "slug": "page-market-share",
          "why": "Page-level share is a separate client-only measure with its own contract, not the same per-domain share column read at page grain."
        },
        {
          "slug": "ai-share-of-voice",
          "why": "Both get called \"share of voice\". This one is CTR-modeled search market share of tracked demand on the Google SERP; the other is share of answer-engine responses. Different surfaces, different denominators, and they move independently."
        },
        {
          "slug": "category-market-share",
          "why": "Segment share is share of voice against tracked rivals; category share is your own share within a content category, on a member that has no competitor columns.",
          "mirroredFrom": "category-market-share"
        },
        {
          "slug": "avg-position",
          "why": "Average position is an impression-weighted ordinal on your own results; search market share is a CTR-modeled share of tracked demand, aggregated across a segment and comparable to competitors. Position can improve while share falls, because share depends on what everyone else did with the same demand.",
          "mirroredFrom": "avg-position"
        },
        {
          "slug": "our-rank",
          "why": "A rank is an ordinal on a single keyword; search market share is a CTR-modeled share of the tracked demand aggregated across the segment. You can hold better ranks on more keywords and still hold less share, because share weights by the demand behind each keyword.",
          "mirroredFrom": "our-rank"
        },
        {
          "slug": "keyword-rank-gap",
          "why": "A rank gap is a per-keyword position difference; search market share is a CTR-modeled share of tracked demand across the whole segment. Closing gaps on low-demand keywords can leave share unchanged, and share can move with no gap changing at all.",
          "mirroredFrom": "keyword-rank-gap"
        }
      ],
      "related": [
        "market-share-leader",
        "gap-to-leader",
        "market-share-standings-rank",
        "category-market-share",
        "search-market-share-change"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "search-market-share-change",
      "name": "Search market share change",
      "aliases": [
        "Share delta",
        "Period-over-period share move"
      ],
      "definition": "The period-over-period move in your CTR-modeled search market share, returned as an absolute difference in share points alongside a proportional change.",
      "category": "Search market share",
      "type": "derived metric",
      "unit": "share points for the absolute move",
      "direction": "higher-better",
      "verification": "review",
      "aggregation": "Not summable. Each period pair produces its own difference; chaining them does not give a longer-period move.",
      "grain": "One segment × period pair × medium.",
      "dimensions": [
        "intent",
        "brand",
        "keyword",
        "page",
        "category",
        "country",
        "rank_bucket"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "comparison_range",
        "source_medium"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "search-market-share-report"
      ],
      "skills": [
        "market-share-review",
        "weekly-search-report",
        "monthly-exec-review",
        "significance-referee"
      ],
      "verbs": [
        "growth_vs_market_share",
        "market_share_breakdown",
        "competitive_trends"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2"
      ],
      "questions": [
        "Did our search market share move against last month?",
        "Which rows moved most between the two periods?"
      ],
      "caveats": [
        "The comparison leg is the identical query with only the period filter swapped, so any filter difference between the two legs invalidates the pair.",
        "The proportional change is computed as the difference over the earlier value and is returned as a fraction here, while the significance verbs express the same idea as a percent, the two must not be quoted interchangeably.",
        "The share leg's delta is returned unrounded while the count legs beside it are rounded to two decimal places, so a share move and a click move in the same row are not reported at the same precision.",
        "A move is not a verdict: nothing in this figure tests whether the change is distinguishable from noise."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Rendering the fraction as if it were already a percentage, inflating the move a hundredfold.",
        "Calling a share move real without running the significance check."
      ],
      "notSameAs": [
        {
          "slug": "gap-to-leader",
          "why": "The gap compares two domains in one period; this compares one domain across two periods."
        }
      ],
      "related": [
        "search-market-share",
        "gap-to-leader",
        "market-share-table-clicks"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "market-share-leader",
      "name": "Segment leader",
      "aliases": [
        "Leader",
        "Top domain by share"
      ],
      "definition": "The tracked domain holding the highest CTR-modeled search market share in a segment for the period, reported with its share value.",
      "category": "Search market share",
      "type": "derived metric",
      "unit": "competitor domain, with its share as a % of tracked search demand",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "Every roster row's share value is collected, columns that are not finite numbers dropped, the list sorted by share descending on the PRECISE value, and the first entry taken as the leader, domain plus share, the share rounded to one decimal place for display. Computed in the MCP over values the semantic layer returns; nothing about the leader is asked of the warehouse.",
      "aggregation": "Not aggregatable. It is a selection over one period's standings; a leader across periods must be recomputed per period, not averaged.",
      "grain": "One segment × period × medium.",
      "dimensions": [
        "intent",
        "brand",
        "keyword",
        "page",
        "country",
        "device"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "search-market-share-report"
      ],
      "skills": [
        "market-share-review",
        "competitor-deep-dive",
        "monthly-exec-review"
      ],
      "verbs": [
        "market_share_overview",
        "market_share_query"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2"
      ],
      "questions": [
        "Who leads this segment?",
        "Did the leader change this month?",
        "Is the leader a direct rival or an aggregator?"
      ],
      "interpretation": "The leader is whoever takes the most results-page real estate for this tracked demand, routinely an aggregator, marketplace or forum rather than the rival named on an org chart. A surprising leader is usually correct and worth saying out loud.",
      "caveats": [
        "Only tracked domains can lead: an untracked competitor with a larger real presence will never appear.",
        "You can be the leader yourself; the standings mark your own row and exclude it from the competitor list.",
        "Leadership does NOT flip on rounding, the sort runs on the precise share values and only the displayed figure is rounded to a tenth. Two domains can therefore publish the same share and still have a determinate order, which reads as an arbitrary tie unless the ordering is explained."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Reporting a leader change as a market event when it is a roster change (a competitor added or removed from the segment).",
        "Explaining a leader-versus-runner-up ordering by the published shares when those two shares are equal after rounding.",
        "Naming a leader for a segment whose share columns are entirely unpopulated, the verbs return a stated no-data note instead."
      ],
      "notSameAs": [
        {
          "slug": "market-share-standings-rank",
          "why": "The leader is an identity (which domain is first); the standings rank is your own ordinal position in the same sorted list."
        }
      ],
      "related": [
        "search-market-share",
        "gap-to-leader",
        "market-share-standings-rank"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "total-daily-market-share",
      "name": "Total daily share denominator",
      "aliases": [
        "total_daily_market_share",
        "The SOV denominator"
      ],
      "definition": "The share-of-voice denominator carried on the market-share family, the quantity the per-domain columns are shares OF, and never itself a domain's share.",
      "category": "Search market share",
      "type": "raw measure",
      "unit": "share-of-voice denominator units (not a percentage of anything)",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "Exposed on every read in the market-share family alongside the per-domain columns. It is deliberately never returned as anyone's share: your own figure always comes from your own domain's share column. Three separate code paths document it as the denominator and refuse to read it as a share.",
      "aggregation": "Do not report it. The semantic layer wraps the summed denominator in a null-if-zero guard, so an empty slice returns null rather than a real quantity, and the breakdown handler documents that reading as zero downstream, which is how it becomes a plausible-looking wrong answer.",
      "grain": "One segment × period × medium, on whichever read it comes from.",
      "dimensions": [
        "intent",
        "brand",
        "keyword",
        "page",
        "country",
        "device"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "ai-overview-report",
        "competitor-search-report",
        "monthly-executive-search-report",
        "search-market-share-report",
        "serp-volatility-report"
      ],
      "skills": [
        "quattr-iq",
        "quattr-troubleshooter"
      ],
      "verbs": [
        "market_share_query"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2"
      ],
      "questions": [
        "Why does this field look like our search market share but disagree with the app?",
        "What are the per-competitor share columns a share of?"
      ],
      "interpretation": "This entry exists to be recognised and avoided. It is the single most convincing wrong answer in the family: it sits on the same dataset, carries a share-shaped name, and returns a number for any slice. Every published share comes from a per-domain column instead.",
      "caveats": [
        "It is documented in the metric registry, the query composer and the breakdown handler as the denominator, not the customer's share.",
        "It is not the segment total either, the semantic layer nulls it when the summed value is zero, and in a grouped read that surfaces as a zero where the underlying demand is not zero.",
        "Anything reading it as a share will disagree with the product's own numbers in a way that looks like a data problem rather than a field-choice problem."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Selecting it because the field name matches the question's wording.",
        "Using it as a denominator to hand-compute a share, which double-counts the adjustment already baked into the per-domain columns."
      ],
      "notSameAs": [
        {
          "slug": "search-market-share",
          "why": "This is what the per-domain columns are shares of; your share is your own domain's share column. Reading this one as a share is the documented decoy."
        }
      ],
      "related": [
        "search-market-share",
        "category-market-share",
        "page-market-share"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "market-share-standings-rank",
      "name": "Your rank in the standings",
      "aliases": [
        "Position in the standings",
        "Where we sit vs tracked rivals"
      ],
      "definition": "Your ordinal position among the tracked domains of a segment when they are sorted by CTR-modeled search market share, highest first.",
      "category": "Search market share",
      "type": "rank",
      "unit": "position among tracked domains (1 = highest share)",
      "direction": "lower-better",
      "verification": "verified",
      "calculation": "The standings are built by collecting each roster row's share value, dropping the columns that are not finite numbers, sorting descending on the PRECISE value rather than the rounded one, and marking the row the roster flags as yours. Your position is read off that ordered list. The ordering is pinned in code; the ordinal itself is not emitted as its own field, so it is read from the returned standings rather than quoted from the payload.",
      "aggregation": "Not aggregatable, a position is per period and per slice. Track it as a sequence of positions, never an average position.",
      "grain": "One segment × period × medium.",
      "dimensions": [
        "intent",
        "brand",
        "keyword",
        "page",
        "country",
        "device"
      ],
      "requiredFilters": [
        "segment_id",
        "selected_period",
        "source_medium"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "monthly-executive-search-report",
        "search-market-share-report"
      ],
      "skills": [
        "market-share-review",
        "competitor-deep-dive",
        "monthly-exec-review"
      ],
      "verbs": [
        "market_share_overview",
        "market_share_query"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2"
      ],
      "questions": [
        "Where do we sit in the standings for this segment?",
        "Did we move up or down against tracked rivals?",
        "Who is immediately ahead of us?"
      ],
      "interpretation": "A coarse read that hides distance: moving from fourth to third can mean a tenth of a share point. Pair it with the leader gap, which carries the magnitude the position discards.",
      "caveats": [
        "The denominator is the tracked roster, not the market, a position of 3 means third among the domains this segment tracks.",
        "The order can disagree with the displayed shares: two domains rounded to the same tenth still hold distinct positions, decided by digits the card does not show.",
        "Roster changes move the position without anything changing in the results pages.",
        "The ordinal is derived from the returned standings; the payload carries the sorted list and your own row, not a rank integer."
      ],
      "freshness": "~1 day behind, Daily observation, available the following day.",
      "failureModes": [
        "Narrating a position change as a market move when the roster gained or lost a domain.",
        "Averaging positions across weeks, which discards the share distances that made them."
      ],
      "notSameAs": [
        {
          "slug": "avg-rank-vs-competitors",
          "why": "That is a search-results position on keywords; this is a position in a share league table. Different explores, different meaning of the number one."
        },
        {
          "slug": "market-share-leader",
          "why": "The leader names which domain sits first; this names where you sit in the same ordering."
        }
      ],
      "related": [
        "search-market-share",
        "gap-to-leader",
        "market-share-leader"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ctr",
      "name": "Average CTR",
      "aliases": [
        "CTR",
        "Click-through rate",
        "Average click-through rate"
      ],
      "definition": "The share of the impressions in a slice that produced a click, reported as a percentage.",
      "category": "Search performance",
      "type": "derived metric",
      "unit": "percent (0 to 100, rounded to one decimal)",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "`ROUND(100.0 * clicks / NULLIF(impressions, 0), 1)`, the pooled clicks of the slice over the pooled impressions of the same slice, expressed on a 0 to 100 scale.",
      "numerator": "Organic clicks in the slice",
      "denominator": "Organic impressions in the slice",
      "aggregation": "Recomputed from summed clicks and summed impressions at whatever grain is queried. Never average a column of CTRs, rows carry wildly different impression counts, so the mean of rates is not the rate.",
      "grain": "One date range × the selected slice.",
      "dimensions": [
        "query",
        "page",
        "country",
        "device",
        "intent",
        "category",
        "brand",
        "rank bucket"
      ],
      "requiredFilters": [
        "date range",
        "source medium"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "ai-overview-report",
        "cannibalization-report",
        "content-decay-report",
        "content-performance-report",
        "keyword-ranking-report",
        "weekly-search-report"
      ],
      "skills": [
        "ctr-opportunity-audit",
        "weekly-search-report",
        "rank-movement-review",
        "anomaly-investigator"
      ],
      "verbs": [
        "search_performance",
        "gsc_breakdown",
        "compare_periods"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L3"
      ],
      "questions": [
        "What is our CTR for non-brand keywords?",
        "Which pages have high impressions and low CTR?",
        "Did CTR drop after the title rewrites?"
      ],
      "interpretation": "The click-earning step: given that you appeared, how often you were chosen. It is only interpretable against a position, a 2% CTR at position 3 and a 2% CTR at position 14 are opposite findings, which is why the reference keeps a fitted expected-CTR curve rather than a benchmark.",
      "caveats": [
        "Stored on a 0 to 100 scale here, while the CTR figures computed by the CTR-curve and striking-distance analyses are 0 to 1 fractions. The same word covers both scales in different parts of the product.",
        "Rounded to one decimal at the source, so small CTR movements on large slices are inside the rounding.",
        "A site-level CTR blends branded and non-branded demand, and the branded half dominates it. Split before drawing a conclusion.",
        "There is no click-share metric anywhere in the product; a share-shaped click number is always something else mis-stated."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Averaging per-row CTRs instead of recomputing from pooled clicks and impressions.",
        "Comparing a 0 to 100 CTR to a 0 to 1 modeled CTR and reporting a 100× gap.",
        "Reading a blended branded and non-branded CTR as a site-wide snippet verdict."
      ],
      "notSameAs": [
        {
          "slug": "actual-ctr",
          "why": "Both are clicks over impressions, but this one is a LookML measure returned on a 0 to 100 scale for whatever slice was queried, while actual CTR is computed in our own compute pass as a 0 to 1 fraction for a single query-and-page row. Different scale, different grain, and they are never interchangeable in a formula."
        },
        {
          "slug": "search-impression-share",
          "why": "CTR is the share of impressions you received that clicked; impression share is the share of an available paid auction you appeared in at all. They share no numerator and no denominator, and click share, the metric people reach for when they conflate the two, does not exist in the product."
        },
        {
          "slug": "weighted-ctr",
          "why": "Search Console's average CTR is a warehouse measure returned on a 0 to 100 scale for whatever slice was queried; weighted CTR is computed in our own compute pass as a 0 to 1 fraction for one position bucket inside one segment cell. Same arithmetic, different scale and a completely different grain.",
          "mirroredFrom": "weighted-ctr"
        }
      ],
      "related": [
        "clicks",
        "impressions",
        "expected-ctr",
        "ctr-delta"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "avg-position",
      "name": "Average position",
      "aliases": [
        "Average weighted position",
        "Avg position",
        "Position"
      ],
      "definition": "Where your results sat on the Google results page over the period, averaged across every impression rather than across every keyword.",
      "category": "Search performance",
      "type": "rank",
      "unit": "results-page position (1 = top)",
      "direction": "lower-better",
      "verification": "verified",
      "calculation": "Σ(position × impressions) / Σ(impressions), built from a hidden per-row column defined as position × impressions on the keyword-and-page fact.",
      "numerator": "Sum of position × impressions",
      "denominator": "Sum of impressions",
      "aggregation": "Impression-weighted at every grain. It cannot be re-averaged from a column of positions, and two periods' averages cannot be added or differenced without their impression weights.",
      "grain": "One date range × the selected slice, over the ranked keyword-and-page rows in that slice.",
      "dimensions": [
        "query",
        "page",
        "country",
        "device",
        "intent",
        "category",
        "brand",
        "rank bucket"
      ],
      "requiredFilters": [
        "date range",
        "source medium"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "ai-overview-report",
        "cannibalization-report",
        "content-decay-report",
        "content-performance-report",
        "ctr-opportunity-report",
        "keyword-ranking-report",
        "monthly-executive-search-report",
        "paid-organic-overlap-report",
        "search-market-share-report",
        "search-opportunity-report",
        "serp-volatility-report",
        "weekly-search-report"
      ],
      "skills": [
        "rank-movement-review",
        "weekly-search-report",
        "striking-distance-sprint",
        "anomaly-investigator",
        "cannibalization-check"
      ],
      "verbs": [
        "search_performance",
        "gsc_breakdown",
        "seo_ranking_movement_report"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L3",
        "L4"
      ],
      "questions": [
        "What is our average position for non-brand keywords?",
        "Did average position improve versus last month?",
        "Average position by device",
        "Which keywords sit between positions 8 and 20?"
      ],
      "interpretation": "A weighted read of the consideration set: how prominently you appeared, with the loudest keywords counting most. Movement is only meaningful against a stable mix, a shift in which countries or devices produced the impressions moves this number without anything ranking differently.",
      "caveats": [
        "Site-level position is not read from the site rollup table. That table's weighted-position column holds the raw position instead of position × impressions, so its average divides positions by impressions and returns a meaningless small number, roughly 0.05 where the correct weighted value is around 15. Site-grain position is sourced from a second read of the ranked keyword-and-page rows and merged over it.",
        "Because of that split, a site-grain average position describes ranked keyword rows only, while the clicks and impressions beside it are whole-site totals. The two halves of the card have different coverage and the card says so.",
        "Average position is an organic measure. For a paid medium there is no position source at all and it reads null rather than zero.",
        "A blended device or country cut can move average position through mix shift alone; the mix check comes before the narration.",
        "Windows straddling Google's September 2025 num=100 reporting change carry an artifact in position as well as impressions."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Quoting the site rollup table's position field directly and publishing a number near zero as an average rank.",
        "Comparing a site-grain average position to a keyword-level one as if the two covered the same rows.",
        "Calling a position move an improvement when the underlying device or geography mix changed."
      ],
      "notSameAs": [
        {
          "slug": "search-market-share",
          "why": "Average position is an impression-weighted ordinal on your own results; search market share is a CTR-modeled share of tracked demand, aggregated across a segment and comparable to competitors. Position can improve while share falls, because share depends on what everyone else did with the same demand."
        },
        {
          "slug": "our-rank",
          "why": "This is your own reported position across all impressions Google recorded for you; our rank is Quattr's observed position for one keyword inside one tracked segment, alongside competitor ranks on that keyword. Different sources, different keyword universes, they are not expected to reconcile."
        }
      ],
      "related": [
        "keyword-page-click-coverage",
        "impressions",
        "ranking-movement",
        "striking-distance-candidates"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "keyword-page-click-coverage",
      "name": "Keyword-page click coverage",
      "aliases": [
        "Keyword-attributed coverage",
        "KPR coverage"
      ],
      "definition": "The share of whole-site organic clicks that can be attributed to a specific ranked keyword and page, the basis on which site-level average position and every branded or intent rollup is computed.",
      "category": "Search performance",
      "type": "share",
      "unit": "% of whole-site organic clicks",
      "direction": "higher-better",
      "verification": "inferred",
      "aggregation": "Not returned by any verb. It is the implied ratio between the keyword-attributed rows and the whole-site totals for the same window and slice.",
      "grain": "One date range × the whole site.",
      "dimensions": [
        "search type",
        "source medium"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "cannibalization-report",
        "content-performance-report",
        "keyword-ranking-report",
        "weekly-search-report"
      ],
      "skills": [
        "quattr-iq",
        "anomaly-investigator"
      ],
      "verbs": [
        "search_performance"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2"
      ],
      "questions": [
        "Why is our keyword-level total smaller than our site total?",
        "How much of our traffic can be attributed to specific keywords?"
      ],
      "interpretation": "The reason two correct numbers on the same card disagree. Anything computed on ranked keyword rows, site average position, a branded or non-branded rollup, a keyword worklist, describes only the attributable share of the site, while clicks and impressions beside it describe all of it. The gap is anonymized and unranked demand, not loss.",
      "caveats": [
        "No verb computes or returns this ratio; the routing code records an observed range of roughly 64 to 70% of site clicks on the tenants it was checked against, and the underlying formula is not implemented anywhere in this repository.",
        "It varies by tenant, by window and by slice, so a recorded range is a prior and not a value to quote for a specific account.",
        "The keyword-attributed rollup returns its own coverage note on every response that uses it, that note, not this ratio, is what should travel with a number."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Treating the gap between a brand rollup and a site total as missing data or a bug.",
        "Quoting a remembered coverage percentage for a specific account instead of running the two reads."
      ],
      "notSameAs": [],
      "related": [
        "avg-position",
        "clicks",
        "unique-keywords"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "clicks",
      "name": "Organic clicks",
      "aliases": [
        "Clicks",
        "Total clicks",
        "Search Console clicks"
      ],
      "definition": "The number of times someone clicked through to your site from a Google results page, as counted by Search Console.",
      "category": "Search performance",
      "type": "raw measure",
      "unit": "clicks",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "`nvl(sum(clicks), 0)`, a plain sum of the Search Console click column across whichever rows the query selects.",
      "aggregation": "Sums across rows and across dates. The underlying tables blend organic and paid, so a click total is only organic because the query pins the traffic source to google/organic; without that pin it silently reports organic plus paid.",
      "grain": "One date range × the selected slice, whole site, one keyword, or one page.",
      "dimensions": [
        "query",
        "page",
        "country",
        "device",
        "intent",
        "category",
        "brand",
        "rank bucket",
        "search type",
        "traffic source"
      ],
      "requiredFilters": [
        "date range",
        "source medium"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "ai-overview-report",
        "cannibalization-report",
        "competitor-search-report",
        "content-decay-report",
        "content-performance-report",
        "core-web-vitals-report",
        "ctr-opportunity-report",
        "internal-linking-report",
        "keyword-ranking-report",
        "monthly-executive-search-report",
        "paid-organic-overlap-report",
        "search-market-share-report",
        "search-opportunity-report",
        "search-to-revenue-report",
        "serp-volatility-report",
        "technical-seo-audit-report",
        "weekly-search-report"
      ],
      "skills": [
        "search-pulse",
        "weekly-search-report",
        "rank-movement-review",
        "cannibalization-check",
        "search-to-revenue"
      ],
      "verbs": [
        "search_performance",
        "gsc_breakdown",
        "seo_ranking_movement_report",
        "compare_periods"
      ],
      "rungs": [
        "R2",
        "R5"
      ],
      "levers": [
        "L2",
        "L3"
      ],
      "questions": [
        "How many organic clicks did we get last month?",
        "What were our non-brand organic clicks last week?",
        "Which pages earned the most clicks in the last 28 days?",
        "Break organic clicks down by country"
      ],
      "interpretation": "The demand you actually captured. Read it next to impressions and average position before calling it a win or a loss: clicks can fall while impressions rise (you entered more results pages and earned fewer of them) and clicks can rise while your standing against competitors falls. A week-over-week move is descriptive until a significance test has run on it.",
      "caveats": [
        "Search Console omits query-level rows below a privacy threshold, so a breakdown by query sums to less than the site total. The difference is the omission, not an error.",
        "A branded or intent slice at site grain is a keyword-attributed rollup: clicks from anonymized or unranked queries are excluded from that total, so it is smaller than the unsliced site total by construction.",
        "Every routed query pins search type to web unless a search type is supplied, so image, video and news clicks sit outside these totals.",
        "Where the customer is entitled to it, the Search Console BigQuery export carries far more of the long tail and will not match the API-sourced number, it is a deliberate switch, not an upgrade applied silently."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Reconciling a query-level breakdown to the site total and treating the shortfall as missing data.",
        "Dropping the organic medium pin and reporting a blended organic-plus-paid number as organic.",
        "Summing a keyword-attributed brand rollup and an unsliced site total as if they shared a denominator."
      ],
      "notSameAs": [],
      "related": [
        "impressions",
        "ctr",
        "avg-position",
        "pop-delta"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "impressions",
      "name": "Organic impressions",
      "aliases": [
        "Impressions",
        "Total impressions"
      ],
      "definition": "The number of times one of your results appeared on a Google results page for a search, whether or not anyone clicked it.",
      "category": "Search performance",
      "type": "raw measure",
      "unit": "impressions",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "`nvl(sum(impressions), 0)`, a plain sum of the Search Console impression column across the selected rows.",
      "aggregation": "Sums across rows and dates. It is also the weight behind average position and behind every CTR figure in this reference, so it should never be filtered differently from the metric it weights.",
      "grain": "One date range × the selected slice, whole site, one keyword, or one page.",
      "dimensions": [
        "query",
        "page",
        "country",
        "device",
        "intent",
        "category",
        "brand",
        "rank bucket",
        "search type"
      ],
      "requiredFilters": [
        "date range",
        "source medium"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "ai-overview-report",
        "cannibalization-report",
        "competitor-search-report",
        "content-decay-report",
        "content-performance-report",
        "ctr-opportunity-report",
        "internal-linking-report",
        "keyword-ranking-report",
        "paid-organic-overlap-report",
        "search-opportunity-report",
        "technical-seo-audit-report",
        "weekly-search-report"
      ],
      "skills": [
        "search-pulse",
        "weekly-search-report",
        "rank-movement-review",
        "striking-distance-sprint",
        "cannibalization-check"
      ],
      "verbs": [
        "search_performance",
        "gsc_breakdown",
        "seo_ranking_movement_report",
        "compare_periods"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2",
        "L5"
      ],
      "questions": [
        "Did our impressions grow last month?",
        "Which keywords have impressions but almost no clicks?",
        "Impressions by device for non-brand demand"
      ],
      "interpretation": "The Retrieved rung in one number: whether you enter the pool a ranking system draws from at all. Rising impressions with flat clicks usually means you entered more results pages at positions that do not earn, which is a position or a snippet question, not a demand question.",
      "caveats": [
        "Google's September 2025 num=100 reporting change moved the impression baseline. Windows that straddle it produce artifact movement in impressions and average position, and comparisons across it need re-cutting rather than narrating.",
        "Privacy-suppressed query rows are omitted from query-level breakdowns; the BigQuery export groups those impressions under a placeholder query instead.",
        "Search type defaults to web, so image, video and news impressions are excluded unless asked for."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Narrating an impression spike that is a reporting-change artifact as a demand event.",
        "Comparing impressions across a window boundary where the reporting basis changed."
      ],
      "notSameAs": [],
      "related": [
        "clicks",
        "ctr",
        "avg-position",
        "unique-keywords"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "pop-delta",
      "name": "Period-over-period change",
      "aliases": [
        "Delta",
        "PoP change",
        "Change vs prior period"
      ],
      "definition": "The difference between a metric in the selected period and the same metric in a comparison period, computed from two identical queries that differ only in their date filter.",
      "category": "Search performance",
      "type": "derived metric",
      "unit": "the same unit as the metric being compared",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "delta = selected − comparison. Each side is rounded to two decimals before the subtraction; either side missing yields null rather than zero. The comparison leg is the selected leg's query with only the period filter value swapped, so every other filter is held identical.",
      "aggregation": "Computed per row and joined on the row key, the non-numeric columns of the result, never on row order, because the two periods return different key sets at page and query grain. Rows present in only one of the two periods get a null delta, not a delta against zero; only their counts are reported. Row-index pairing survives in exactly one place: a pure aggregate with no dimension columns, where both sides are a single row.",
      "grain": "One row key × the pair of periods.",
      "dimensions": [
        "query",
        "page",
        "country",
        "device",
        "intent",
        "category"
      ],
      "requiredFilters": [
        "date range",
        "comparison range"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "ai-overview-report",
        "cannibalization-report",
        "content-decay-report",
        "content-performance-report",
        "crawl-log-report",
        "keyword-ranking-report",
        "monthly-executive-search-report",
        "serp-volatility-report",
        "weekly-search-report"
      ],
      "skills": [
        "weekly-search-report",
        "rank-movement-review",
        "anomaly-investigator",
        "content-decay-refresh"
      ],
      "verbs": [
        "compare_periods",
        "search_performance",
        "gsc_breakdown",
        "seo_ranking_movement_report"
      ],
      "rungs": [
        "R2",
        "R5"
      ],
      "levers": [],
      "questions": [
        "How did clicks change versus the previous month?",
        "Compare last week to the week before by page",
        "Which categories lost the most impressions versus last quarter?"
      ],
      "interpretation": "A description of what changed, not a claim that it changed for a reason or that the change is distinguishable from noise. Comparisons hold every filter constant except the date, so a delta is only as like-for-like as the two windows are, unequal lengths, or a window that straddles a seasonal break, produce a real delta about the wrong thing.",
      "caveats": [
        "The comparison window is explicit; the assistant does date arithmetic rather than relying on relative expressions, so a mis-specified window silently produces a valid delta about the wrong period.",
        "Unmatched rows are counted and reported separately, and their delta is null rather than a number. Reading the unmatched count itself as a set of launches and collapses is the common misread, it is a coverage difference between two windows.",
        "Position deltas invert: a negative delta is an improvement."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Comparing a 28-day window to a calendar month and reading the length difference as performance.",
        "Substituting zero for an unmatched row's null delta and totalling it into a period change."
      ],
      "notSameAs": [
        {
          "slug": "real-noise-verdict",
          "why": "A delta states how far the number moved; a significance verdict states whether the move is distinguishable from noise at an alpha. The verdict is a p-value threshold only, no effect size is computed anywhere, so a significant change can be trivially small and a large delta can fail the test."
        }
      ],
      "related": [
        "pop-delta-pct",
        "ranking-movement",
        "clicks"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "pop-delta-pct",
      "name": "Period-over-period change, relative",
      "aliases": [
        "Delta %",
        "Percent change",
        "deltaPct"
      ],
      "definition": "The period-over-period change expressed relative to the comparison period rather than in the metric's own units.",
      "category": "Search performance",
      "type": "derived metric",
      "unit": "relative change",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "Computed per row from that row's own two values; null whenever the comparison value is zero, because the ratio is undefined rather than infinite.",
      "grain": "One row key × the pair of periods.",
      "dimensions": [
        "query",
        "page",
        "country",
        "device",
        "intent",
        "category"
      ],
      "requiredFilters": [
        "date range",
        "comparison range"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "ai-referral-traffic-report",
        "content-decay-report",
        "content-performance-report",
        "keyword-ranking-report",
        "monthly-executive-search-report",
        "weekly-search-report"
      ],
      "skills": [
        "weekly-search-report",
        "rank-movement-review",
        "significance-referee",
        "anomaly-investigator"
      ],
      "verbs": [
        "compare_periods",
        "search_performance",
        "gsc_breakdown",
        "significance_check"
      ],
      "rungs": [
        "R2",
        "R5"
      ],
      "levers": [],
      "questions": [
        "What was the percentage change in clicks versus last month?",
        "Which pages fell more than 20 percent?"
      ],
      "caveats": [
        "Null when the comparison value is zero, a row that went from nothing to something has no relative change, only an absolute one.",
        "Relative change on a small base is large by arithmetic; the movement classification and the significance verdict exist precisely because this number alone cannot rank findings."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Multiplying an already-percent value by 100 a second time, or reading a fraction as a percent, depending on which code path produced it.",
        "Ranking a worklist by relative change and filling it with rows that moved from two clicks to four."
      ],
      "notSameAs": [
        {
          "slug": "real-noise-verdict",
          "why": "A relative change is a magnitude; a significance verdict is a test result at an alpha. Neither implies the other, and no effect size is computed on either side."
        }
      ],
      "related": [
        "pop-delta",
        "ranking-movement"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ranking-movement",
      "name": "Ranking movement (gainers and losers)",
      "aliases": [
        "Movers",
        "Gainers and losers",
        "Movement report"
      ],
      "definition": "The classification of each keyword's period-over-period change into a gainer, a loser or flat, using a fixed relative threshold and the metric's own good direction.",
      "category": "Search performance",
      "type": "derived metric",
      "unit": "keywords classified as gainers, losers or flat",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "A row is classified a gainer when its relative change moves at least 10% in the metric's good direction and a loser when it moves at least 10% the other way. Direction is metric-aware: for clicks and impressions a rise is a gain, for average position a FALL is a gain because lower is better. Each side is then sorted on the delta in the metric's own units, signed, not its absolute value, best improvement first for gainers and worst first for losers, and cut to the top 20. Membership is decided on the relative change; the ordering and the cut are decided on the unit change.",
      "aggregation": "Per keyword, from the two-period join. The flat count is whatever is left after the two TRUNCATED lists, rows are excluded from the classification only when their delta is null, so the three numbers add up to the matched rows without describing them: the 21st gainer is counted as flat.",
      "grain": "One keyword (or the single site row when run at site scope) × the pair of periods.",
      "dimensions": [
        "query",
        "page",
        "intent",
        "category"
      ],
      "requiredFilters": [
        "date range",
        "comparison range"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "cannibalization-report",
        "content-decay-report",
        "keyword-ranking-report",
        "serp-volatility-report",
        "weekly-search-report"
      ],
      "skills": [
        "rank-movement-review",
        "weekly-search-report",
        "content-decay-refresh",
        "anomaly-investigator"
      ],
      "verbs": [
        "seo_ranking_movement_report"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L3"
      ],
      "questions": [
        "Which keywords gained the most rankings this month?",
        "What were our biggest click losers versus last month?",
        "Show me gainers and losers by position"
      ],
      "interpretation": "The what-moved table. The ±10% cut is a product convention that keeps the list readable, and the direction handling is what stops a keyword climbing from position 8 to 3 being filed as a loss. Treat the lists as candidates for a cause hunt, not as a set of findings.",
      "caveats": [
        "Flat is not a synonym for did not move. It is the arithmetic remainder after each list is cut to 20, so every mover beyond the twentieth is counted as flat. On a wide keyword set the flat number is mostly movement.",
        "The ±10% threshold is a fixed convention, not a statistical test, a ten percent move on three clicks clears it as readily as one on three thousand.",
        "Keywords present in only one of the two periods carry a null delta and are dropped from the classification entirely, they are in none of the three groups, and only their counts are reported. The response's own unmatched caveat says those deltas are measured against zero; they are not.",
        "The lists are ranked on the unit delta while membership is decided on the relative change, so the ordering is not the ordering of the ±10% test.",
        "At site scope there are no per-keyword rows at all and the single aggregate is labelled as the site total."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Narrating the top of the gainers list as an achievement without the significance gate.",
        "Reading a position gainer as a rise because the delta is negative.",
        "Quoting the flat count as the number of keywords that held steady.",
        "Assuming the list covers every keyword rather than the top rows of each side."
      ],
      "notSameAs": [
        {
          "slug": "real-noise-verdict",
          "why": "Movement classification is a fixed ±10% cut on the relative change; a significance verdict is a two-sample test at an alpha. Being a gainer says nothing about whether the change is distinguishable from noise, and no effect size is computed on either side."
        },
        {
          "slug": "serp-volatility-index",
          "why": "Opposite subjects. This sorts your own keywords into gainers and losers, it describes you. A volatility index describes how much the results pages moved across a tracked market, including every domain on them. A quiet market with heavy movement on your set means something you did; a loud market with the same movement usually does not. Reading either one alone answers the update question wrongly.",
          "mirroredFrom": "serp-volatility-index"
        }
      ],
      "related": [
        "pop-delta",
        "pop-delta-pct",
        "avg-position",
        "clicks",
        "serp-volatility-index"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "unique-keywords",
      "name": "Unique keywords",
      "aliases": [
        "Total keywords",
        "Unique keyword count"
      ],
      "definition": "How many distinct keywords produced at least one impression for the site in the period.",
      "category": "Search performance",
      "type": "raw measure",
      "unit": "distinct keywords",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "`NULLIF(COUNT(DISTINCT keyword), 0)` on the keyword-and-page combined table.",
      "aggregation": "A distinct count. It never sums, two periods' counts do not add, and the counts of two slices do not add to the count of their union.",
      "grain": "One date range × the whole site.",
      "dimensions": [
        "brand",
        "intent",
        "search type"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "cannibalization-report",
        "content-performance-report",
        "keyword-ranking-report",
        "weekly-search-report"
      ],
      "skills": [
        "weekly-search-report",
        "monthly-exec-review",
        "quattr-iq"
      ],
      "verbs": [
        "search_performance"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2",
        "L5"
      ],
      "questions": [
        "How many unique keywords do we rank for?",
        "How many non-brand keywords did we appear for last month?"
      ],
      "interpretation": "Coverage of the demand pool rather than performance within it, the breadth half of the Retrieved rung. It moves with content footprint and with seasonality of the long tail, so a rise is a coverage signal and not a traffic signal.",
      "caveats": [
        "Only the keyword-and-page combined table serves this correctly. The keyword-only rollup reads a larger keyword universe and over-counts to the point where a non-brand slice exceeded the all-searches total on two live tenants, which is impossible for a subset, so branded and intent slices are deliberately routed to the keyword-and-page table.",
        "It cannot be requested in the same query as clicks, impressions, CTR or position: the count metrics live on a different dataset and the query assembler refuses the mix rather than returning a wrong field.",
        "Privacy-suppressed queries are not counted, so this is distinct keywords that were reported, not distinct keywords that existed."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Summing the count across weeks to produce a quarter.",
        "Comparing a branded and a non-branded count and expecting them to add to the total."
      ],
      "notSameAs": [],
      "related": [
        "unique-pages",
        "impressions",
        "keyword-page-click-coverage"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "unique-pages",
      "name": "Unique pages",
      "aliases": [
        "Total pages",
        "Unique page count"
      ],
      "definition": "How many distinct pages of your site earned at least one impression in the period.",
      "category": "Search performance",
      "type": "raw measure",
      "unit": "distinct pages",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "`NULLIF(COUNT(DISTINCT page), 0)` on the keyword-and-page combined table.",
      "aggregation": "A distinct count, never summed across periods or slices.",
      "grain": "One date range × the whole site.",
      "dimensions": [
        "brand",
        "intent",
        "search type"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "search-console"
      ],
      "reports": [
        "cannibalization-report",
        "content-decay-report",
        "content-performance-report",
        "internal-linking-report",
        "keyword-ranking-report",
        "weekly-search-report"
      ],
      "skills": [
        "weekly-search-report",
        "content-decay-refresh",
        "linking-opportunity-review"
      ],
      "verbs": [
        "search_performance"
      ],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L4",
        "L5"
      ],
      "questions": [
        "How many pages of ours actually get impressions?",
        "How many unique pages earned non-brand impressions last month?"
      ],
      "interpretation": "How much of the published site is doing any work in search at all. Read beside the crawl's page count, the gap between published and appearing is the indexation and linking question rather than a ranking one.",
      "caveats": [
        "The measure is dead on the keyword-only rollup table, that table has no page column, so a branded or intent rollup of this count is routed to the keyword-and-page table and must never be redirected to the keyword-only one.",
        "It cannot be requested alongside clicks, impressions, CTR or position; the assembler refuses the mix.",
        "Pages that were crawled but never surfaced in a results page do not appear here at all."
      ],
      "freshness": "1 to 2 days behind, Google's own reporting lag. Any answer touching the last 48 hours says so on the card.",
      "failureModes": [
        "Reading a null as zero pages when the distinct count is empty.",
        "Comparing this count to a crawl's page count as if the two measured the same thing."
      ],
      "notSameAs": [],
      "related": [
        "unique-keywords",
        "impressions"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "domain-movers-count",
      "name": "Domain movers",
      "aliases": [
        "SERP-wide movers",
        "Domains gaining and losing page-one space",
        "Market movers"
      ],
      "definition": "Which domains gained or lost results-page presence across the tracked demand during a window, the answer to 'who benefited' when the market moved.",
      "category": "SERP volatility",
      "type": "raw measure",
      "unit": "domains observed moving, each carrying its own presence counts",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "One row per domain per day per platform and results-page feature, carrying summed slot, query and URL counts. There is no movers measure at all; a count of movers is something the reader assembles by choosing a movement cut-off.",
      "grain": "One domain, on one day, for one platform and results-page feature.",
      "dimensions": [
        "domain",
        "platform",
        "results-page feature",
        "date"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "serp-volatility-report"
      ],
      "skills": [
        "update-week-check",
        "competitor-deep-dive",
        "anomaly-investigator"
      ],
      "verbs": [],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2"
      ],
      "questions": [
        "Which kinds of sites gained during the update?",
        "Who took the space we lost?",
        "Did publishers or retailers benefit?"
      ],
      "caveats": [
        "The set of domains is whatever appeared on the tracked results pages, not a curated competitor set, most movers will not be competitors in any commercial sense.",
        "A domain gaining presence on a tracked demand set is not a domain gaining traffic; presence is slots on a page, and click behaviour is not observed here.",
        "There is no movement threshold in the data, and no movers measure in the dataset: \"a mover\" is a judgement the reader imposes, so two readers produce different mover counts from the same day."
      ],
      "freshness": "~1 day behind, daily observation, available the following day.",
      "failureModes": [
        "Quoting a mover count as if the threshold were defined in the product.",
        "Treating publisher and community domains that gained space as addressable competitors.",
        "Reading presence gains as traffic gains."
      ],
      "notSameAs": [],
      "related": [
        "serp-volatility-index",
        "page-one-footprint-retention",
        "competitor-share-by-rank-bucket",
        "market-share-leader"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "page-one-footprint-retention",
      "name": "Page-one footprint retention",
      "aliases": [
        "Page-one retention",
        "Footprint retention",
        "Page-one slots held"
      ],
      "definition": "How much of the page-one presence held in an earlier window is still held now, whether a market event cost you standing space or merely rearranged it.",
      "category": "SERP volatility",
      "type": "rate",
      "unit": "a retention percentage against the comparison window",
      "direction": "higher-better",
      "verification": "review",
      "aggregation": "A comparison between two windows of results-page observations, averaged across the rows in scope. Retention percentages do not average across formats meaningfully; each format's retention is against its own comparison base.",
      "grain": "One content format, across a current window and a comparison window.",
      "dimensions": [
        "content format"
      ],
      "requiredFilters": [
        "date range",
        "comparison date range"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "serp-volatility-report"
      ],
      "skills": [
        "update-week-check",
        "market-share-review",
        "anomaly-investigator"
      ],
      "verbs": [],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2"
      ],
      "questions": [
        "Did we keep our page-one space through the update?",
        "Which content formats lost page-one ground?"
      ],
      "caveats": [
        "Retention is against a chosen comparison window, so the reading changes with the window, a quiet comparison base makes an ordinary week look like a collapse.",
        "Slots are results-page positions, not clicks: holding the same footprint through a layout change can still cost traffic.",
        "The dataset carries a retention percentage and a separate share-retention index among eight related figures. They are different readings and must not be quoted interchangeably.",
        "Content format is the only dimension on it. There is no platform, country or device axis, so a cut by those is not something this dataset can answer."
      ],
      "freshness": "~1 day behind, daily observation, available the following day.",
      "failureModes": [
        "Comparing retention figures computed against different comparison windows.",
        "Reading a retained footprint as retained traffic.",
        "Averaging per-format retention into a site figure.",
        "Quoting the share-retention index as though it were the retention percentage."
      ],
      "notSameAs": [],
      "related": [
        "serp-volatility-index",
        "domain-movers-count",
        "ranked-keyword-coverage",
        "search-market-share"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "serp-volatility-index",
      "name": "SERP volatility index",
      "aliases": [
        "Volatility index",
        "SERP turbulence",
        "Search results churn"
      ],
      "definition": "A market-level reading of how much the results pages themselves moved across a tracked demand set, the number you check to find out whether a drop was yours or everyone's.",
      "category": "SERP volatility",
      "type": "score",
      "unit": "not established",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "A daily market-level reading, averaged across the rows in the period. It is not a per-keyword measure and does not aggregate up from one; averaging days to describe a week flattens exactly the spike the index exists to show.",
      "grain": "One day and one country, for the demand set the index is built over.",
      "dimensions": [
        "date",
        "country",
        "derivation method"
      ],
      "requiredFilters": [
        "date range"
      ],
      "sources": [
        "rank-tracking"
      ],
      "reports": [
        "serp-volatility-report"
      ],
      "skills": [
        "update-week-check",
        "anomaly-investigator",
        "significance-referee"
      ],
      "verbs": [],
      "rungs": [
        "R2"
      ],
      "levers": [
        "L2"
      ],
      "questions": [
        "Was that drop us or was it everyone?",
        "How volatile were results this week?",
        "Did something market-wide happen on that date?"
      ],
      "caveats": [
        "Any such index is built over a tracked keyword set, so it describes that market and not the web, an index built on one cohort is not a general web-volatility reading.",
        "A confirmed algorithm-update announcement and a movement in the data are separate facts; a spike in the same window is correlation, and rollouts run for weeks.",
        "There is more than one score. The dataset carries a volatility score, a proxy score and a structure-movement score side by side, plus a dimension naming the derivation method, so \"the index\" is several readings that must not be compared as one series.",
        "It is keyed by date and country only. There is no platform, content-format or device axis on it, so a cut by those is not something this dataset can answer."
      ],
      "freshness": "~1 day behind, daily observation, available the following day.",
      "failureModes": [
        "Quoting a volatility number as though it were an industry-wide index rather than a reading over one tracked set.",
        "Attributing a movement to a named update because the two share a week.",
        "Comparing readings produced by different derivation methods as one series."
      ],
      "notSameAs": [
        {
          "slug": "ranking-movement",
          "why": "Opposite subjects. Ranking movement is your own keywords sorted into gainers and losers, it describes you. A volatility index describes the results pages across a tracked market, including every domain on them. Reading a quiet volatility index as 'we did not move', or a loud one as 'we were hit', inverts what each measures; the pair is only informative read together, which is the whole reason the update question exists."
        }
      ],
      "related": [
        "domain-movers-count",
        "page-one-footprint-retention",
        "search-market-share",
        "overall-average-rank"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "conversion-rate-change",
      "name": "Conversion-rate change",
      "aliases": [
        "Conversion rate delta",
        "Conversion rate period over period"
      ],
      "definition": "The difference between a period's conversion rate and a comparison period's, reported alongside both rates and their underlying counts.",
      "category": "Statistics",
      "type": "derived metric",
      "unit": "difference between two rates, on whatever scale the underlying rate measure carries, rounded to two decimal places",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "The rate under test is the product's OWN displayed conversion-rate measure, conversions divided by unique users, or, on tenants whose analytics supply a stored per-row rate, the average of those stored rates. Both periods' rates are fetched as the product's weighted period aggregates and the change is the selected rate minus the comparison rate, rounded to two decimal places. A relative form is reported beside it as a percentage to two decimal places. Both period rates are echoed in the response so the subtraction is checkable.",
      "numerator": "Selected-period rate minus comparison-period rate",
      "denominator": "Each rate's own denominator is set by the underlying measure: unique users, or none at all where the measure is an average of stored per-row rates",
      "aggregation": "Computed once from the two periods' weighted aggregates, not averaged over buckets, the per-bucket series exists but is used for the significance test, not for the change.",
      "grain": "One value per pair of date ranges.",
      "dimensions": [],
      "requiredFilters": [
        "date_range",
        "comparison_range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "ai-referral-traffic-report",
        "search-to-revenue-report"
      ],
      "skills": [
        "significance-referee",
        "anomaly-investigator",
        "search-to-revenue"
      ],
      "verbs": [
        "pop_significance"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [],
      "questions": [
        "Did conversion rate really change versus last month?",
        "How much did conversion rate move?"
      ],
      "interpretation": "The size of the move, kept separate from whether the move is distinguishable from noise. Read it beside the p-value and the verdict: a large change on thin traffic and a small change on heavy traffic can carry the same p-value, and only the pair tells the story. Because it is the difference between the two numbers the product itself displays, it should reconcile against the product UI exactly, which is the point of it.",
      "caveats": [
        "The change and the significance test are computed on DIFFERENT quantities. The change is the difference between two weighted period aggregates; the test compares equal-weight per-bucket means. When traffic weights shift between periods those two can move in opposite directions, and when they do the tool refuses to transfer the verdict, it returns a can't-tell for the displayed rate and withholds the significance flag rather than making a claim about a quantity the test did not measure.",
        "The denominator is not sessions. It is unique users, or, on tenants whose analytics supply a stored per-row rate, no explicit denominator at all, the measure is an average of stored rates. A change computed against a session-based rate will not match this one.",
        "It is a difference between two rates, not a percentage-point figure and not a percent change, the relative form is a separate field with its own scale problem.",
        "Fewer than two buckets in either period, or no within-period variation, returns a can't-tell with an explanatory note; the aggregate change is still reported, because it was already known before the test was attempted.",
        "Whole-domain only; a non-default segment returns a note explaining the limitation.",
        "The result is stamped observational in the payload."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Reconstructing the rate as conversions over sessions and comparing the two.",
        "Reading the value as percentage points.",
        "Presenting a significance verdict for the displayed change when the tool withheld one because the two quantities disagreed in direction.",
        "Quoting the change without the verdict beside it."
      ],
      "notSameAs": [
        {
          "slug": "conversion-rate",
          "why": "One is a level for a single period; the other is the difference between two of those levels. They share a definition and a denominator, what differs is the question, and the fact that only the change carries a significance verdict."
        },
        {
          "slug": "rate-change-percent",
          "why": "One is an absolute difference between two rates, in percentage points; the other expresses that difference relative to the comparison period. Confirm which you have before quoting it, they answer different questions and are not interchangeable."
        }
      ],
      "related": [
        "conversion-rate",
        "rate-change-percent",
        "significance-p-value",
        "real-noise-verdict"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "funnel-dropoff-rate",
      "name": "Funnel drop-off rate",
      "aliases": [
        "Step drop-off",
        "Biggest leak"
      ],
      "definition": "The share of a funnel step's count that did not carry through to the next step, plus the step where the largest single drop occurs.",
      "category": "Statistics",
      "type": "rate",
      "unit": "fraction of the previous step's count",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "The caller supplies an ordered list of steps, each an existing web-analytics count metric. Each step's total is fetched, and in the compute engine the drop-off for a step is the previous step's count minus this step's, divided by the previous step's count. The first step has no previous step and returns nothing; a previous count of zero returns nothing rather than dividing. The biggest leak is the largest drop-off among the legs that have one.",
      "numerator": "Previous step count minus this step count",
      "denominator": "Previous step count",
      "aggregation": "Computed per consecutive pair over already-aggregated step totals.",
      "grain": "One rate per step after the first, per date range.",
      "dimensions": [],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "search-to-revenue-report"
      ],
      "skills": [
        "search-to-revenue",
        "anomaly-investigator"
      ],
      "verbs": [
        "funnel_dropoff"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [],
      "questions": [
        "Where do users fall out of the funnel?",
        "Which step leaks the most?"
      ],
      "interpretation": "Where the funnel loses people, at aggregate grain. Locating the leak comes before recommending anything, a step with a large drop and small volume is a different problem from a small drop on the whole audience. The canonical macro-funnel runs sessions to conversions to transactions.",
      "caveats": [
        "Direction is published as neutral because the shipped renderers disagree with the arithmetic. More drop-off is plainly worse, but neither shared oracle knows the field: one finds no classifying word in its name and falls through to its higher-is-better default, and the other classifies it as a plain count with no unit at all, so a rising leak can be painted as an improvement, and a fraction can be rendered as though it were a number of things. Never let the automatic colouring or formatting speak for this field.",
        "This is a macro-funnel over aggregate counts, not a per-user event sequence. Drop-off is the relative decline between consecutive totals and is directional, not a per-user retention rate. The tool carries this caveat in its own payload.",
        "Steps can span two different traffic scopes. Behavioural steps are read on organic search traffic while conversion and transaction steps are read across all traffic sources, mirroring the product's own card defaults, so a mixed funnel compares populations, and an all-source conversion count can legitimately exceed an organic session count above it. The tool discloses this when it happens.",
        "There is no ordered step or event dimension in the model, so the caller supplies the order. A different step order produces different drop-offs from the same data, and the tool does not validate that the order is a real funnel.",
        "Steps are drawn from a fixed list of count metrics, sessions, users, conversions, transactions, unique pageviews and events, and nothing else can be a step.",
        "Because the step counts come from differently constructed measures, some approximate distinct counts and some plain sums, a drop-off between two of them mixes estimator behaviour with real attrition.",
        "A step with no data is kept as absent and excluded from the arithmetic rather than counted as zero; fewer than two steps with data returns an explanatory note.",
        "Whole-domain only; the result is stamped observational."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Trusting the automatic direction or unit on this field, both are wrong, and a bigger leak can be painted as a win.",
        "Reading a drop-off as a per-user retention rate.",
        "Choosing an order that is not a real funnel and reporting the resulting leak.",
        "Comparing steps read on different traffic scopes without saying so.",
        "Reading a step count of zero as total attrition when the measure simply had no data."
      ],
      "notSameAs": [
        {
          "slug": "conversion-rate",
          "why": "Conversion rate is a single measured rate over users for the whole period; a funnel drop-off is the relative decline between two chosen aggregate counts. The end-to-end product of the drop-offs will not equal the conversion-rate measure."
        }
      ],
      "related": [
        "conversions-count",
        "sessions",
        "transactions",
        "conversion-rate"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "significance-p-value",
      "name": "p-value",
      "aliases": [
        "Significance value",
        "p"
      ],
      "definition": "The probability of seeing a difference at least this large if there were no real difference between the two periods or samples.",
      "category": "Statistics",
      "type": "statistical verdict",
      "unit": "probability between 0 and 1, rounded to six decimal places",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "One of two tests, chosen by sample size, and both run on per-bucket series rather than on period totals. Welch's two-sample t-test with Welch to Satterthwaite degrees of freedom is the default; where either period has fewer than eight buckets the cross-domain tool switches to the Mann to Whitney U rank test, using a normal approximation with a continuity correction. Conversion rate is no exception, it is tested with Welch's t-test over its per-bucket rate values, like every other metric. Both tests are computed in a pure module, never by the model.",
      "aggregation": "One p-value per test. It is never averaged, combined across tests, or carried between metrics.",
      "grain": "One value per test, a metric, a pair of date ranges, and a bucket size.",
      "dimensions": [],
      "requiredFilters": [
        "date_range",
        "comparison_range"
      ],
      "sources": [
        "search-console",
        "web-analytics",
        "google-ads",
        "rank-tracking",
        "lighthouse"
      ],
      "reports": [
        "weekly-search-report"
      ],
      "skills": [
        "significance-referee",
        "anomaly-investigator",
        "rank-movement-review",
        "monthly-exec-review",
        "cross-domain-correlator"
      ],
      "verbs": [
        "pop_significance",
        "significance_check",
        "correlate_domains"
      ],
      "rungs": [
        "R5",
        "R2"
      ],
      "levers": [],
      "questions": [
        "Is this drop real?",
        "Is the lift statistically significant?",
        "Can we trust this change?"
      ],
      "interpretation": "Evidence that a difference exists, and nothing more. It is not the probability the change is real, not a measure of how big the change is, and not a cause. Read it with the sample size beside it, the same p-value means something different at eight buckets and at eighty.",
      "caveats": [
        "No exact t-distribution is ever evaluated. The t-statistic is real, but its probability comes from a normal approximation with a Cornish to Fisher correction, documented in code as anti-conservative at small degrees of freedom: at five degrees of freedom the probability can be understated by roughly a quarter. Treat samples under ten as indicative rather than definitive.",
        "The Mann to Whitney probability also uses a normal approximation; the exact distribution would be preferable below about twenty observations.",
        "A pooled two-proportion test exists in the statistics module but nothing calls it. There is no count-based proportion test anywhere in the tool surface, a rate is tested as a series of bucket values, not as successes over trials, and the cross-domain tool records the proportion case as deferred.",
        "Every test compares per-bucket MEANS, not aggregate totals, a change in total driven by more buckets rather than bigger buckets will not show here, and where a displayed period aggregate moves opposite to the bucket means the rate-aware tool withholds the result rather than transferring it.",
        "The cross-domain tool needs at least two buckets per period and returns an explanatory note instead of a test below that.",
        "No multiple-comparison correction is applied anywhere. Testing many metrics or many rows will produce significant results by chance, and nothing in the tool surface adjusts for it.",
        "A significant change is still not a cause. The tools rule on existence, never on attribution."
      ],
      "freshness": "varies by site, priority URLs can run nightly; most pages far less often. The collection date rides on the card rather than being assumed.",
      "failureModes": [
        "Reading the p-value as the probability that the change is real.",
        "Running many tests and reporting the significant ones without noting that nothing corrected for the number of tests.",
        "Treating a small p-value as evidence of a large or important change."
      ],
      "notSameAs": [
        {
          "slug": "practical-effect-magnitude",
          "why": "The p-value speaks to whether a difference is distinguishable from noise; magnitude speaks to whether it matters. No effect size, minimum detectable effect or confidence interval is computed by any tool, so magnitude cannot be read off this number."
        },
        {
          "slug": "rate-change-percent",
          "why": "Evidence versus size. Neither implies the other, and reporting one in place of the other is the most common misreading of a significance result."
        }
      ],
      "related": [
        "significant-flag",
        "real-noise-verdict",
        "practical-effect-magnitude",
        "pearson-correlation"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "pearson-correlation",
      "name": "Pearson correlation",
      "aliases": [
        "Pearson r",
        "Linear correlation"
      ],
      "definition": "How closely two metrics move together in a straight-line sense, over aligned time buckets.",
      "category": "Statistics",
      "type": "statistical verdict",
      "unit": "coefficient between −1 and 1",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "Each metric is fetched as a bucketed series through a governed read, the two series are aligned on the shared time bucket in the compute engine, and the product-moment coefficient is computed on the aligned pairs. A t-statistic is formed from the coefficient with two fewer degrees of freedom than pairs, but its probability is NOT read from a t-distribution: the statistic is rescaled by a Cornish to Fisher term and fed to the standard normal curve. A perfect coefficient short-circuits to a probability of zero.",
      "numerator": "The covariance of the two aligned series",
      "denominator": "The product of their standard deviations",
      "aggregation": "One coefficient per pair of series. Coefficients are never averaged or chained.",
      "grain": "One value per metric pair, date range and bucket size.",
      "dimensions": [
        "bucket"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "search-console",
        "web-analytics",
        "google-ads",
        "rank-tracking",
        "lighthouse"
      ],
      "reports": [],
      "skills": [
        "cross-domain-correlator",
        "anomaly-investigator"
      ],
      "verbs": [
        "correlate_domains"
      ],
      "rungs": [
        "R5",
        "R2"
      ],
      "levers": [],
      "questions": [
        "Does page speed move with our clicks?",
        "Does search market share track traffic?"
      ],
      "interpretation": "A relationship, described in bounded language: correlates, moves with, consistent with. Never drives, causes or explains. Where the answer would drive spend or work, the correct next step is a designed test rather than a stronger adjective.",
      "caveats": [
        "The significance attached to the coefficient is approximate: a normal approximation with a Cornish to Fisher correction, which is anti-conservative at small degrees of freedom, at five, the probability can be understated by roughly a quarter. A cross-domain correlation often runs on a handful of aligned buckets, so treat a borderline significance on a short series as unproven.",
        "Correlation is not causation, and the payload carries that caveat with the sample size attached.",
        "Shared trends and confounds inflate it, two metrics that both rise seasonally will correlate without being related.",
        "It measures straight-line association only and is sensitive to outliers; the rank-based coefficient is the robust alternative and both are returned by default.",
        "At least three buckets are needed on each side and at least three aligned buckets after the join, or the tool returns an explanatory note instead of a coefficient.",
        "The two series are aligned by bucket, so the freshness of the slowest contributing source governs the whole read, page experience is the least predictable and is named when it is one of the pair.",
        "An insignificant coefficient is reported as no detectable relationship at this power, not as no relationship."
      ],
      "freshness": "varies by site, priority URLs can run nightly; most pages far less often. The collection date rides on the card rather than being assumed.",
      "failureModes": [
        "Describing the significance as a t-test result, no t-distribution is evaluated.",
        "Reading a strong coefficient as a causal mechanism.",
        "Correlating two metrics that share an obvious driver and reporting the result as a finding.",
        "Computing a coefficient by hand when the tool declined to and presenting it as a product number."
      ],
      "notSameAs": [
        {
          "slug": "spearman-correlation",
          "why": "Pearson measures straight-line association on the values; Spearman measures monotonic association on their ranks. They disagree exactly where the relationship is real but not linear, or where an outlier dominates."
        },
        {
          "slug": "practical-effect-magnitude",
          "why": "A coefficient describes the tightness of a relationship, not its business size, and no interval is computed around it."
        }
      ],
      "related": [
        "spearman-correlation",
        "significance-p-value"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "practical-effect-magnitude",
      "name": "Practical magnitude",
      "aliases": [
        "Effect size",
        "Minimum detectable effect",
        "Confidence interval"
      ],
      "definition": "How large a measured change is in terms that matter to a decision, an effect size, a minimum detectable effect, or an interval around the estimate.",
      "category": "Statistics",
      "type": "statistical verdict",
      "unit": "not produced",
      "direction": "neutral",
      "verification": "review",
      "grain": "Would be one value per test if it were produced.",
      "dimensions": [],
      "requiredFilters": [],
      "sources": [
        "search-console",
        "web-analytics",
        "google-ads",
        "rank-tracking",
        "lighthouse"
      ],
      "reports": [
        "ai-referral-traffic-report",
        "cannibalization-report",
        "content-decay-report",
        "content-performance-report",
        "internal-linking-report",
        "keyword-ranking-report",
        "monthly-executive-search-report",
        "paid-organic-overlap-report",
        "paid-search-performance-report",
        "search-market-share-report",
        "search-to-revenue-report",
        "serp-volatility-report",
        "weekly-search-report"
      ],
      "skills": [
        "significance-referee",
        "anomaly-investigator"
      ],
      "verbs": [],
      "rungs": [
        "R5"
      ],
      "levers": [],
      "questions": [
        "Is this change big enough to act on?",
        "What is the confidence interval?",
        "What change could we even have detected?"
      ],
      "caveats": [
        "No tool produces an effect size, a minimum detectable effect or a confidence interval.",
        "The absolute change and the relative change are available and are the closest thing to a magnitude read, but neither carries uncertainty around the estimate.",
        "No multiple-comparison correction is applied anywhere either, so a batch of significant results has no adjusted view to fall back on.",
        "When a magnitude question is asked, the answer is what exists, the change, the sample size and the verdict, plus a plain statement that the sizing statistics are not available."
      ],
      "freshness": "varies by site, priority URLs can run nightly; most pages far less often. The collection date rides on the card rather than being assumed.",
      "failureModes": [
        "Presenting a small p-value as evidence that a change is large.",
        "Computing an interval or an effect size outside the tools and presenting it as a product output.",
        "Reading the significance threshold as a minimum effect the test was designed to detect."
      ],
      "notSameAs": [
        {
          "slug": "significant-flag",
          "why": "The flag is the p-value below a threshold and nothing else. It carries no effect size, and none is computed anywhere, so significance can never stand in for magnitude."
        },
        {
          "slug": "significance-p-value",
          "why": "A p-value answers whether a difference is distinguishable from noise. Magnitude answers whether it is worth acting on. The tools produce the first and not the second."
        },
        {
          "slug": "real-noise-verdict",
          "why": "Real means distinguishable from noise, not large enough to act on. No effect size is computed anywhere, so the verdict says nothing about magnitude.",
          "mirroredFrom": "real-noise-verdict"
        },
        {
          "slug": "pearson-correlation",
          "why": "A coefficient describes the tightness of a relationship, not its business size, and no interval is computed around it.",
          "mirroredFrom": "pearson-correlation"
        }
      ],
      "related": [
        "significance-p-value",
        "significant-flag",
        "real-noise-verdict",
        "rate-change-percent"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "real-noise-verdict",
      "name": "Real, noise or can't-tell",
      "aliases": [
        "Verdict",
        "Significance verdict"
      ],
      "definition": "A three-way ruling on a period-over-period change: real, noise, or can't-tell.",
      "category": "Statistics",
      "type": "statistical verdict",
      "unit": "one of real, noise, can't-tell",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "Derived, never eyeballed. A p-value below the threshold gives real. Otherwise the sample is checked for adequate power: a null result with adequate power gives noise, and a null result without it gives can't-tell. Power is a floor, not a computed power figure, at least eight time buckets in each period, the same floor for every metric including conversion rate. One further route to can't-tell bypasses the p-value entirely: when the change in the displayed period aggregate and the change in the per-bucket means point in opposite directions, the test result is not transferred to the displayed number at all.",
      "aggregation": "One verdict per test.",
      "grain": "One verdict per test.",
      "dimensions": [],
      "requiredFilters": [
        "date_range",
        "comparison_range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "ai-overview-report",
        "ai-referral-traffic-report",
        "ai-visibility-report",
        "cannibalization-report",
        "competitor-search-report",
        "content-decay-report",
        "content-performance-report",
        "crawl-log-report",
        "ctr-opportunity-report",
        "keyword-ranking-report",
        "monthly-executive-search-report",
        "paid-organic-overlap-report",
        "paid-search-performance-report",
        "search-market-share-report",
        "search-to-revenue-report",
        "serp-volatility-report",
        "weekly-search-report"
      ],
      "skills": [
        "significance-referee",
        "anomaly-investigator",
        "monthly-exec-review"
      ],
      "verbs": [
        "pop_significance"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [],
      "questions": [
        "Is this drop real or just noise?",
        "Can we call this month a real improvement?"
      ],
      "interpretation": "The three-word vocabulary exists because two words are not enough: an underpowered null is not stability. Can't-tell means the test lacked the sample to find a change of the size that would matter, and it is the correct answer more often than teams expect on low-traffic segments. The vocabulary is fixed, probably real, trending significant and basically stable are not options.",
      "caveats": [
        "Power here is a fixed floor on the number of time buckets, not a computed statistical power figure. A change smaller than the floor could detect will still be called noise once the floor is cleared.",
        "The floor is eight buckets per period, and it is the same for every metric, there is no separate sample-size floor for rates, because rates are tested the same way as counts.",
        "Because the floor counts buckets, the bucket size chosen for the test decides whether a period is deemed powered at all. A month tested weekly cannot clear eight buckets; the same month tested daily clears it easily on the same data.",
        "Only the web-analytics period-over-period tool emits this verdict. The cross-domain tool returns a two-state flag, so a can't-tell there is reported as not significant.",
        "A real verdict is still not a cause; ruling on existence is the whole of the opinion.",
        "Too few buckets, or no variation within either period, produces a can't-tell with an explanatory note rather than a test result, and the change itself is still reported beside it."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Reporting a can't-tell as stable or unchanged.",
        "Reading the power floor as a computed power figure, or as a floor on traffic rather than on buckets.",
        "Comparing verdicts produced at different bucket sizes as though they were equally powered.",
        "Expecting a verdict from the cross-domain tool, which does not produce one."
      ],
      "notSameAs": [
        {
          "slug": "significant-flag",
          "why": "The flag has two states and collapses an underpowered null into the same answer as a well-powered one. The verdict keeps them apart, which is the entire reason it exists."
        },
        {
          "slug": "practical-effect-magnitude",
          "why": "Real means distinguishable from noise, not large enough to act on. No effect size is computed anywhere, so the verdict says nothing about magnitude."
        },
        {
          "slug": "pop-delta",
          "why": "A delta states how far the number moved; a significance verdict states whether the move is distinguishable from noise at an alpha. The verdict is a p-value threshold only, no effect size is computed anywhere, so a significant change can be trivially small and a large delta can fail the test.",
          "mirroredFrom": "pop-delta"
        },
        {
          "slug": "pop-delta-pct",
          "why": "A relative change is a magnitude; a significance verdict is a test result at an alpha. Neither implies the other, and no effect size is computed on either side.",
          "mirroredFrom": "pop-delta-pct"
        },
        {
          "slug": "ranking-movement",
          "why": "Movement classification is a fixed ±10% cut on the relative change; a significance verdict is a two-sample test at an alpha. Being a gainer says nothing about whether the change is distinguishable from noise, and no effect size is computed on either side.",
          "mirroredFrom": "ranking-movement"
        }
      ],
      "related": [
        "significant-flag",
        "significance-p-value",
        "conversion-rate-change"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "rate-change-percent",
      "name": "Relative change",
      "aliases": [
        "Relative period-over-period change",
        "Delta percent"
      ],
      "definition": "How large a period-over-period change is relative to the comparison period.",
      "category": "Statistics",
      "type": "derived metric",
      "unit": "relative change",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "Computed once per metric per comparison. Null when the comparison value is zero, so a growth-from-nothing case returns no relative change rather than an infinity.",
      "grain": "One value per metric per pair of date ranges, or one per breakdown row in a period-over-period breakdown.",
      "dimensions": [],
      "requiredFilters": [
        "date_range",
        "comparison_range"
      ],
      "sources": [
        "search-console",
        "web-analytics",
        "google-ads",
        "rank-tracking",
        "lighthouse"
      ],
      "reports": [],
      "skills": [
        "significance-referee",
        "anomaly-investigator",
        "rank-movement-review",
        "monthly-exec-review"
      ],
      "verbs": [
        "pop_significance",
        "significance_check",
        "paid_search_overview",
        "paid_impression_share",
        "web_analytics_overview",
        "conversions_overview",
        "site_health_cwv_check"
      ],
      "rungs": [
        "R5",
        "R2"
      ],
      "levers": [],
      "questions": [
        "How much did clicks change in percentage terms?",
        "What is the percent change versus last month?"
      ],
      "caveats": [
        "The scale is not consistent between producers, confirm which one a value came from before rendering it as a percentage.",
        "Null when the comparison value is zero, which is correct and is not the same as a zero change.",
        "It is a relative change, so a small absolute move on a small base produces a large value. Always pair it with the absolute change.",
        "It says nothing about whether a change is distinguishable from noise; that is the p-value's job."
      ],
      "freshness": "varies by site, priority URLs can run nightly; most pages far less often. The collection date rides on the card rather than being assumed.",
      "failureModes": [
        "Rendering a fraction-scaled value as a percent, or a percent-scaled value as a fraction, a hundredfold error in either direction.",
        "Reading a large relative change on a tiny base as a meaningful result.",
        "Treating a null as a zero change."
      ],
      "notSameAs": [
        {
          "slug": "conversion-rate-change",
          "why": "One is the absolute difference between two rates; this expresses a difference relative to its comparison base. On a small base the relative form can be dramatic while the absolute form is negligible."
        },
        {
          "slug": "significance-p-value",
          "why": "Size and evidence are different questions. A large relative change on thin data and a small one on heavy data routinely carry opposite p-values."
        }
      ],
      "related": [
        "conversion-rate-change",
        "significance-p-value",
        "significant-flag"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "significant-flag",
      "name": "Significant",
      "aliases": [
        "Statistically significant",
        "Significance flag"
      ],
      "definition": "A true or false flag set when the p-value falls below the chosen threshold.",
      "category": "Statistics",
      "type": "statistical verdict",
      "unit": "true or false, or absent",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "The p-value compared against the threshold, which defaults to 0.05 and is a caller-settable parameter. That comparison is the whole of the flag, nothing else feeds it. The one exception is a refusal rather than a computation: where the displayed period change and the per-bucket change point in opposite directions, the period-over-period tool emits no flag at all rather than attaching the bucket-level result to a number the test did not measure.",
      "aggregation": "One flag per test.",
      "grain": "One flag per test.",
      "dimensions": [],
      "requiredFilters": [
        "date_range",
        "comparison_range"
      ],
      "sources": [
        "search-console",
        "web-analytics",
        "google-ads",
        "rank-tracking",
        "lighthouse"
      ],
      "reports": [
        "keyword-ranking-report"
      ],
      "skills": [
        "significance-referee",
        "anomaly-investigator",
        "monthly-exec-review",
        "rank-movement-review"
      ],
      "verbs": [
        "pop_significance",
        "significance_check"
      ],
      "rungs": [
        "R5",
        "R2"
      ],
      "levers": [],
      "questions": [
        "Is that significant?",
        "Did it really change?"
      ],
      "interpretation": "A threshold crossing, not a judgment about importance. The threshold is a parameter, so a flag is only comparable against another flag computed at the same threshold. Where a decision is at stake, the verdict field is the better read, because it separates a well-powered null result from an underpowered one.",
      "caveats": [
        "The flag is the p-value below the threshold and nothing else. It carries no effect size, no minimum detectable effect and no confidence interval, none of those is computed anywhere in the tool surface.",
        "No multiple-comparison correction is applied, so a batch of tests will produce false flags at roughly the threshold rate.",
        "A false flag does not mean no change. The cross-domain tool reports only this flag, so an underpowered null there is indistinguishable from a well-powered one, the rate-aware tool's verdict field exists to make that distinction.",
        "The threshold is caller-settable, so two flags are only comparable when both used the same one.",
        "An absent flag is a third state, not a false one. It means the tool declined to attach a test result to the displayed change, and reading it as not-significant inverts the refusal into a finding.",
        "Significance is not causation."
      ],
      "freshness": "varies by site, priority URLs can run nightly; most pages far less often. The collection date rides on the card rather than being assumed.",
      "failureModes": [
        "Reading a false flag as evidence of stability.",
        "Treating an absent flag as a false one.",
        "Comparing flags computed at different thresholds.",
        "Reporting the significant rows from a large batch without noting that nothing corrected for the batch size."
      ],
      "notSameAs": [
        {
          "slug": "practical-effect-magnitude",
          "why": "This flag is a threshold crossing on a p-value only. No effect size is ever computed by any tool, so the flag cannot speak to whether a change is large enough to act on."
        },
        {
          "slug": "real-noise-verdict",
          "why": "The flag has two states; the verdict has three, because it separates a null result with adequate power from a null result without it. A false flag can mean either."
        }
      ],
      "related": [
        "significance-p-value",
        "real-noise-verdict",
        "practical-effect-magnitude"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "spearman-correlation",
      "name": "Spearman correlation",
      "aliases": [
        "Spearman rho",
        "Rank correlation"
      ],
      "definition": "How closely two metrics move together in rank order, over aligned time buckets.",
      "category": "Statistics",
      "type": "statistical verdict",
      "unit": "coefficient between −1 and 1",
      "direction": "neutral",
      "verification": "verified",
      "calculation": "Both aligned series are converted to ranks, with tied values sharing an average rank, and the product-moment coefficient is then computed on those ranks, it is literally the value-based routine applied to ranks. The probability is produced the same way too, which means it inherits the same normal approximation rather than an exact distribution.",
      "aggregation": "One coefficient per pair of series.",
      "grain": "One value per metric pair, date range and bucket size.",
      "dimensions": [
        "bucket"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "search-console",
        "web-analytics",
        "google-ads",
        "rank-tracking",
        "lighthouse"
      ],
      "reports": [],
      "skills": [
        "cross-domain-correlator",
        "anomaly-investigator"
      ],
      "verbs": [
        "correlate_domains"
      ],
      "rungs": [
        "R5",
        "R2"
      ],
      "levers": [],
      "questions": [
        "Do citations and sessions move together?",
        "Is the relationship robust to outliers?"
      ],
      "interpretation": "The robust reading of the same question. Because it works on ranks, a single extreme week cannot dominate it and a real but curved relationship still shows. When the two coefficients disagree sharply, that disagreement is itself the finding.",
      "caveats": [
        "Its significance carries the same approximation as the value-based coefficient: a normal approximation with a Cornish to Fisher correction, anti-conservative on short series and never stated on the card. It is also the standard coefficient's probability formula applied to ranks, which is a further approximation on top.",
        "Correlation is not causation; the same caveat and sample size ride on the payload.",
        "Ranking discards magnitude, so a relationship that is strong in rank order can be small in absolute terms.",
        "Ties share an average rank, which flattens the coefficient on series with many repeated values.",
        "Same minimum of three buckets per side and three aligned buckets as the value-based coefficient.",
        "An insignificant coefficient is reported as no detectable relationship at this power."
      ],
      "freshness": "varies by site, priority URLs can run nightly; most pages far less often. The collection date rides on the card rather than being assumed.",
      "failureModes": [
        "Reading rank agreement as proportional movement.",
        "Reporting whichever of the two coefficients is larger without saying which was used."
      ],
      "notSameAs": [
        {
          "slug": "pearson-correlation",
          "why": "Spearman works on ranks and Pearson on values. Where they disagree, the relationship is either non-linear or outlier-driven, and reporting only one hides that."
        }
      ],
      "related": [
        "pearson-correlation",
        "significance-p-value"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "average-session-duration",
      "name": "Average session duration",
      "aliases": [
        "Avg session length"
      ],
      "definition": "The average length of a visit in the period, as recorded by your web-analytics source.",
      "category": "Web analytics and conversions",
      "type": "raw measure",
      "unit": "seconds (inferred from the field name, not declared in the semantic layer)",
      "direction": "higher-better",
      "verification": "inferred",
      "aggregation": "An average of a per-row session-duration column supplied by the analytics export, with nulls read as zero. Unweighted, so low-traffic rows count as much as high-traffic ones.",
      "grain": "One number per date range, or one row per breakdown value.",
      "dimensions": [
        "country",
        "device",
        "page",
        "keyword",
        "source_medium",
        "intent",
        "category"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [],
      "skills": [
        "search-to-revenue"
      ],
      "verbs": [
        "web_analytics_overview"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [],
      "questions": [
        "How long do visits last?",
        "Session duration by device?"
      ],
      "interpretation": "An engagement signal rather than an outcome. It is one of the two measures the engagement shorthand expands to, so it appears in default responses alongside bounce rate. Treat movement in it as a prompt to look at behaviour, not as a result in itself.",
      "caveats": [
        "The unit is not declared anywhere in the semantic layer; seconds is inferred from the field name and the way the shared format contract classifies duration fields. Do not present the unit as established.",
        "The measure's own label in the semantic layer reads \"Average Sessions\", which is a mislabel, it is a duration, not a session count.",
        "An unweighted average of a per-row column; nulls are read as zero, so a zero can mean no engagement or no data.",
        "Whole-domain only today."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Reading the mislabelled measure name and reporting a session count.",
        "Stating the unit as seconds without the caveat."
      ],
      "notSameAs": [
        {
          "slug": "average-time-on-page",
          "why": "One averages the length of a whole visit, the other averages time on a single page. They come from different columns and answer different questions."
        },
        {
          "slug": "bounce-rate",
          "why": "Both are surfaced together under the engagement shorthand, but one is a rate over visits and one is a duration. They move independently and are reported as separate columns.",
          "mirroredFrom": "bounce-rate"
        }
      ],
      "related": [
        "average-time-on-page",
        "bounce-rate",
        "sessions"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "average-time-on-page",
      "name": "Average time on page",
      "aliases": [
        "Avg time on page"
      ],
      "definition": "The average time visitors spent on a page in the period, as recorded by your web-analytics source.",
      "category": "Web analytics and conversions",
      "type": "raw measure",
      "unit": "seconds (inferred from the field name, not declared in the semantic layer)",
      "direction": "higher-better",
      "verification": "inferred",
      "aggregation": "An unweighted average of a per-row time-on-page column supplied by the analytics export, with nulls read as zero.",
      "grain": "One number per date range, or one row per breakdown value.",
      "dimensions": [
        "country",
        "device",
        "page",
        "keyword",
        "source_medium",
        "intent",
        "category"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [],
      "skills": [
        "search-to-revenue"
      ],
      "verbs": [
        "web_analytics_overview"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [],
      "questions": [
        "How long do people spend on this page?",
        "Time on page by template?"
      ],
      "interpretation": "A page-grain engagement signal. Longer is usually read as better for long-form content and can be read the other way on a page whose job is to route people onward, the metric itself carries no view on which case applies.",
      "caveats": [
        "The unit is not declared in the semantic layer; seconds is inferred from the field name. Do not present it as established.",
        "Unweighted across rows, so a page with a handful of views moves the site number as much as a page with thousands.",
        "Nulls are read as zero, so a zero can mean no time recorded or no data.",
        "Whole-domain only today."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Stating the unit as seconds without the caveat.",
        "Comparing page-level values without weighting by pageviews."
      ],
      "notSameAs": [
        {
          "slug": "average-session-duration",
          "why": "Time on page is per page; session duration is per visit across all pages in it."
        }
      ],
      "related": [
        "average-session-duration",
        "unique-pageviews"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "bounce-rate",
      "name": "Bounce rate",
      "aliases": [
        "Bounces"
      ],
      "definition": "The share of visits that ended without further interaction, as recorded by your web-analytics source.",
      "category": "Web analytics and conversions",
      "type": "rate",
      "unit": "not established in the codebase",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "An average of a per-row bounce-rate column supplied by the analytics export, with nulls read as zero. It is not recomputed from bounce and session counts.",
      "grain": "One number per date range, or one row per breakdown value.",
      "dimensions": [
        "country",
        "device",
        "page",
        "keyword",
        "source_medium",
        "intent",
        "category"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [],
      "skills": [
        "search-to-revenue",
        "anomaly-investigator"
      ],
      "verbs": [
        "web_analytics_overview"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [],
      "questions": [
        "What is our bounce rate?",
        "Which landing pages bounce most?"
      ],
      "caveats": [
        "It is an average of a per-row rate rather than a recomputed ratio, so rows with very little traffic weigh the same as rows with a lot.",
        "It is one of the two measures the engagement shorthand expands to, so it appears in default responses even when it was not asked for by name.",
        "Whole-domain only today.",
        "Nulls are read as zero in the underlying measure, so a zero can mean either no bounces or no data."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Painting a bounce-rate rise as an improvement because a direction oracle defaulted it to higher-is-better.",
        "Comparing page-level bounce rates without weighting by traffic."
      ],
      "notSameAs": [
        {
          "slug": "average-session-duration",
          "why": "Both are surfaced together under the engagement shorthand, but one is a rate over visits and the other is a duration. They move independently and are reported as separate columns."
        }
      ],
      "related": [
        "average-session-duration",
        "sessions"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "conversion-rate",
      "name": "Conversion rate",
      "aliases": [
        "CVR"
      ],
      "definition": "The share of visitors who converted against your configured goals in the period.",
      "category": "Web analytics and conversions",
      "type": "rate",
      "unit": "fraction of users (stored 0 to 1, shown as a percent)",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "Conversions divided by users, with a null guard on the denominator: `1.0 * conversions / NULLIF(users, 0)`. The denominator is not a sum, users is an approximate distinct count, a HyperLogLog estimate over the per-row visitor sketches with nulls read as zero, so the rate is conversions per estimated distinct person.",
      "numerator": "Conversions against configured goals over the period",
      "denominator": "Distinct users over the period, as a sketch-based approximate distinct count rather than a summed column",
      "aggregation": "A ratio, recomputed at the queried grain. Averaging per-page rates does not reproduce the site rate.",
      "grain": "One number per date range, or one row per breakdown value.",
      "dimensions": [
        "country",
        "device",
        "page",
        "keyword",
        "source_medium",
        "intent",
        "category"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "ai-referral-traffic-report",
        "content-performance-report",
        "monthly-executive-search-report",
        "search-to-revenue-report"
      ],
      "skills": [
        "search-to-revenue",
        "significance-referee",
        "monthly-exec-review"
      ],
      "verbs": [
        "web_analytics_overview",
        "conversions_overview",
        "pop_significance"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [],
      "questions": [
        "What is our conversion rate?",
        "Did conversion rate really change versus last month?"
      ],
      "interpretation": "The efficiency half of the outcome story, measured entirely inside the analytics source. It is stored as a fraction and displayed as a percent, so a value of 0.021 is 2.1%. Because the denominator is an estimated distinct user count rather than sessions, it answers what share of PEOPLE converted, not what share of visits did, and because the numerator counts conversion EVENTS rather than converted users, the two sides are not a matched proportion and the ratio is not a per-person probability.",
      "caveats": [
        "Never derive this from a conversion count and a click count. Conversion rate comes from the analytics source; dividing one system's numerator by another system's denominator produces a number that is wrong in a way nobody can see.",
        "The numerator counts conversion EVENTS, not converted users, while the denominator is an estimated distinct user count. The two are not a matched proportion, which is why the significance tool tests the displayed rate's own movement instead of modelling it as successes over trials.",
        "There is no session-denominator construction anywhere in the product. Every tool reads the displayed measure, conversions over estimated users, or the analytics source's own averaged per-row rate on non-enterprise accounts, and the code explicitly refuses to reconstruct a rate over sessions or clicks.",
        "On accounts below the enterprise analytics tier the tool swaps to a differently constructed twin: an average of a per-row rate column rather than a ratio of two totals. That is a different definition, not just a different source, and it is not reconstructible from aggregate counts at all.",
        "Stored as a fraction between 0 and 1; a consumer that multiplies by a hundred twice will report a rate a hundred times too high.",
        "Whole-domain only today."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Computing conversions divided by clicks and presenting it as conversion rate.",
        "Assuming the rate is conversions over sessions because that is the industry default, the denominator is an estimated distinct user count.",
        "Averaging per-page conversion rates into a site rate."
      ],
      "notSameAs": [
        {
          "slug": "conversions-count",
          "why": "The rate is its own measure with its own denominator and is never derived from the count. The code says so explicitly, and the two answer different questions: how many, versus what share."
        },
        {
          "slug": "conversion-rate-change",
          "why": "One is a level for a period; the other is the difference between two periods, carried on a different scale."
        },
        {
          "slug": "paid-cost-per-conversion",
          "why": "Cost per conversion is a price from the ad platform's attribution; conversion rate is a rate measured in the analytics source against your own named goals. They come from different systems and are never combined.",
          "mirroredFrom": "paid-cost-per-conversion"
        },
        {
          "slug": "funnel-dropoff-rate",
          "why": "Conversion rate is a single measured rate over users for the whole period; a funnel drop-off is the relative decline between two chosen aggregate counts. The end-to-end product of the drop-offs will not equal the conversion-rate measure.",
          "mirroredFrom": "funnel-dropoff-rate"
        }
      ],
      "related": [
        "conversions-count",
        "users",
        "conversion-rate-change",
        "significance-p-value"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "conversions-count",
      "name": "Conversions",
      "aliases": [
        "Conversion count",
        "Total conversions",
        "Goal completions"
      ],
      "definition": "The total number of conversions recorded against your configured goals in the period.",
      "category": "Web analytics and conversions",
      "type": "raw measure",
      "unit": "conversions",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "A sum of the conversions column over the rows in scope, but WHICH measure does the summing depends on the read. The conversions tool and the whole-domain site rollup use a plain `sum(...)` with NO null guard. The page-grain analytics read uses a `coalesce(sum(...), 0)` over the same underlying column. Same column, two measures, and only one of them turns a null into a zero.",
      "aggregation": "Sums across rows. This is the one conversion figure that may be added up, the per-goal counts beneath it may not.",
      "grain": "One number per date range and medium, or one row per breakdown value.",
      "dimensions": [
        "country",
        "device",
        "page",
        "keyword",
        "source_medium",
        "intent",
        "category"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "ai-referral-traffic-report",
        "content-performance-report",
        "internal-linking-report",
        "monthly-executive-search-report",
        "paid-organic-overlap-report",
        "paid-search-performance-report",
        "search-to-revenue-report"
      ],
      "skills": [
        "search-to-revenue",
        "monthly-exec-review",
        "anomaly-investigator"
      ],
      "verbs": [
        "conversions_overview",
        "web_analytics_overview",
        "funnel_dropoff",
        "pop_significance"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [],
      "questions": [
        "How many conversions did we get?",
        "How many sign-ups came from organic?"
      ],
      "interpretation": "The count of outcomes your own analytics configuration recognises. The conversions tool defaults to ALL traffic sources with the search type pinned to web, mirroring the product's own all-conversions card, so an unqualified total is an all-source total, not an organic one. Name the medium whenever it matters.",
      "caveats": [
        "The conversions rollup blends organic and paid, and the tool's default scope is All traffic sources with the search type pinned to web. A total quoted without naming the medium is an all-source total; organic is a narrowing you have to ask for.",
        "The two measures over this column differ on null handling, one coalesces to zero, the other does not, so a period with no recorded conversions can return a zero on one route and no value on the other.",
        "The conversion RATE is a separate measure and is never derived from this count.",
        "Organic has no query-level conversion data anywhere, so attribution stops at the landing page.",
        "Whole-domain only, the site rollup carries no segment id, and the tool says so rather than silently scoping.",
        "These are analytics goal conversions, not the ad platform's attributed conversions."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Dividing this count by Search Console clicks to make a conversion rate, one system's numerator over another's denominator.",
        "Reporting an unqualified conversions total without naming the medium."
      ],
      "notSameAs": [
        {
          "slug": "conversion-rate",
          "why": "The rate is its own measure in the semantic layer with its own denominator, and is never derived from this count. Deriving it, especially by dividing conversions by clicks from a different system, produces a number that is wrong in a way nobody can see."
        },
        {
          "slug": "paid-conversions",
          "why": "This is your own configured goals in the analytics source; paid conversions are the ad platform's attribution. Different systems, overlapping events, never summed."
        },
        {
          "slug": "transactions",
          "why": "Conversions cover every configured goal; transactions are completed purchases only. In most configurations transactions are already inside the conversion count.",
          "mirroredFrom": "transactions"
        },
        {
          "slug": "per-goal-conversions",
          "why": "The overall count is a separate measure over its own column, not the sum of the per-goal counts. Because goals overlap, the per-goal figures will typically add to more than the overall count.",
          "mirroredFrom": "per-goal-conversions"
        },
        {
          "slug": "web-analytics-events",
          "why": "Events are every recorded interaction; conversions are the subset your configuration marks as a goal. Reading an event count as an outcome count overstates results substantially.",
          "mirroredFrom": "web-analytics-events"
        }
      ],
      "related": [
        "conversion-rate",
        "per-goal-conversions",
        "transactions",
        "paid-conversions"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "per-goal-conversions",
      "name": "Conversions by goal",
      "aliases": [
        "Per-goal conversions",
        "Goal breakdown"
      ],
      "definition": "The conversion count for each of your own named goals, labelled with the name you configured rather than a generic goal number.",
      "category": "Web analytics and conversions",
      "type": "raw measure",
      "unit": "conversions per named goal",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "Two reads. The first reads your active goal configuration to get the goal identifier and the name you gave it, no date filter, because it is configuration rather than data. The second reads one summed goal measure per active goal over the date range. The two are merged in a pure function that pairs each configured goal with its count, in goal order, capped at ten or at the caller's row cap if that is lower.",
      "aggregation": "Each goal sums independently across rows. The goals are NEVER summed with each other.",
      "grain": "One count per named goal per date range and medium.",
      "dimensions": [
        "source_medium"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "content-performance-report",
        "paid-search-performance-report",
        "search-to-revenue-report"
      ],
      "skills": [
        "search-to-revenue",
        "monthly-exec-review"
      ],
      "verbs": [
        "conversions_overview"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [],
      "questions": [
        "How many sign-ups versus purchases?",
        "Conversions by goal this month?"
      ],
      "interpretation": "The breakdown that makes a conversion number mean something, because it names what converted. Configured goals overlap, so they are never summed, the assistant asks which goal rather than reporting a total that double-counts. Goal names are reported exactly as configured, never paraphrased.",
      "caveats": [
        "Configured goals overlap, so they are never summed. A single visit can satisfy several goals at once.",
        "Capped at ten goals, in goal order, a property with more configured goals will not show them all.",
        "Only goals marked active in the configuration are read, so a goal retired mid-period disappears from the labels while its historic counts remain in the overall total.",
        "The goal name comes from your configuration; a goal left unnamed falls back to its identifier.",
        "Whole-domain only; the tool's default scope is All traffic sources with the search type pinned to web, not organic."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Adding the per-goal counts and presenting the sum as total conversions.",
        "Renaming or grouping goals in the output, the names are the customer's own."
      ],
      "notSameAs": [
        {
          "slug": "conversions-count",
          "why": "The overall count is a separate measure over its own column, not the sum of the per-goal counts. Because goals overlap, the per-goal figures will typically add to more than the overall count."
        }
      ],
      "related": [
        "conversions-count",
        "transactions",
        "conversion-rate"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "web-analytics-events",
      "name": "Events (total and average)",
      "aliases": [
        "Total events",
        "Average events"
      ],
      "definition": "The count of analytics events in the period, and their average per row.",
      "category": "Web analytics and conversions",
      "type": "raw measure",
      "unit": "events",
      "direction": "neutral",
      "verification": "review",
      "aggregation": "The total sums the events column across rows; the average takes an unweighted mean of the same column.",
      "grain": "One number per date range, or one row per breakdown value.",
      "dimensions": [
        "country",
        "device",
        "page",
        "keyword",
        "source_medium",
        "intent",
        "category"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "search-to-revenue-report"
      ],
      "skills": [],
      "verbs": [
        "web_analytics_overview",
        "conversions_overview",
        "pop_significance"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [],
      "questions": [
        "How many events did we record?"
      ],
      "caveats": [
        "Neither measure carries a definition of what counts as an event; that is set in your analytics property and is not visible here.",
        "The average is unweighted across rows, so it is a per-row mean rather than a per-session or per-user rate.",
        "Whole-domain only today."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Reading the average as events per session.",
        "Comparing event counts across properties with different event configurations."
      ],
      "notSameAs": [
        {
          "slug": "conversions-count",
          "why": "Events are every recorded interaction; conversions are the subset your configuration marks as a goal. Reading an event count as an outcome count overstates results substantially."
        }
      ],
      "related": [
        "conversions-count",
        "sessions"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "sessions",
      "name": "Sessions",
      "aliases": [
        "Total sessions",
        "Visits"
      ],
      "definition": "The number of distinct visits to the site in the period, from your web-analytics source.",
      "category": "Web analytics and conversions",
      "type": "raw measure",
      "unit": "sessions",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "An approximate distinct count: the per-row session sketches are combined and estimated, with nulls read as zero. The measure is a HyperLogLog estimate over a combined session array, not a sum.",
      "aggregation": "Never summed across rows. The estimate is recomputed at whatever grain is queried, which is why a set of breakdown rows will not add up to the total.",
      "grain": "One number per date range, or one row per breakdown value.",
      "dimensions": [
        "country",
        "device",
        "page",
        "keyword",
        "source_medium",
        "intent",
        "category",
        "subcategory1",
        "subcategory2"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "ai-referral-traffic-report",
        "content-performance-report",
        "monthly-executive-search-report",
        "search-to-revenue-report"
      ],
      "skills": [
        "search-to-revenue",
        "monthly-exec-review",
        "anomaly-investigator"
      ],
      "verbs": [
        "web_analytics_overview",
        "pop_significance",
        "funnel_dropoff",
        "correlate_domains",
        "significance_check"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [],
      "questions": [
        "How many sessions did we get?",
        "Which landing pages drive the most sessions?"
      ],
      "interpretation": "What arrived on the site, in the analytics source's own definition of a visit. It is the denominator most engagement questions eventually reduce to, and it is deliberately not reconciled against Search Console clicks, the two count different events at different moments.",
      "caveats": [
        "An approximate distinct count, not a sum. Breakdown rows will not add to the total, and the difference is the estimator, not missing data.",
        "When the analytics account is not on the enterprise tier, the tool swaps to a raw summed twin of this measure instead. That changes the construction, not just the source, and a summed session count double-counts across rows in a way the estimate does not.",
        "The default scope is the product's own behavioural card scope, web search type plus google/organic, so an unqualified session count is organic sessions, not a raw all-source analytics total.",
        "Whole-domain only today: the web-analytics dataset scopes by a whole-domain flag rather than by segment, so a non-default segment returns a note explaining the limitation instead of a number.",
        "Analytics and Search Console will not reconcile and are not made to.",
        "Visitor state and city breakdowns are unavailable, the geography dataset they need has a defect in the semantic layer."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Summing a session breakdown and expecting the site total.",
        "Comparing a session count across accounts on different analytics tiers without noticing the measure swapped."
      ],
      "notSameAs": [
        {
          "slug": "users",
          "why": "Sessions count visits, users count people. Both are approximate distinct counts over different sketches, and neither divides into the other."
        },
        {
          "slug": "unique-pageviews",
          "why": "Sessions are an approximate distinct count of visits; unique pageviews are a sum of per-page uniques. One visit can contribute many unique pageviews.",
          "mirroredFrom": "unique-pageviews"
        }
      ],
      "related": [
        "users",
        "conversions-count",
        "conversion-rate",
        "bounce-rate"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "total-value",
      "name": "Total value",
      "aliases": [
        "Goal value"
      ],
      "definition": "The summed value your analytics configuration assigns to the events it recorded in the period.",
      "category": "Web analytics and conversions",
      "type": "monetary",
      "unit": "value in the currency configured in your analytics property",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "A sum of the total-value column supplied by the analytics export, with nulls read as zero.",
      "aggregation": "Sums across rows.",
      "grain": "One number per date range and medium, or one row per breakdown value.",
      "dimensions": [
        "country",
        "device",
        "page",
        "keyword",
        "source_medium",
        "intent",
        "category"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "search-to-revenue-report"
      ],
      "skills": [
        "search-to-revenue",
        "monthly-exec-review"
      ],
      "verbs": [
        "web_analytics_overview",
        "conversions_overview"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [],
      "questions": [
        "What value did organic traffic generate?"
      ],
      "interpretation": "Whatever your analytics property was configured to call value, assigned goal values, event values, or both. It is only as meaningful as that configuration, which is why it is reported beside transaction revenue rather than instead of it.",
      "caveats": [
        "The composition of value is set in your analytics property and is not visible here; two accounts' totals are not comparable.",
        "Value and transaction revenue are separate columns and are never added together.",
        "Whole-domain only today.",
        "The conversions tool's default scope is All traffic sources with the search type pinned to web, so an unqualified total is an all-source total, not an organic one."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Adding total value to transaction revenue to make a revenue figure."
      ],
      "notSameAs": [
        {
          "slug": "transaction-revenue",
          "why": "Revenue is money from recorded transactions; total value is whatever the analytics configuration assigns to events, which may include non-purchase goals."
        }
      ],
      "related": [
        "transaction-revenue",
        "transactions",
        "conversions-count"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "transaction-revenue",
      "name": "Transaction revenue",
      "aliases": [
        "Revenue"
      ],
      "definition": "The money recorded against completed transactions by your web-analytics source in the period.",
      "category": "Web analytics and conversions",
      "type": "monetary",
      "unit": "revenue in the currency configured in your analytics property",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "A sum of the transaction-revenue column supplied by the analytics export, with nulls read as zero.",
      "aggregation": "Sums across rows.",
      "grain": "One number per date range and medium, or one row per breakdown value.",
      "dimensions": [
        "country",
        "device",
        "page",
        "keyword",
        "source_medium",
        "intent",
        "category"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "ai-referral-traffic-report",
        "monthly-executive-search-report",
        "search-to-revenue-report"
      ],
      "skills": [
        "search-to-revenue",
        "monthly-exec-review"
      ],
      "verbs": [
        "conversions_overview",
        "web_analytics_overview"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [],
      "questions": [
        "How much revenue did organic search produce?",
        "Which pages make money?"
      ],
      "interpretation": "The rung the business actually asks about. It is a referral-based read: the analytics source attributes it to the channel that brought the visit, and no claim beyond that attribution is supportable without an integration.",
      "caveats": [
        "Attribution is whatever your analytics property is configured to do; the model is not visible here.",
        "Revenue and total value are separate columns and are never added together.",
        "No deterministic cross-domain or AI-influence revenue attribution is available, those claims need an integration that does not exist yet.",
        "Whole-domain only today; the conversions tool's default scope is All traffic sources with the search type pinned to web, not organic."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Attributing revenue to a keyword, organic has no query-level conversion data anywhere.",
        "Adding revenue to total value."
      ],
      "notSameAs": [
        {
          "slug": "total-value",
          "why": "Revenue is money from recorded transactions; total value is the analytics configuration's assigned value for events, which can include non-purchase goals."
        }
      ],
      "related": [
        "transactions",
        "total-value",
        "conversions-count"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "transactions",
      "name": "Transactions",
      "aliases": [
        "Purchases",
        "Orders"
      ],
      "definition": "The number of completed transactions recorded by your web-analytics source in the period.",
      "category": "Web analytics and conversions",
      "type": "raw measure",
      "unit": "transactions",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "A sum of the transactions column supplied by the analytics export, with nulls read as zero.",
      "aggregation": "Sums across rows.",
      "grain": "One number per date range and medium, or one row per breakdown value.",
      "dimensions": [
        "country",
        "device",
        "page",
        "keyword",
        "source_medium",
        "intent",
        "category"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "search-to-revenue-report"
      ],
      "skills": [
        "search-to-revenue",
        "monthly-exec-review"
      ],
      "verbs": [
        "conversions_overview",
        "web_analytics_overview",
        "pop_significance",
        "funnel_dropoff"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [],
      "questions": [
        "How many orders came from organic search?",
        "Transactions by landing page?"
      ],
      "interpretation": "The narrowest and least ambiguous outcome in the set, a completed purchase, not a configured goal. It is the natural bottom step of a macro funnel that runs sessions to conversions to transactions.",
      "caveats": [
        "Transactions are a subset of conversions in most configurations, so they are never added to the conversion count.",
        "Whole-domain only today.",
        "The conversions tool's default scope is All traffic sources with the search type pinned to web, not organic."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Adding transactions to conversions to make an outcome total."
      ],
      "notSameAs": [
        {
          "slug": "conversions-count",
          "why": "Conversions cover every configured goal; transactions are completed purchases only. In most configurations transactions are already inside the conversion count."
        }
      ],
      "related": [
        "transaction-revenue",
        "conversions-count",
        "funnel-dropoff-rate"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "unique-pageviews",
      "name": "Unique pageviews",
      "aliases": [
        "Unique page views"
      ],
      "definition": "The number of visits during which a page was viewed at least once, summed across the pages in scope.",
      "category": "Web analytics and conversions",
      "type": "raw measure",
      "unit": "unique pageviews",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "A sum of the unique-pageviews column supplied by the analytics export, with nulls read as zero.",
      "aggregation": "Sums across rows. Because uniqueness is already resolved per row before the sum, a site total is a sum of per-page uniques and not a site-level distinct count.",
      "grain": "One number per date range, or one row per breakdown value.",
      "dimensions": [
        "country",
        "device",
        "page",
        "keyword",
        "source_medium",
        "intent",
        "category"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "ai-referral-traffic-report"
      ],
      "skills": [
        "search-to-revenue"
      ],
      "verbs": [
        "web_analytics_overview",
        "pop_significance",
        "funnel_dropoff"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [],
      "questions": [
        "How many unique pageviews did our content get?",
        "Which pages are viewed most?"
      ],
      "interpretation": "Content consumption at page grain. It is the right denominator for page-level engagement questions and the wrong one for site-level reach, because summing per-page uniques counts a visitor once per page they saw.",
      "caveats": [
        "A site total is a sum of per-page uniques, so a visitor who viewed five pages contributes five.",
        "Nulls are read as zero.",
        "Whole-domain only today."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Presenting a summed unique-pageview total as a reach or audience-size number."
      ],
      "notSameAs": [
        {
          "slug": "sessions",
          "why": "Sessions are an approximate distinct count of visits; unique pageviews are a sum of per-page uniques. One visit can contribute many unique pageviews."
        }
      ],
      "related": [
        "sessions",
        "average-time-on-page"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "users",
      "name": "Users",
      "aliases": [
        "Total users",
        "Visitors"
      ],
      "definition": "The number of distinct visitors to the site in the period, from your web-analytics source.",
      "category": "Web analytics and conversions",
      "type": "raw measure",
      "unit": "users",
      "direction": "higher-better",
      "verification": "verified",
      "calculation": "An approximate distinct count: the per-row visitor sketches are combined and estimated, with nulls read as zero. The measure is a HyperLogLog estimate over a combined visitor array, not a sum.",
      "aggregation": "Never summed across rows; the estimate is recomputed at the queried grain.",
      "grain": "One number per date range, or one row per breakdown value.",
      "dimensions": [
        "country",
        "device",
        "page",
        "keyword",
        "source_medium",
        "intent",
        "category",
        "subcategory1",
        "subcategory2"
      ],
      "requiredFilters": [
        "date_range"
      ],
      "sources": [
        "web-analytics"
      ],
      "reports": [
        "ai-referral-traffic-report",
        "search-to-revenue-report"
      ],
      "skills": [
        "search-to-revenue",
        "monthly-exec-review"
      ],
      "verbs": [
        "web_analytics_overview",
        "pop_significance",
        "funnel_dropoff"
      ],
      "rungs": [
        "R5"
      ],
      "levers": [],
      "questions": [
        "How many people visited?",
        "Users by device?"
      ],
      "interpretation": "People rather than visits, and the denominator the conversion-rate measure actually uses. That last point matters more than it looks: a conversion rate quoted per user and one quoted per session are different numbers about the same period.",
      "caveats": [
        "An approximate distinct count, not a sum, breakdown rows will not add to the total.",
        "On accounts below the enterprise analytics tier the tool swaps to a raw summed twin, which double-counts visitors seen across multiple rows.",
        "Whole-domain only today.",
        "This is the denominator of the conversion-rate measure in the semantic layer, and no tool substitutes a session denominator, the significance tool tests the same user-based measure the product displays."
      ],
      "freshness": "loads nightly, a same-day question gets yesterday's number, labelled as yesterday's.",
      "failureModes": [
        "Summing a user breakdown.",
        "Assuming conversion rate is conversions over sessions because that is the industry default."
      ],
      "notSameAs": [
        {
          "slug": "sessions",
          "why": "Users count people, sessions count visits. One person can open many sessions, and neither measure is derived from the other."
        }
      ],
      "related": [
        "sessions",
        "conversion-rate"
      ],
      "workflows": [],
      "lastVerified": "2026-08-04"
    }
  ],
  "reports": [
    {
      "slug": "ai-bot-activity-report",
      "name": "AI bot activity report",
      "aliases": [
        "AI crawler readiness",
        "LLM bot report",
        "GPTBot activity",
        "AI bot coverage"
      ],
      "audience": "Technical SEO",
      "job": "Confirm the AI crawlers are fetching the pages you want cited, before anyone optimises for citations.",
      "cadence": "Monthly",
      "summary": "The same server logs, read for a different question: which AI crawlers fetch you, how often, with what status, and whether they reach the specific pages that are supposed to earn citations. Crossed with indexability and orphan status, it separates 'they could not fetch it' from 'they did not choose to'. A page an AI crawler never fetched cannot be cited, which makes this the gate on the whole AI visibility programme.",
      "headline": [
        "bot-hits",
        "unique-pages-crawled-by-bots",
        "status-code-hits"
      ],
      "diagnostic": [
        "indexability-flags",
        "incoming-internal-links",
        "crawl-depth",
        "cited-page-citation-count",
        "ai-citation-count"
      ],
      "guardrail": [
        "crawler-readiness",
        "verified-vs-spoofed-googlebot",
        "crawler-response-time"
      ],
      "sources": [
        "server-logs",
        "site-crawl",
        "ai-visibility"
      ],
      "skills": [
        "ai-crawler-readiness",
        "ai-crawler-check",
        "page-citability-read",
        "technical-health-audit"
      ],
      "rungs": [
        "R1"
      ],
      "questions": [
        "Are AI bots crawling our site?",
        "Is GPTBot fetching the pages we want cited?",
        "Are we accidentally blocking AI crawlers?",
        "Which citation targets have never been crawled?"
      ],
      "workflows": [
        "prompts-that-cite-us"
      ],
      "caveats": "The readiness join between observed bot visits and citation targets is composed at read time, not a stored measure, treat it as an assembled view. Absence of a bot in the logs can mean an edge block, a robots directive, or the crawler simply not choosing the page, and the log alone cannot tell you which. AI crawler user agents change frequently; a fall to zero for one agent is a naming change until proven otherwise.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-overview-report",
      "name": "AI Overview and SERP feature report",
      "aliases": [
        "GEO report",
        "AIO report",
        "AI Overview impact",
        "SERP feature report",
        "Featured snippet report"
      ],
      "audience": "SEO lead",
      "job": "Track presence in Google's on-SERP generated answers and other SERP features, and what their spread does to your clicks.",
      "cadence": "Weekly",
      "summary": "Google's AI Overviews and the other SERP features sit on the search results page, are measured from ranking data, and are a different surface from answer-engine citations, this report keeps them apart on purpose. It covers which of your keywords trigger an overview, whether you are inside it, how feature coverage is spreading across your keyword set, and the click effect on keywords where it appeared.",
      "headline": [
        "ai-overview-inclusion",
        "ai-overview-serp-count",
        "ai-overview-daily-visibility",
        "ai-overview-page-impressions"
      ],
      "diagnostic": [
        "clicks",
        "impressions",
        "ctr",
        "avg-position",
        "pop-delta",
        "search-market-share"
      ],
      "guardrail": [
        "featured-snippet-ownership",
        "serp-brand-coverage",
        "total-daily-market-share",
        "real-noise-verdict"
      ],
      "sources": [
        "rank-tracking",
        "search-console"
      ],
      "skills": [
        "serp-feature-watch",
        "ai-vs-traditional-gap",
        "market-share-review"
      ],
      "rungs": [
        "R2",
        "R3"
      ],
      "questions": [
        "How many of our keywords now show an AI Overview?",
        "Are AI Overviews taking our clicks?",
        "Do we appear inside the overview or just below it?",
        "Where do we hold featured snippets?"
      ],
      "workflows": [
        "aio-benchmark",
        "aio-by-market",
        "search-strong-ai-silent"
      ],
      "caveats": "An AI Overview is not an answer-engine citation, same words, different surfaces, different datasets; never add the two into one 'AI visibility' figure. Overview presence is observed at the time of measurement and Google varies it by query, device and geography, so coverage percentages move without any change on your side. Featured snippet and ranked-keyword counts in this family are flagged for review in the product and should be presented as directional.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-referral-traffic-report",
      "name": "AI referral traffic report",
      "aliases": [
        "AI sessions report",
        "Assistant referral report",
        "Generative AI traffic",
        "LLM referral traffic"
      ],
      "audience": "In-house strategist",
      "job": "Measure the sessions and conversions that AI assistants actually send, so citation work can be tied to an outcome.",
      "cadence": "Monthly",
      "summary": "Being cited is R3; being visited is R5. This report reads the analytics side, sessions arriving from AI assistant referrers, which pages they land on, and whether they convert, and sits next to the AI visibility report as its outcome half. Volumes are small in absolute terms for most sites, which is exactly why it is reported as a trend with its own scale rather than as a share of total traffic.",
      "headline": [
        "ai-referral-sessions",
        "ai-referral-conversions",
        "ai-referral-conversion-rate",
        "ai-referral-session-change"
      ],
      "diagnostic": [
        "ai-referral-source-split",
        "sessions",
        "users",
        "conversions-count",
        "conversion-rate",
        "unique-pageviews",
        "transaction-revenue",
        "cited-page-citation-count"
      ],
      "guardrail": [
        "real-noise-verdict",
        "practical-effect-magnitude",
        "conversion-rate-change",
        "pop-delta-pct"
      ],
      "sources": [
        "web-analytics",
        "ai-visibility"
      ],
      "skills": [
        "search-to-revenue",
        "ai-citation-monitoring",
        "cross-domain-correlator"
      ],
      "rungs": [
        "R5"
      ],
      "questions": [
        "How much traffic do AI assistants send us?",
        "Do AI referral visits convert?",
        "Which pages do AI assistants send people to?",
        "Is AI referral traffic growing?"
      ],
      "workflows": [
        "ai-assistant-referrals",
        "rank-without-revenue"
      ],
      "caveats": "AI referral traffic depends entirely on how the analytics property classifies those referrers; assistants that strip or rewrite the referrer are invisible here, so this is a floor and not a total. Session counts are small enough that week-over-week percentage swings are usually noise, report the trend. Cited pages and landing pages are different lists and will not match.",
      "verification": "review",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ai-visibility-report",
      "name": "AI visibility report",
      "aliases": [
        "AEO report",
        "Answer engine report",
        "AI citation report",
        "AI search standing"
      ],
      "audience": "SEO lead",
      "job": "Show whether answer engines cite you, for which prompts, and how that standing compares to rivals, per engine, not blended.",
      "cadence": "Weekly",
      "summary": "The answer-engine index: citation rate and share of voice against tracked rivals, the URLs actually cited, the prompts where you appear and the prompts where a rival does instead, cut per engine, because one blended number hides an engine you are absent from. This is the R3 report, and it is strictly separate from Google's on-SERP AI Overviews, which is a different surface measured a different way.",
      "headline": [
        "ai-citation-rate",
        "ai-share-of-voice",
        "ai-citation-count"
      ],
      "diagnostic": [
        "ai-mention-share",
        "ai-mention-count",
        "cited-page-citation-count",
        "prompt-citation-count",
        "prompt-citation-share",
        "prompt-mention-share",
        "ai-avg-citation-position",
        "ai-competitive-rank",
        "ai-citation-category-mix",
        "prompt-share-of-voice-score",
        "ai-positive-sentiment-rate"
      ],
      "guardrail": [
        "prompt-share-of-voice-share",
        "ai-negative-sentiment-rate",
        "ai-answer-presence-score",
        "real-noise-verdict"
      ],
      "sources": [
        "ai-visibility"
      ],
      "skills": [
        "aeo-audit",
        "ai-visibility-pulse",
        "ai-citation-monitoring",
        "ai-prompt-coverage-gaps",
        "competitor-deep-dive"
      ],
      "rungs": [
        "R3",
        "R4"
      ],
      "questions": [
        "Does ChatGPT cite us, and for what?",
        "What is our share of voice in AI answers?",
        "Which of our pages get cited most?",
        "Which prompts do we not appear in at all?"
      ],
      "workflows": [
        "citations-by-page",
        "prompts-that-cite-us",
        "ai-platform-scorecard",
        "ai-rivals-benchmark",
        "ai-intent-heatmap",
        "llm-segment-sweep",
        "search-strong-ai-silent"
      ],
      "caveats": "Everything here is measured against a monitored prompt set, not all AI traffic, the prompt set defines the ceiling, so state its size. Citation rate and mention rate are different measures with different denominators, and share of voice weights citations above mentions, so the three will not reconcile arithmetically. Engines vary day to day on the same prompt; read the trend over weeks, not one run. Sentiment is instrumented for mentions only and does not yet cover positioning fidelity.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "cannibalization-report",
      "name": "Cannibalization report",
      "aliases": [
        "Keyword cannibalisation",
        "Self-competition report",
        "Overlapping pages report",
        "Consolidation candidates"
      ],
      "audience": "Content lead",
      "job": "Surface queries where more than one of your own pages competes, and flag which pairs are worth consolidating.",
      "cadence": "Quarterly",
      "summary": "Queries where two or more of your URLs take impressions and rank positions, with the impression split, the position each page holds, and how stable the split is over time. Multiple pages on one query is not automatically a fault, different intents legitimately share vocabulary, so every candidate is presented for review with the intent caveat attached rather than as a defect.",
      "headline": [
        "unique-keywords",
        "unique-pages",
        "clicks"
      ],
      "diagnostic": [
        "impressions",
        "ctr",
        "avg-position",
        "ranking-movement",
        "pop-delta"
      ],
      "guardrail": [
        "keyword-page-click-coverage",
        "real-noise-verdict",
        "practical-effect-magnitude"
      ],
      "sources": [
        "search-console"
      ],
      "skills": [
        "cannibalization-check",
        "content-decay-refresh",
        "linking-opportunity-review"
      ],
      "rungs": [
        "R2"
      ],
      "questions": [
        "Are our pages competing with each other?",
        "Which queries have more than one of our URLs ranking?",
        "Should we consolidate these pages?",
        "Is this cannibalisation or two different intents?"
      ],
      "workflows": [
        "keyword-coverage-gap",
        "subpage-portfolio-audit"
      ],
      "caveats": "Two pages on one query is evidence of overlap, not proof of harm, a commercial page and a guide answering the same phrase are often both correct. Rotation between URLs across days is normal for Google and should not be read as instability. Consolidation is irreversible in practice, so treat every row as a review candidate and check intent before merging.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "competitor-search-report",
      "name": "Competitor search report",
      "aliases": [
        "Competitive landscape report",
        "Competitor battlecard",
        "Keyword gap report",
        "Ranking factor benchmark",
        "Rival benchmark"
      ],
      "audience": "In-house strategist",
      "job": "Profile named rivals, where they outrank you, what they rank with, and what their pages do differently, so content and technical work can be aimed.",
      "cadence": "Monthly",
      "summary": "The per-rival profile, as distinct from the aggregate share number: which keywords each competitor wins, where you win, where neither of you ranks, and how their ranking pages compare on measurable page attributes. Publisher and community domains are treated as competitors here too, since they take page-one real estate on the same demand. The output is a target list, not a standing.",
      "headline": [
        "losing-keywords",
        "winning-keywords",
        "not-ranked-keywords",
        "keyword-rank-gap"
      ],
      "diagnostic": [
        "our-rank",
        "best-competitor-rank",
        "head-to-head-rank-gap",
        "avg-rank-vs-competitors",
        "overall-average-rank",
        "competitor-share-by-rank-bucket",
        "impressions",
        "clicks"
      ],
      "guardrail": [
        "total-daily-market-share",
        "ranked-keyword-count",
        "ranked-page-count",
        "real-noise-verdict"
      ],
      "sources": [
        "rank-tracking",
        "search-console",
        "site-crawl"
      ],
      "skills": [
        "competitor-deep-dive",
        "keyword-gap-audit",
        "market-share-review"
      ],
      "rungs": [
        "R2",
        "R3"
      ],
      "questions": [
        "Where do competitors outrank us?",
        "What keywords do they rank for that we do not?",
        "Which rivals actually own page one for our terms?",
        "How do their ranking pages differ from ours?"
      ],
      "workflows": [
        "ai-rivals-benchmark",
        "keyword-coverage-gap",
        "keyword-rank-duel",
        "competitor-movers-deck",
        "page-niche-share",
        "subpage-portfolio-audit"
      ],
      "caveats": "The competitor set is configured per segment and the column-to-domain mapping is not fixed across segments, resolve which domain is which before quoting a rival by name. Gaps found against a community or publisher domain usually are not addressable with a competing page; say so instead of putting them on the content list. Ranking-factor comparisons describe correlation on observed pages, never a ranking cause.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "content-decay-report",
      "name": "Content decay report",
      "aliases": [
        "Content refresh report",
        "Declining pages report",
        "Refresh worklist",
        "Content lifecycle report"
      ],
      "audience": "Content lead",
      "job": "Produce a refresh-or-consolidate worklist ordered by recoverable clicks, not by how old the page is.",
      "cadence": "Quarterly",
      "summary": "Pages measured against their own peak rather than against the site average: how far each has slid, over what period, and how many clicks are plausibly recoverable if it is refreshed. Each entry carries a recommendation, refresh, consolidate or leave, so the output is a work queue rather than a list of declines. Seasonality is separated from decay before anything reaches the list.",
      "headline": [
        "clicks",
        "pop-delta",
        "potential-clicks-raw",
        "unique-pages"
      ],
      "diagnostic": [
        "pop-delta-pct",
        "avg-position",
        "impressions",
        "ctr",
        "ctr-delta",
        "potential-clicks-adjusted",
        "ranking-movement"
      ],
      "guardrail": [
        "real-noise-verdict",
        "practical-effect-magnitude",
        "aio-haircut",
        "fallback-ctr-prior"
      ],
      "sources": [
        "search-console",
        "web-analytics"
      ],
      "skills": [
        "content-decay-refresh",
        "cannibalization-check",
        "significance-referee"
      ],
      "rungs": [
        "R2",
        "R5"
      ],
      "questions": [
        "Which pages have decayed since their peak?",
        "What should we refresh next quarter?",
        "How many clicks could a refresh recover?",
        "Is this decline decay or seasonality?"
      ],
      "workflows": [
        "twelve-week-drop",
        "year-over-year-truth",
        "category-decline-verdict"
      ],
      "caveats": "A decline against peak is not decay if the peak was a seasonal high or a one-off event, compare year over year before adding a page to the list. Recoverable-click estimates assume the page can return to a prior position and are a planning aid, not a forecast. Pages that declined because a rival page of yours now ranks for the same query belong in the cannibalisation report instead.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "content-performance-report",
      "name": "Content performance report",
      "aliases": [
        "Page performance report",
        "Blog performance report",
        "Article performance report",
        "Content scorecard"
      ],
      "audience": "Content lead",
      "job": "Tell the content team which published pages earn search demand and which do not, at the grain they actually publish in.",
      "cadence": "Monthly",
      "summary": "The page-level index rolled up the way content is planned, by section, template, topic or publication cohort, with clicks, impressions, position and conversions per page. It is the report that turns 'organic is up' into 'these twelve pages did it'. Newly published cohorts are tracked from launch so a publishing programme can be judged on its own pages rather than on site totals.",
      "headline": [
        "clicks",
        "impressions",
        "avg-position",
        "unique-pages"
      ],
      "diagnostic": [
        "ctr",
        "pop-delta",
        "pop-delta-pct",
        "unique-keywords",
        "sessions",
        "conversions-count",
        "per-goal-conversions",
        "conversion-rate"
      ],
      "guardrail": [
        "keyword-page-click-coverage",
        "real-noise-verdict",
        "practical-effect-magnitude"
      ],
      "sources": [
        "search-console",
        "web-analytics"
      ],
      "skills": [
        "content-decay-refresh",
        "weekly-search-report",
        "cannibalization-check",
        "chart-composer"
      ],
      "rungs": [
        "R2",
        "R5"
      ],
      "questions": [
        "Which of our pages get the most search traffic?",
        "How is the blog performing in search?",
        "Did the pages we published last quarter work?",
        "Which pages get impressions but no clicks?"
      ],
      "workflows": [
        "subpage-portfolio-audit",
        "impressions-without-clicks",
        "rank-without-revenue"
      ],
      "caveats": "Search Console reports on canonical URLs, so parameterised and variant URLs roll up in ways that surprise people comparing against the CMS list, state the normalisation rule. New pages need weeks of data before an absence of clicks means anything. The BigQuery Search Console export returns far more URLs than the API for large sites; page counts are not comparable across the two sources.",
      "verification": "inferred",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "core-web-vitals-report",
      "name": "Core Web Vitals report",
      "aliases": [
        "Page speed report",
        "CWV report",
        "Site performance report",
        "Lighthouse report"
      ],
      "audience": "Engineering",
      "job": "Identify which vital is failing, on which templates, and whether it moved enough to warrant engineering time.",
      "cadence": "Monthly",
      "summary": "The performance index at site and template level: the three Core Web Vitals with their pass rates, the supporting Lighthouse scores, and the trend across measurement runs. It exists to replace the forwarded single-page screenshot with a distribution, one slow page is not a site problem, and a failing vital on a high-traffic template is. Measurement cadence varies by property, which the report states rather than smooths over.",
      "headline": [
        "cumulative-layout-shift",
        "interaction-to-next-paint",
        "cwv-grade-distribution",
        "cwv-overall-verdict"
      ],
      "diagnostic": [
        "performance-score",
        "cwv-vital-grade",
        "cwv-weakest-vital",
        "clicks"
      ],
      "guardrail": [
        "largest-contentful-paint",
        "lighthouse-category-scores",
        "crawler-response-time"
      ],
      "sources": [
        "lighthouse",
        "site-crawl",
        "search-console",
        "server-logs"
      ],
      "skills": [
        "cwv-regression-watch",
        "technical-health-audit"
      ],
      "rungs": [
        "R1"
      ],
      "questions": [
        "Are our Core Web Vitals passing?",
        "Which vital is failing and on which pages?",
        "Did page speed regress after the release?",
        "Which templates are slowest?"
      ],
      "workflows": [],
      "caveats": "Vitals collection is typically biweekly and the interval differs by property, some priority URLs are measured nightly and the rest much less often, so a 'change' can be two measurements weeks apart. These are lab-style measurements on a sampled URL set, not field data from your users. The vitals are lower-is-better while the Lighthouse scores are higher-is-better, and the non-vital Lighthouse scores are on a scale that is still under review; present those as directional only.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "crawl-log-report",
      "name": "Crawl log report",
      "aliases": [
        "Log file report",
        "Server log analysis",
        "Crawl budget report",
        "Bot crawl report",
        "Logfile insights"
      ],
      "audience": "Technical SEO",
      "job": "Show what search crawlers actually fetched, with what status, and where crawl effort is being spent or wasted.",
      "cadence": "Weekly",
      "summary": "Server-log truth about crawling: requests by bot, status-code distribution, response times, which URL groups absorb the crawl budget and which valuable pages are fetched rarely or not at all. It is the R1 gate, nothing above it is possible for a page no crawler fetched, and it is the single most-run family in the estate, which reflects how often it is checked rather than how rarely it changes.",
      "headline": [
        "bot-hits",
        "unique-pages-crawled-by-bots",
        "status-code-hits"
      ],
      "diagnostic": [
        "indexability-flags",
        "crawl-depth",
        "incoming-internal-links",
        "pop-delta"
      ],
      "guardrail": [
        "verified-vs-spoofed-googlebot",
        "crawler-response-time",
        "real-noise-verdict"
      ],
      "sources": [
        "server-logs",
        "site-crawl"
      ],
      "skills": [
        "crawl-efficiency-review",
        "technical-health-audit",
        "anomaly-investigator"
      ],
      "rungs": [
        "R1"
      ],
      "questions": [
        "What is Googlebot crawling on our site?",
        "Where is crawl budget being wasted?",
        "Are crawlers hitting errors?",
        "Which important pages are not being crawled?"
      ],
      "workflows": [
        "subpage-portfolio-audit"
      ],
      "caveats": "Log coverage depends on which hosts, CDNs and edge layers forward logs, a bot missing from the file may be blocked at the edge rather than absent, and the two look identical here. Bot identity is claimed in the user agent unless reverse-DNS verification is in place, so 'Googlebot' counts include impostors. Log delivery lags from hours to overnight and varies by site; check the max available date before reading the last day.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "ctr-opportunity-report",
      "name": "CTR opportunity report",
      "aliases": [
        "Click-through rate report",
        "CTR gap report",
        "Title and meta opportunity",
        "Underperforming CTR"
      ],
      "audience": "SEO lead",
      "job": "Find queries and pages that rank well but are clicked below what their position should earn, and size the fix.",
      "cadence": "Monthly",
      "summary": "Actual click-through rate compared against what the position would normally return, at query and page grain, with the gap converted into clicks left on the table. The remedy is usually a title, description or snippet change rather than a ranking push, which makes this the cheapest worklist in the set. SERP features that legitimately depress CTR are separated out so they are not mistaken for a copy problem.",
      "headline": [
        "actual-ctr",
        "expected-ctr",
        "ctr-delta",
        "ctr-impact"
      ],
      "diagnostic": [
        "impressions",
        "clicks",
        "avg-position",
        "weighted-ctr",
        "ctr-gain",
        "potential-clicks-raw",
        "ai-overview-inclusion"
      ],
      "guardrail": [
        "ctr-bucket-support",
        "fallback-ctr-prior",
        "aio-haircut",
        "real-noise-verdict"
      ],
      "sources": [
        "search-console",
        "rank-tracking"
      ],
      "skills": [
        "ctr-opportunity-audit",
        "striking-distance-sprint",
        "serp-feature-watch"
      ],
      "rungs": [
        "R2",
        "R5"
      ],
      "questions": [
        "Which pages rank well but get no clicks?",
        "Where is our CTR below what the position should earn?",
        "How many clicks are we leaving on the table?",
        "Which titles should we rewrite first?"
      ],
      "workflows": [
        "impressions-without-clicks",
        "query-family-watch"
      ],
      "caveats": "The expected-CTR baseline is a modelled prior, and the fallback curve used where a site-specific curve is not available is unvalidated, read the gap as a ranking signal, not a quantified loss. Brand queries sit far above any generic curve and will flood the list unless excluded. A large gap on a keyword whose SERP carries an AI Overview or a feature block is often correct behaviour rather than a copy fault.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "internal-linking-report",
      "name": "Internal linking report",
      "aliases": [
        "Link equity report",
        "Orphan page report",
        "Site architecture report",
        "Linking worklist"
      ],
      "audience": "SEO lead",
      "job": "Produce a ranked list of internal linking moves, under-linked valuable pages and orphans worth rescuing.",
      "cadence": "Quarterly",
      "summary": "Where internal links point versus where search value sits: pages carrying impressions and conversions but few incoming links, orphaned pages that no navigation reaches, and the templates that concentrate links on low-value destinations. The output is a set of specific linking moves ordered by the value behind the target page.",
      "headline": [
        "incoming-internal-links",
        "outgoing-internal-links",
        "crawl-depth"
      ],
      "diagnostic": [
        "unique-pages",
        "clicks",
        "impressions",
        "conversions-count",
        "indexability-flags"
      ],
      "guardrail": [
        "unique-pages-crawled-by-bots",
        "bot-hits",
        "practical-effect-magnitude"
      ],
      "sources": [
        "site-crawl",
        "search-console"
      ],
      "skills": [
        "linking-opportunity-review",
        "technical-health-audit"
      ],
      "rungs": [
        "R1",
        "R2"
      ],
      "questions": [
        "Which valuable pages have too few internal links?",
        "Do we have orphan pages worth rescuing?",
        "Where should we add internal links first?",
        "Is link equity pooling on the wrong pages?"
      ],
      "workflows": [
        "subpage-portfolio-audit"
      ],
      "caveats": "Link counts come from a crawl with a defined start point and depth, so navigation reachable only from unusual entry points can look orphaned when it is not. A low inlink count is only interesting where search value sits behind the page, rank by value, never by link count. No standing dashboard evidence exists for this deliverable, so present it as an assembled analysis rather than an established report.",
      "verification": "review",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "keyword-ranking-report",
      "name": "Keyword ranking and movement report",
      "aliases": [
        "Keyword ranking report",
        "Rank movement report",
        "Rank tracking report",
        "Ranked pages report",
        "Gainers and losers"
      ],
      "audience": "SEO lead",
      "job": "Show where tracked keywords and pages sit now, and which of them moved enough between periods to be worth acting on.",
      "cadence": "Weekly",
      "summary": "The position table and its deltas in one place: current average position and the page-one footprint for the tracked keyword set, plus the biggest gainers and losers between two periods with a significance annotation on each. Ranking and movement are kept in one family because the same boards carry both and the reader flips between them in one sitting. It answers what moved; the anomaly report answers why.",
      "headline": [
        "avg-position",
        "ranked-keyword-coverage",
        "ranking-movement",
        "pop-delta"
      ],
      "diagnostic": [
        "clicks",
        "impressions",
        "ctr",
        "unique-keywords",
        "unique-pages",
        "pop-delta-pct",
        "overall-average-rank"
      ],
      "guardrail": [
        "real-noise-verdict",
        "significant-flag",
        "practical-effect-magnitude",
        "keyword-page-click-coverage"
      ],
      "sources": [
        "search-console",
        "rank-tracking"
      ],
      "skills": [
        "rank-movement-review",
        "significance-referee",
        "keyword-gap-audit",
        "set-analysis-scope"
      ],
      "rungs": [
        "R2"
      ],
      "questions": [
        "Which keywords moved the most this period?",
        "What are our biggest ranking gains and losses?",
        "How many keywords sit on page one?",
        "Did that ranking drop actually matter?"
      ],
      "workflows": [
        "nonbrand-weekly-gainers",
        "keyword-rank-duel",
        "query-family-watch",
        "twelve-week-drop"
      ],
      "caveats": "Average position from Search Console is impression-weighted, so a position 'improvement' can come entirely from losing low-position impressions rather than from ranking better. Keywords with a handful of impressions produce large, meaningless position swings, apply the impression floor before ranking movers. The BigQuery Search Console export surfaces many more low-volume queries than the API, so counts of ranked keywords are not comparable across the two.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "monthly-executive-search-report",
      "name": "Monthly executive search report",
      "aliases": [
        "SEO executive report",
        "Monthly business review, search",
        "Board deck numbers",
        "Monthly overall scorecard",
        "Leadership readout"
      ],
      "audience": "CMO",
      "job": "Put the month's search outcome in front of leadership in business language, with every claim significance-gated before it enters a deck.",
      "cadence": "Monthly",
      "summary": "The month-end leadership readout: demand captured, market position against the tracked competitive set, AI-search standing, and the revenue-adjacent outcome, four numbers, each with a trend and a verdict. It deliberately runs at a coarser grain than the weekly report, because the decision it supports is budget and priority, not this week's worklist. Year-over-year sits alongside month-over-month so seasonal swings are not read as performance.",
      "headline": [
        "clicks",
        "search-market-share",
        "ai-citation-rate",
        "conversions-count"
      ],
      "diagnostic": [
        "sessions",
        "transaction-revenue",
        "gap-to-leader",
        "market-share-standings-rank",
        "avg-position",
        "ranked-keyword-coverage",
        "pop-delta",
        "conversion-rate"
      ],
      "guardrail": [
        "real-noise-verdict",
        "practical-effect-magnitude",
        "pop-delta-pct",
        "total-daily-market-share",
        "market-share-table-clicks"
      ],
      "sources": [
        "search-console",
        "web-analytics",
        "rank-tracking",
        "ai-visibility"
      ],
      "skills": [
        "monthly-exec-review",
        "significance-referee",
        "search-to-revenue",
        "market-share-review",
        "chart-composer"
      ],
      "rungs": [
        "R2",
        "R3",
        "R5"
      ],
      "questions": [
        "What did search deliver this month?",
        "Are we gaining or losing ground against the field?",
        "What goes in the board deck for search?",
        "Is the month-over-month change real or seasonal?"
      ],
      "workflows": [
        "share-trajectory-quarter",
        "year-over-year-truth",
        "competitor-movers-deck",
        "conversion-spike-verdict"
      ],
      "caveats": "Month boundaries and the analytics attribution window rarely line up, say which window the conversion number came from. Search market share is CTR-modelled against a tracked competitor set, not a measured share of all search; name the set. Do not blend a Search Console click total and an analytics session total into one 'traffic' number; they count different things.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "paid-organic-overlap-report",
      "name": "Paid and organic overlap report",
      "aliases": [
        "Paid and organic report",
        "SEM and SEO overlap",
        "Paid cannibalisation report",
        "Incrementality review",
        "Paid plus SEO trends"
      ],
      "audience": "PPC manager",
      "job": "Find the terms being bought that organic already wins, and the terms organic cannot reach that deserve budget.",
      "cadence": "Monthly",
      "summary": "The two channels on one keyword axis: where paid and organic both appear, where only one does, and what each is spending or earning on the overlap. It supports two decisions in the Thursday budget review, where to pull spend because organic already holds position one, and where to add it because organic will not get there this quarter. Brand terms are separated because the overlap argument works differently there.",
      "headline": [
        "paid-organic-keyword-overlap",
        "paying-for-owned-term",
        "clicks",
        "paid-ad-cost"
      ],
      "diagnostic": [
        "paid-clicks",
        "paid-average-cpc",
        "avg-position",
        "impressions",
        "paid-conversions",
        "conversions-count",
        "search-impression-share",
        "total-search-share"
      ],
      "guardrail": [
        "total-search-share-organic-leg",
        "total-search-share-paid-leg",
        "real-noise-verdict",
        "practical-effect-magnitude"
      ],
      "sources": [
        "google-ads",
        "search-console",
        "web-analytics"
      ],
      "skills": [
        "paid-organic-balance",
        "paid-efficiency-review",
        "cross-domain-correlator"
      ],
      "rungs": [
        "R5"
      ],
      "questions": [
        "Which keywords are we paying for that we already rank for?",
        "Where should we cut ad spend because organic covers it?",
        "Which terms does organic not reach that we should buy?",
        "What is the paid and organic split on brand?"
      ],
      "workflows": [
        "organic-vs-paid-share",
        "paid-query-losses",
        "rank-without-revenue"
      ],
      "caveats": "The join between the two channels runs two ways, search term to organic query, and bidded keyword to organic query, and the two produce different overlap sets; say which was used. Organic has no query-level conversion data, so a like-for-like conversion comparison at keyword grain is not available. Holding position one organically does not make paid spend wasted; incrementality needs a test, and this report sizes the candidates for one rather than settling it.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "paid-search-performance-report",
      "name": "Paid search performance report",
      "aliases": [
        "PPC performance report",
        "Paid efficiency report",
        "Ad spend report",
        "Campaign performance report",
        "Paid search optimisation"
      ],
      "audience": "PPC manager",
      "job": "Show where ad spend goes, what it returns, and which auctions are losing ground to rank rather than to budget.",
      "cadence": "Weekly",
      "summary": "The spend index: cost, clicks, CPC, conversions and cost per conversion swept by campaign, ad group, keyword, match type and search term, with impression share broken into the part lost to budget and the part lost to rank. The rank-loss split is the actionable half, budget loss is a finance decision, rank loss is fixable ground. Negative-keyword and match-type analysis sit here because that is where the waste is found.",
      "headline": [
        "paid-ad-cost",
        "paid-cost-per-conversion",
        "paid-conversions",
        "paid-ctr"
      ],
      "diagnostic": [
        "paid-clicks",
        "paid-impressions",
        "paid-average-cpc",
        "paid-cpm",
        "search-impression-share",
        "impression-share-lost-to-rank",
        "top-impression-share-lost-to-rank",
        "absolute-top-impression-share"
      ],
      "guardrail": [
        "per-goal-conversions",
        "conversions-count",
        "real-noise-verdict",
        "practical-effect-magnitude"
      ],
      "sources": [
        "google-ads",
        "web-analytics"
      ],
      "skills": [
        "paid-efficiency-review",
        "paid-organic-balance",
        "significance-referee"
      ],
      "rungs": [
        "R5"
      ],
      "questions": [
        "Where is our ad spend going?",
        "What is our cost per conversion by campaign?",
        "Which campaigns are losing impression share to rank?",
        "Which search terms should we add as negatives?"
      ],
      "workflows": [
        "paid-query-losses",
        "organic-vs-paid-share"
      ],
      "caveats": "Cost, CPC and spend metrics have a contested direction in the product, a rising CPC is not automatically bad, so state the intended reading rather than colouring the arrow. Conversions depend entirely on which conversion actions the account counts; name them. Geography on the paid feed is unreliable on some tenants and a country filter can silently return zeros, so verify a country-filtered total against the unfiltered one before reporting it.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "search-market-share-report",
      "name": "Search market share report",
      "aliases": [
        "Share of search report",
        "Market position report",
        "Competitive share overview"
      ],
      "audience": "SEO lead",
      "job": "Establish where you stand against the tracked competitive set and whether your own movement or the market's moved the gap.",
      "cadence": "Weekly",
      "summary": "The market-position index: your CTR-modelled share of tracked demand, the leader, the gap to the leader, and how both moved, sliced by intent, category, language or geography. It answers 'are we winning' at a level the keyword table cannot, and it catches the case that a clicks report hides entirely: growing in absolute clicks while losing share because the category grew faster. It is the single most-run family in the estate.",
      "headline": [
        "search-market-share",
        "gap-to-leader",
        "market-share-leader",
        "search-market-share-change"
      ],
      "diagnostic": [
        "market-share-standings-rank",
        "category-market-share",
        "page-market-share",
        "competitor-share-by-rank-bucket",
        "ranked-keyword-coverage",
        "avg-position",
        "clicks"
      ],
      "guardrail": [
        "total-daily-market-share",
        "market-share-table-clicks",
        "real-noise-verdict",
        "practical-effect-magnitude"
      ],
      "sources": [
        "rank-tracking",
        "search-console"
      ],
      "skills": [
        "market-share-review",
        "competitor-deep-dive",
        "significance-referee",
        "set-analysis-scope"
      ],
      "rungs": [
        "R2"
      ],
      "questions": [
        "What is our search market share and who leads?",
        "Are we gaining or losing share against competitors?",
        "Did we move, or did the market move?",
        "How does our share differ by intent?"
      ],
      "workflows": [
        "market-share-daily",
        "share-by-language",
        "nonbrand-intent",
        "segment-share-drivers",
        "intent-vertical-share",
        "page-niche-share",
        "share-trajectory-quarter",
        "category-decline-verdict"
      ],
      "caveats": "Share is meaningless without a segment, an unsegmented number silently averages across unrelated keyword sets. It is CTR-modelled from ranking position against a tracked competitor set, so it estimates share of that set's demand, not share of all search. The click total carried on the market-share table is a modelled figure and undercounts Search Console clicks materially; quote Search Console for clicks and this report for share.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "search-opportunity-report",
      "name": "Search opportunity report",
      "aliases": [
        "Striking distance report",
        "Quick wins report",
        "New page backlog",
        "Content gap report",
        "Opportunity explorer"
      ],
      "audience": "SEO lead",
      "job": "Rank this period's addressable upside, near-page-one pushes and uncovered demand, by the clicks each move would return.",
      "cadence": "Monthly",
      "summary": "Two kinds of upside in one ordered list: queries sitting just off page one where an existing page can be pushed, and demand with no dedicated page at all where new content is the move. Each candidate carries the impressions behind it and an estimated click gain, so a fixed content budget can be spent on the largest returns rather than the loudest requests.",
      "headline": [
        "striking-distance-candidates",
        "potential-clicks-adjusted",
        "impressions",
        "not-ranked-keywords"
      ],
      "diagnostic": [
        "avg-position",
        "actual-ctr",
        "expected-ctr",
        "ctr-gain",
        "potential-clicks-raw",
        "clicks",
        "keyword-rank-gap",
        "losing-keywords"
      ],
      "guardrail": [
        "aio-haircut",
        "fallback-ctr-prior",
        "ctr-bucket-support",
        "ai-overview-inclusion"
      ],
      "sources": [
        "search-console",
        "rank-tracking"
      ],
      "skills": [
        "striking-distance-sprint",
        "keyword-gap-audit",
        "ctr-opportunity-audit",
        "set-analysis-scope"
      ],
      "rungs": [
        "R2"
      ],
      "questions": [
        "What are our quick wins this month?",
        "Which keywords are just off page one?",
        "Where do we have demand but no page?",
        "What should we build next?"
      ],
      "workflows": [
        "keyword-coverage-gap",
        "nonbrand-weekly-gainers",
        "impressions-without-clicks",
        "query-family-watch"
      ],
      "caveats": "Projected click gain is modelled from a position-to-CTR curve with a reduction applied where an AI Overview is present; both the curve fallback and the reduction constant are unvalidated, so treat the ranking as an ordering, not a forecast. Keywords with thin impressions dominate percentage-based sorts, apply the volume floor. A gap against a community or publisher domain is often not addressable with a page of your own.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "search-to-revenue-report",
      "name": "Search to revenue report",
      "aliases": [
        "SEO ROI report",
        "Organic conversion report",
        "Search revenue attribution",
        "Organic business impact"
      ],
      "audience": "CMO",
      "job": "Connect search visibility to the named business goals leadership actually asks about.",
      "cadence": "Monthly",
      "summary": "The R5 report: organic sessions, the conversions and revenue attributed to them, and the pages and query groups behind those outcomes. It runs from the analytics side rather than from Search Console because that is where the goals live, and it names the attribution model in the report rather than in a footnote. The pairing with visibility metrics is what makes 'ranks fine, converts nothing' visible.",
      "headline": [
        "sessions",
        "conversions-count",
        "conversion-rate",
        "transaction-revenue"
      ],
      "diagnostic": [
        "clicks",
        "users",
        "per-goal-conversions",
        "total-value",
        "transactions",
        "funnel-dropoff-rate",
        "ai-referral-conversions",
        "paid-conversions"
      ],
      "guardrail": [
        "conversion-rate-change",
        "real-noise-verdict",
        "practical-effect-magnitude",
        "web-analytics-events"
      ],
      "sources": [
        "web-analytics",
        "search-console"
      ],
      "skills": [
        "search-to-revenue",
        "monthly-exec-review",
        "cross-domain-correlator",
        "significance-referee"
      ],
      "rungs": [
        "R5"
      ],
      "questions": [
        "What did organic search actually bring in?",
        "Which pages convert, not just rank?",
        "What is our organic conversion rate by segment?",
        "Which query groups drive revenue?"
      ],
      "workflows": [
        "rank-without-revenue",
        "conversion-spike-verdict",
        "ai-assistant-referrals"
      ],
      "caveats": "Last-click attribution understates search's role in assisted paths, say which model produced the number before it goes in a deck. Pre-aggregated analytics exports and raw event feeds behave differently: totals from a pre-aggregated feed can be summed, unique-user style measures cannot, and mixing them inflates rates. Search Console clicks and analytics sessions will not reconcile, and presenting them as the same quantity is the most common error in this report.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "serp-volatility-report",
      "name": "SERP volatility and algorithm update report",
      "aliases": [
        "Algorithm update impact report",
        "Google update report",
        "Volatility report",
        "Market event report"
      ],
      "audience": "In-house strategist",
      "job": "Separate a market-wide ranking event from something you did, and quantify how it landed on your keyword set.",
      "cadence": "On demand",
      "summary": "A market-level read of ranking turbulence: how much the result pages moved across the tracked demand, which domain types gained or lost during the window, how page-one composition changed, and where your own set sits inside that movement. It exists to answer the question asked in every update week, was that us or was that everyone, before anyone starts changing pages.",
      "headline": [
        "serp-volatility-index",
        "page-one-footprint-retention",
        "domain-movers-count"
      ],
      "diagnostic": [
        "search-market-share",
        "avg-position",
        "overall-average-rank",
        "clicks",
        "pop-delta",
        "ranking-movement",
        "competitor-share-by-rank-bucket",
        "ranked-keyword-coverage"
      ],
      "guardrail": [
        "total-daily-market-share",
        "market-share-table-clicks",
        "real-noise-verdict",
        "practical-effect-magnitude"
      ],
      "sources": [
        "rank-tracking",
        "search-console"
      ],
      "skills": [
        "update-week-check",
        "anomaly-investigator",
        "serp-feature-watch",
        "significance-referee"
      ],
      "rungs": [
        "R2"
      ],
      "questions": [
        "Did the algorithm update hit us?",
        "Is this drop market-wide or specific to us?",
        "How volatile were results this week?",
        "Which kinds of sites gained during the update?"
      ],
      "workflows": [
        "category-decline-verdict",
        "competitor-movers-deck",
        "twelve-week-drop"
      ],
      "caveats": "Volatility is measured over a tracked keyword set, so an index built on your segments describes your market and not the web. A confirmed update announcement and a movement in the data are separate facts; correlation across the same window is not attribution, and rollouts run for weeks. Most of the standing evidence for this report is internal market monitoring rather than per-customer boards, so treat the customer-facing framing as newer than the underlying data.",
      "verification": "review",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "technical-seo-audit-report",
      "name": "Technical SEO audit report",
      "aliases": [
        "Site crawl report",
        "Technical health audit",
        "Indexability report",
        "Site health report"
      ],
      "audience": "Technical SEO",
      "job": "Give engineering a ranked list of structural faults blocking pages from being fetched, indexed or consolidated correctly.",
      "cadence": "Monthly",
      "summary": "The crawl-side inventory: what is reachable, what is indexable, where canonicals disagree with reality, where redirect chains and error responses sit, and which templates carry the problem. It is scoped to structural faults rather than performance, Core Web Vitals and linking each have their own report, and it is ordered by how much search value sits behind the fault, not by fault count.",
      "headline": [
        "indexability-flags",
        "status-code-hits",
        "crawl-depth"
      ],
      "diagnostic": [
        "incoming-internal-links",
        "outgoing-internal-links",
        "unique-pages-crawled-by-bots",
        "bot-hits"
      ],
      "guardrail": [
        "clicks",
        "impressions",
        "crawler-response-time",
        "verified-vs-spoofed-googlebot"
      ],
      "sources": [
        "site-crawl",
        "server-logs",
        "search-console"
      ],
      "skills": [
        "technical-health-audit",
        "crawl-efficiency-review",
        "linking-opportunity-review"
      ],
      "rungs": [
        "R1"
      ],
      "questions": [
        "What technical issues are blocking our pages?",
        "Which pages are not indexable and should be?",
        "Where do our canonicals disagree with what ranks?",
        "How deep are our important pages buried?"
      ],
      "workflows": [
        "subpage-portfolio-audit"
      ],
      "caveats": "A crawl is a snapshot with a start URL, a depth limit and a page budget, say what it covered before calling anything site-wide. Deep crawl coverage is population-gated on some properties, so an empty section can mean 'not collected' rather than 'no issues'. A fault count is not a priority list; weight by the impressions and clicks sitting behind the affected pages.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    },
    {
      "slug": "weekly-search-report",
      "name": "Weekly search report",
      "aliases": [
        "Weekly SEO report",
        "Weekly scorecard",
        "Monday scorecard",
        "Weekly reporting pack",
        "SEO weekly"
      ],
      "audience": "SEO lead",
      "job": "Give the practitioner team one defensible read of what search did last week and what to work on next.",
      "cadence": "Weekly",
      "summary": "The standing weekly index: clicks, impressions, average position and CTR for the selected scope, period over period, with the movement broken out by intent, page group and brand vs non-brand. It is the report the Monday standup runs on, and the one every other report drills out of. Every up/down claim on it is gated on a significance verdict rather than asserted from the raw delta.",
      "headline": [
        "clicks",
        "impressions",
        "avg-position",
        "ctr"
      ],
      "diagnostic": [
        "pop-delta",
        "pop-delta-pct",
        "ranking-movement",
        "unique-keywords",
        "unique-pages"
      ],
      "guardrail": [
        "real-noise-verdict",
        "significance-p-value",
        "practical-effect-magnitude",
        "keyword-page-click-coverage"
      ],
      "sources": [
        "search-console",
        "web-analytics",
        "rank-tracking"
      ],
      "skills": [
        "weekly-search-report",
        "search-pulse",
        "significance-referee",
        "rank-movement-review",
        "set-analysis-scope"
      ],
      "rungs": [
        "R2",
        "R5"
      ],
      "questions": [
        "How did organic search do last week?",
        "Are we up or down week over week, and is it real?",
        "Which pages and queries drove the change?",
        "What should the team work on this week?"
      ],
      "workflows": [
        "nonbrand-weekly-gainers",
        "year-over-year-truth",
        "query-family-watch",
        "impressions-without-clicks"
      ],
      "caveats": "Search Console lags one to two days, so the most recent day is usually incomplete, state the max available date before quoting a weekly total. Week-over-week deltas on small segments frequently fail the significance test; say the verdict out loud rather than reading the arrow. If the scope is a filtered segment, name it, because unfiltered and filtered totals are different numbers and get compared by accident.",
      "verification": "verified",
      "lastVerified": "2026-08-04"
    }
  ]
}