For the complete documentation index, see
llms.txt
Skill: set a brand up in Shruwd
Shruwd (
Everything below is doable over the REST API. There is no onboarding UI to drive and nothing to scrape — one step needs a human, and it is called out in step 1.
Interfaces, in order of preference
- The MCP server. Best if you are running in Claude, ChatGPT, Grok, Claude Code
or Cursor: the tools carry their own descriptions. Hosted at
https://shruwd.io/mcp(Streamable HTTP), where the human signs in with Shruwd when the app connects, or you send an API key asAuthorization: Bearer <key>. Or local, as theshruwd-mcpnpm package over stdio, with a key. Setup for each app:https://shruwd.io/docs/api/mcp-server @shruwd/sdk— a typed TypeScript client. Best if you are writing code.https://shruwd.io/api/v1— plain REST, described athttps://shruwd.io/openapi.json.
Inputs
nameanddomain— the brand to track, e.g.Northwind/northwind.iocompetitors— the brands you expect to be compared againstprompts— the questions buyers actually ask. Start with 10 to 25
No lists yet? After step 2, POST https://shruwd.io/api/v1/brands/{brandId}/setup-suggestions
drafts 10 to 25 prompts, each with the page that should answer it, and up to six
competitors from the brand's homepage and sitemap. Nothing is added: review the draft
with the human, then add what they keep in steps 3 and 4. Send each competitor with the
draft's aliases and contextTerms (matching is exact), and each prompt with its page.
Three drafts per brand per day.
Procedure
- Get a key — this step is the human's. On the hosted MCP server the human
signs in when their app connects instead, choosing read and write access, and
you can skip to step 2. API keys are minted only with an interactive session,
so an agent cannot create its own. Ask the account owner
to sign in at
https://shruwd.io , open Account → API keys, and create a key with read and write scope. Suggested message: "Create a Shruwd API key under Account → API keys and paste it to me — I'll do the rest."
Keys look likesh_live_...and go inAuthorization: Bearer <key>. Treat it as a secret: put it in an environment variable, never in a committed file.
A key is bound to one workspace and reaches its holder's brands there: every brand for the workspace owner, the brands they are a member of otherwise. It never exceeds their role on a brand: reads needviewer, writeseditor, minting a log-ingest tokenadmin, and creating or archiving a brand needs the owner. If you are expected to create the brand in step 2, ask the owner for the key. A brand the key cannot reach is404; refusals are403 not_a_memberand403 insufficient_role. - Create the brand.
POST https://shruwd.io/api/v1/brands { name, domain }. A caller who owns no workspace gets one automatically on this call — there is no workspace resource to create first. A short or common-word brand name ("Front") is refused withcontext_terms_requireduntil you addcontextTerms, words that mark a mention as being about this brand — otherwise every "front-end" counts as one. - Add competitors, before any prompt.
POST https://shruwd.io/api/v1/brands/{brandId}/entities, one call each. Matching is exact on token boundaries, never fuzzy, because a false positive here silently corrupts every metric downstream. A short or common-word name or alias is refused withcontext_terms_requireduntil you supplycontextTerms— the terms that make "Arc" mean the company rather than the word. If you need the human for those, ask now, before step 4. - Add every prompt in one call.
POST https://shruwd.io/api/v1/brands/{brandId}/prompts. These are fixed for the brand and repeated every cycle, which is what makes week-over-week comparison meaningful — so write them as a buyer would ask, not as keywords, and change them rarely. The plan's prompt allowance is one pool across every brand in the workspace, not a per-brand limit; a batch that would exceed it is refused whole with409 plan_limit, carryinglimit,currentandsubmitted.
The first measurement starts within minutes of the first prompts and measures only the prompts and competitors that exist at that moment. On the free plan it is the only measurement the domain ever gets, and there is none at all if step 2 answeredsnapshot: "already_taken". That is why competitors come first and the prompts go in together. - Wait, then check. Measurement is asynchronous: the first cycle starts
within minutes of the prompts and completes within a day. Check after about
fifteen minutes, then about once an hour, never in a tight loop:
GET https://shruwd.io/api/v1/brands/{brandId}/cycles. It lists newest first, and on a weekly plan the first entry is next week's cycle, stillpending. Skip pending cycles, which have not started, and read the newest one that has:running— still measuring.complete— the results are in.partial— some runs failed. Report what exists and say so.failedorskipped_quota— no new numbers. Say that rather than reporting older ones as new.
- Read the results: every engine at once, then each engine.
GET https://shruwd.io/api/v1/brands/{brandId}/visibility?engine=allreturns every engine's mention rate for each entity in one call (byEngine), plus the mention rate across engines (mentionRate): an equal-weight average over the engines that answered through the whole window (engines;joiningnames any that start later). Use it for an overview, and say how many engines it covers. Findings, rechecks and movement are per engine: never report a change in the cross-engine rate as a result of a fix. For share of voice, named first and the per-prompt rows, read each engine:GET https://shruwd.io/api/v1/brands/{brandId}/visibility?engine=google_aio,GET https://shruwd.io/api/v1/brands/{brandId}/visibility?engine=google_ai_mode,GET https://shruwd.io/api/v1/brands/{brandId}/visibility?engine=chatgpt,GET https://shruwd.io/api/v1/brands/{brandId}/visibility?engine=geminiandGET https://shruwd.io/api/v1/brands/{brandId}/visibility?engine=perplexity— the brand'sengineslists the ones its plan measures. Withoutenginethe call returns Google AI Overviews only, so report each engine separately, never as one "AI visibility" number. Each read'sintentssplits the brand's rate by question type, buying (commercial) first. Each company'sfirstNamedis how often it is the first of the tracked companies an answer names (n = share of voice's): a proxy for first pick, not a recommendation.GET https://shruwd.io/api/v1/brands/{brandId}/findingsfor the diagnosed causes and the fixes they recommend. Where the plan shows only its top findings, the list returns those and counts the rest inlockedby severity: say how many are withheld rather than reporting the list as the whole set, and expect403 not_entitledon a locked one.
Reading a metric correctly
This is the part agents most often get wrong, so check your output against it before reporting anything.
Every metric comes back as a DisplayableMetric:
{ "state": "ok", "point": 0.142, "lo": 0.081, "hi": 0.226, "n": 42 }
point,loandhiare proportions from 0 to 1: 0.142 is 14.2%.state: "insufficient_data"means fewer than ten responses exist. It is not zero. Say "not enough data yet", never "0%".- Never quote
pointwithoutloandhi. The interval is usually wide, and a bare number reads as far more certain than the measurement is. - Never say a metric "improved" or "dropped" from two point estimates. Movement requires a significant change whose 95% interval excludes zero AND at least 5 percentage points of change. Shruwd applies both gates itself — report what it says, do not recompute it.
Notes
- Engines tracked today: Google AI Overviews, Google AI Mode, ChatGPT, Gemini and
Perplexity. Google AI Mode is measured from 2026-10-15, Gemini from 2026-11-10 and
Perplexity from 2026-11-11, so a brand's numbers on each read
insufficient_datauntil ten answers exist. Perplexity's answers come from Perplexity's Sonar API, not from the Perplexity app; say so when you report them. - On Starter and Pro, cycles run weekly. The free plan takes one snapshot at setup and
no scheduled cycles. A manual run is
POST https://shruwd.io/api/v1/brands/{brandId}/cycles. - A finding about a question has
subjectType: "prompt_group", and itssubjectRefis thepromptGroupId. The answers behind it:GET https://shruwd.io/api/v1/brands/{brandId}/answers?promptGroupId={subjectRef}&limit=50. When itsrecommendation.targetisnull, no page of the brand's answers the question yet; once one does, set it withPATCH https://shruwd.io/api/v1/prompts/{promptGroupId}{ "page": "https://…" }, and later findings name it. - Plans, prices and limits, as markdown:
https://shruwd.io/pricing.md - Errors are
{ code, message, retryable, details? }. Retry429and5xxwith backoff and honourRetry-After; do not retry a4xxthat is not429. - Full documentation in one fetch:
https://shruwd.io/llms-full.txt · index:https://shruwd.io/llms.txt - Any page is markdown with
.mdappended, e.g.https://shruwd.io/docs/getting-started/overview.md , or asked for withAccept: text/markdown.

