Build on Shruwd

Measurement API

Trigger measurement cycles and read visibility, trends, crawler activity 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}/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/waitlister/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.

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/waitlister/visibility?engine=google_aio" \
  -H "Authorization: Bearer $SHRUWD_API_KEY"
Parameter
enginegoogle_aio or chatgpt
from toYYYY-MM-DD. to defaults to today in the brand's timezone

Returns { engine, range, asOf, nResponses, entities, prompts }. Each entity carries mentionRate, shareOfVoice and avgProminence, every one of them with its interval or an explicit insufficient_data.

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/waitlister/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/waitlister/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 individual answers

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

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

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.

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