---
title: "Visibility metrics"
method: GET
path: "/brands/{brandId}/visibility"
tags: ["measurement"]
---

# Visibility metrics

`GET /brands/{brandId}/visibility`

## Request

- Base URL: `https://shruwd.io/api/v1`
- URL: `https://shruwd.io/api/v1/brands/{brandId}/visibility`
- Auth: HTTP bearer

Mention rate and share of voice per tracked entity on one engine over a
window, with per-prompt coverage and the same pooled by question type
(`intents`). Read from precomputed rollups; every
metric is a `DisplayableMetric`. `from` is clamped to the plan's history
window and `historyFrom` says when that happened. `asOf` is the day the
numbers describe when a closed cycle served them.

## Query parameters

- `engine` 'google_aio' | 'google_ai_mode' | 'chatgpt': `google_aio` — Google AI Overviews. `google_ai_mode` — Google AI Mode, tracked since 2026-10-15. `chatgpt` — ChatGPT.
- `from` string, date
- `to` string, date

## Response `200`

Visibility.

- Visibility
  - `brand` object, required
    - `brandId` string, required
    - `name` string, required
    - `timezone` string, required
  - `engine` 'google_aio' | 'google_ai_mode' | 'chatgpt', required: `google_aio` — Google AI Overviews. `google_ai_mode` — Google AI Mode, tracked since 2026-10-15. `chatgpt` — ChatGPT.
  - `range` object, required
    - `from` string, date, required
    - `to` string, date, required
  - `historyFrom` string, date, nullable, required: Set when `from` was moved forward to the plan's history window.
  - `asOf` string, date, nullable, required: The day the numbers describe, when a closed cycle served them.
  - `nResponses` integer, required
  - `entities` EntityVisibility[], required
    - `entityId` string, required
    - `canonicalName` string, required
    - `isSelf` boolean, required
    - `mentionRate` union, required: A metric that can be shown. Never a bare number: either a point estimate with its 95% interval and `n`, or an explicit reason there is no number. `insufficient_data` is **not** zero.
      - object
        - `state` 'ok', required
        - `point` number, required: Proportion in [0, 1].
        - `lo` number, required: Lower bound of the 95% interval.
        - `hi` number, required: Upper bound of the 95% interval.
        - `n` integer, required: Responses the estimate rests on.
      - object
        - `state` 'insufficient_data', required
        - `n` integer, required
        - `needed` integer, required: How many more responses would cross the floor of ten.
      - object
        - `state` 'undefined', required
        - `n` integer, required
        - `reason` string, required
    - `shareOfVoice` union, required: A metric that can be shown. Never a bare number: either a point estimate with its 95% interval and `n`, or an explicit reason there is no number. `insufficient_data` is **not** zero.
      - object
        - `state` 'ok', required
        - `point` number, required: Proportion in [0, 1].
        - `lo` number, required: Lower bound of the 95% interval.
        - `hi` number, required: Upper bound of the 95% interval.
        - `n` integer, required: Responses the estimate rests on.
      - object
        - `state` 'insufficient_data', required
        - `n` integer, required
        - `needed` integer, required: How many more responses would cross the floor of ten.
      - object
        - `state` 'undefined', required
        - `n` integer, required
        - `reason` string, required
    - `sovInterval` 'bootstrap' | 'pooled_daily' | 'none', required: How the share-of-voice interval was obtained. `pooled_daily` is approximate (slightly narrow).
    - `avgProminence` number, nullable, required: Mean of 1 − (characters before the first mention ÷ answer length), over the answers that name the entity: near 1 = the start, near 0 = the end. Higher is more prominent. No interval; null when never named.
    - `firstNamed` union, required: A metric that can be shown. Never a bare number: either a point estimate with its 95% interval and `n`, or an explicit reason there is no number. `insufficient_data` is **not** zero.
      - object
        - `state` 'ok', required
        - `point` number, required: Proportion in [0, 1].
        - `lo` number, required: Lower bound of the 95% interval.
        - `hi` number, required: Upper bound of the 95% interval.
        - `n` integer, required: Responses the estimate rests on.
      - object
        - `state` 'insufficient_data', required
        - `n` integer, required
        - `needed` integer, required: How many more responses would cross the floor of ten.
      - object
        - `state` 'undefined', required
        - `n` integer, required
        - `reason` string, required
    - `modelIds` string[], required: Provider model identifiers seen in the window. A change here can move metrics on its own.
  - `prompts` PromptCoverage[], required
    - `promptGroupId` string, required
    - `text` string, required
    - `intent` string, required
    - `nResponses` integer, required
    - `selfMentionCount` integer, required
    - `unbrandedCount` integer, required: Responses that mentioned no tracked entity at all.
    - `emptyCount` integer, required: Responses where the engine produced no AI answer.
    - `selfMentionRate` union, required: A metric that can be shown. Never a bare number: either a point estimate with its 95% interval and `n`, or an explicit reason there is no number. `insufficient_data` is **not** zero.
      - object
        - `state` 'ok', required
        - `point` number, required: Proportion in [0, 1].
        - `lo` number, required: Lower bound of the 95% interval.
        - `hi` number, required: Upper bound of the 95% interval.
        - `n` integer, required: Responses the estimate rests on.
      - object
        - `state` 'insufficient_data', required
        - `n` integer, required
        - `needed` integer, required: How many more responses would cross the floor of ten.
      - object
        - `state` 'undefined', required
        - `n` integer, required
        - `reason` string, required
  - `intents` IntentCoverage[], required: `prompts` pooled by question type, buying first: commercial, comparison, problem, informational, navigational, each listed only when it has a prompt. Over the request window like `prompts`, so the totals can differ by a few days' runs from `entities`, which describe `asOf`.
    - `intent` 'informational' | 'comparison' | 'commercial' | 'navigational' | 'problem', required: Why someone would ask the prompt. `informational` — learning about a topic. `comparison` — weighing named options. `commercial` — choosing what to buy. `navigational` — looking for a specific site or brand. `problem` — fixing something. The intent decides which diagnostic rules apply to the prompt's results.
    - `prompts` integer, required: Prompts pooled. A type with few is dominated by them.
    - `nResponses` integer, required
    - `selfMentionCount` integer, required
    - `unbrandedCount` integer, required: Responses that mentioned no tracked entity at all.
    - `emptyCount` integer, required: Responses where the engine produced no AI answer.
    - `selfMentionRate` union, required: A metric that can be shown. Never a bare number: either a point estimate with its 95% interval and `n`, or an explicit reason there is no number. `insufficient_data` is **not** zero.
      - object
        - `state` 'ok', required
        - `point` number, required: Proportion in [0, 1].
        - `lo` number, required: Lower bound of the 95% interval.
        - `hi` number, required: Upper bound of the 95% interval.
        - `n` integer, required: Responses the estimate rests on.
      - object
        - `state` 'insufficient_data', required
        - `n` integer, required
        - `needed` integer, required: How many more responses would cross the floor of ten.
      - object
        - `state` 'undefined', required
        - `n` integer, required
        - `reason` string, required

## Other responses

- `404`: `not_found`: no such resource in this workspace.
- `default`: Every failure has this body.

---

[API](https://skmtc.dev/shruwd/apis/shruwd-api.md) · [All operations](https://skmtc.dev/shruwd/apis/shruwd-api/llms.txt) · [OpenAPI document](https://skmtc.dev/shruwd/apis/shruwd-api/revisions/64a5da079928?raw)
