Build on Shruwd

Measurement API

Trigger measurement cycles and read visibility, trends, crawler activity, the sources the answers cite and the individual answers behind them.

Paths on this page are relative to https://shruwd.io/api/v1.

MethodPathScopeRole
POST/brands/{brandId}/cycleswriteeditor
GET/brands/{brandId}/cyclesreadviewer
GET/brands/{brandId}/visibilityreadviewer
GET/brands/{brandId}/visibility/seriesreadviewer
GET/brands/{brandId}/crawlersreadviewer
GET/brands/{brandId}/crawlers/pathsreadviewer
GET/brands/{brandId}/sourcesreadviewer
GET/brands/{brandId}/answersreadviewer

Measurement is asynchronous. Running a cycle schedules work; results arrive over the following hours. Nothing you can call returns a finished measurement, so do not poll in a tight loop and do not report a number before there is one.

Run a cycle

curl -X POST "https://shruwd.io/api/v1/brands/northwind/cycles" \
  -H "Authorization: Bearer $SHRUWD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Creates a manual cycle due now and returns its id. It draws on the same period allowance as any cycle.

One manual cycle per brand at a time: while one is pending or running, another is 409 cycle_in_progress. On a free plan this is the one snapshot, and is 409 snapshot_taken once used. A workspace paused pending review is 409 workspace_on_hold.

GET /brands/{brandId}/cycles?limit= returns recent cycles with their state and counts.

Read visibility

curl "https://shruwd.io/api/v1/brands/northwind/visibility?engine=google_aio" \
  -H "Authorization: Bearer $SHRUWD_API_KEY"
Parameter
enginegoogle_aio (the default), google_ai_mode or chatgpt
from toYYYY-MM-DD. to defaults to today in the brand's timezone

Returns { engine, range, asOf, nResponses, entities, prompts, intents }. Each entity carries mentionRate and shareOfVoice, each with its interval or an explicit insufficient_data, and avgProminence: an average with no interval, near 1 when the entity is named at the start of the answer, null when it was never named.

firstNamed is how often the entity is the first of your tracked companies an answer names, with its interval, over the answers share of voice uses. It is computed when a cycle closes, for 7-, 30- and 90-day ranges; for any other range it is undefined. An untracked company can come earlier, so read it as a sign of being the first pick, not a recommendation.

intents is prompts pooled by question type, buying first: commercial, comparison, problem, informational, navigational, each only when a prompt has it. Each row carries prompts (how many it pools), the summed counts, and selfMentionRate with its own n. Like prompts it covers from to to, while entities describe asOf, so the totals can differ by a few days' runs.

If from reaches past your plan's history window it is clamped, and the response says so in historyFrom rather than failing.

Read the trend

curl "https://shruwd.io/api/v1/brands/northwind/visibility/series?window=30" \
  -H "Authorization: Bearer $SHRUWD_API_KEY"
Parameter
window7, 30 or 90. Default 30
from toDefault is the last ninety days

Returns points (one per cycle close) and, per entity, a series index-aligned with it. A point below the display floor is insufficient_data, never a number.

modelChanges lists the moments the provider changed its underlying models. A difference spanning one of those may be the model rather than you — see When a number has moved.

Read crawler activity

curl "https://shruwd.io/api/v1/brands/northwind/crawlers" \
  -H "Authorization: Bearer $SHRUWD_API_KEY"

Per-bot activity with verified and unverified hits kept separate. Only verified hits count toward anything.

daily carries a per-day series per bot, index-aligned with daily.days.

A day with no log ingest is null, not 0. It means nobody was watching, not that nothing happened — do not chart it as zero.

Read crawler activity per path

Where a bot's errors came from:

curl "https://shruwd.io/api/v1/brands/northwind/crawlers/paths?bot=oai_searchbot&status=error" \
  -H "Authorization: Bearer $SHRUWD_API_KEY"
Parameter
from toDefault is the last thirty days. Per-path detail is kept 90 days
botA botId from the crawlers read, such as oai_searchbot
status2xx, 3xx, 4xx, 5xx or error (4xx or 5xx)
contentOnly1 keeps only pages a person reads
limit1 to 200. Default 50

One row per bot and path, verified hits only. worstStatus tells a missing page (404) from a refusal (403). totalPaths above the rows returned means the list was cut.

contentPage: false marks files and framework data such as _payload.json, and sign-in and account pages. Some frameworks' data files return 404 to every visitor by design, so an error there is rarely a lost citation.

Read the sources the answers cite

Which sites and pages the answers cite, and whose they are:

curl "https://shruwd.io/api/v1/brands/northwind/sources?engine=google_aio" \
  -H "Authorization: Bearer $SHRUWD_API_KEY"
Parameter
from toYYYY-MM-DD. Default is the last thirty days
enginegoogle_aio, google_ai_mode or chatgpt. Default is every engine
promptGroupIdOnly the answers to this prompt. A finding on a prompt carries its id as subjectRef
limit1 to 100. Default 25

One row per site, most-cited first. answers counts the answers citing it, and rate is the share of all answers in answers.total, with its interval, or an explicit insufficient_data below ten answers. byEngine gives each engine's count with its own total. totalSources above the rows returned means the list was cut.

kind says whose a site is: yours or competitor when it is a company you track (named in owner), otherwise review_directory, forum, wikipedia, video or editorial (any other site: a blog, a publication, a vendor). yourAnswers counts the answers citing your own pages there, or videos on one of your YouTube channels. Each site carries its five most-cited pages, without tracking parameters; for a video, the page's owner is the company whose channel published it. findings lists up to three findings about the site that are still open or being fixed.

answers.citingAny is how many answers cite any source at all. ChatGPT often answers without citing anything, so read a share against it: a site in 30% of answers matters more where every answer cites something. It is null when part of the range predates 2026-11-02, when Shruwd started counting it.

Every number here comes from the same daily rollups as the dashboard's Sources tab. Only measurement answers count; a recheck's are left out, as everywhere.

Read individual answers

curl "https://shruwd.io/api/v1/brands/northwind/answers?limit=10" \
  -H "Authorization: Bearer $SHRUWD_API_KEY"

limit is 1–50, default 10. Newest first, measured runs only.

promptGroupId narrows the list to one prompt, and engine to one engine. A finding on a prompt carries that prompt's id as its subjectRef, so this reads the answers behind it:

curl "https://shruwd.io/api/v1/brands/northwind/answers?promptGroupId=$groupId&limit=50" \
  -H "Authorization: Bearer $SHRUWD_API_KEY"

Each answer carries prompt, engine, state, executedAt, whether you were mentioned and at what rank, the surrounding context, the competitors named, and the citations with isSelf marked: a page on your domains, or a video on one of your YouTube channels. ownedVia says which, site or channel.

This is evidence, not a metric. Never compute a rate from these rows — the sample is whatever the last few runs happened to be. It exists so you can read what an answer actually said, which is useful while a brand is still below the display floor.

Next steps