Overview
Sight AI does not have a native Sanity plugin today. Instead, you connect the two platforms with Sight AI’s Webhook integration plus a small custom API route that writes incoming articles into your Sanity dataset. This is the same pattern Sanity recommends for syncing external systems: Sight AI POSTs a signedarticle.ready payload to your endpoint, and your handler creates or updates Sanity documents via the Content API.
This integration requires a developer. If you don’t have one in-house, your Sanity agency can usually set this up in half a day. Non-technical teams can also use Zapier as a no-code middle layer, though HTML and image handling are more limited.
How it works
1
Sight AI ships an article
When you sync manually, Autopilot runs, or an AI agent publishes, Sight AI POSTs the full article (HTML, SEO fields, images, metadata) to your webhook URL.
2
Your handler verifies and upserts
Your API route verifies the HMAC signature, looks up an existing Sanity document by
article.id, and creates or updates it.3
Your frontend reads from Sanity
Your Next.js site (or other frontend) continues to fetch content from Sanity with GROQ — nothing changes on the read path.
Requirements
- Sanity project — With a dataset and a
post(or equivalent) schema - Sanity write token — Editor or custom role with create/update permissions
- Public HTTPS endpoint — Vercel, Netlify, Cloudflare Workers, etc. (local dev via ngrok works for testing)
- Developer access — To add a schema field, deploy the webhook route, and configure environment variables
- Sight AI workspace — Owner or admin role to configure the webhook and set it as the active CMS
Step 1: Add a Sight AI ID to your Sanity schema
Store Sight AI’s stablearticle.id on every document so re-syncs update in place instead of creating duplicates. Never upsert by slug alone — users can rename slugs inside Sight AI.
Add a hidden, read-only field to your post schema:
Deploy your schema changes to Sanity Studio before wiring up the webhook.
Step 2: Create a Sanity write token
- Go to sanity.io/manage and open your project
- Navigate to API → Tokens
- Click Add API token
- Name it
Sight AI webhook(or similar) - Set permissions to Editor (or a custom role with document create/update and asset upload)
- Copy the token — you won’t see it again
Step 3: Deploy a webhook handler
The handler lives in your codebase (not inside Sight AI). Below is a complete Next.js App Router example. Drop it atapp/api/webhooks/sight-ai/route.ts.
Environment variables
Add these to your hosting provider (e.g. Vercel → Project → Settings → Environment Variables):Example handler (HTML body field)
This example stores article HTML in abodyHtml text field — the fastest path to a working integration. See Body content options if you need Portable Text instead.
Step 4: Configure Sight AI
1
Open webhook settings
In Sight AI, go to Integrations → Webhook for your site.
2
Enter your endpoint URL
Paste
https://yourdomain.com/api/webhooks/sight-ai and save.3
Copy the webhook secret
Use Managed by Sight AI (recommended). Copy the secret when shown and add it as
SIGHT_AI_WEBHOOK_SECRET in your hosting environment, then redeploy.4
Test the connection
Click Test connection. Your handler should return
2xx. Test events include "test": true — the example above short-circuits those without writing to Sanity.5
Set webhook as Active CMS
Click Set as Active CMS. From now on, articles that ship from Sight AI — manual sync, Autopilot, or AI agents — are delivered to your Sanity handler instead of WordPress, Webflow, or another CMS.
Body content options
Sight AI sendsarticle.content as HTML. Sanity schemas usually use Portable Text (array of block types), not raw HTML. Pick the approach that fits your stack:
Option A — HTML field (recommended for getting started)
Add a string field to your schema and render it withdangerouslySetInnerHTML (or an HTML sanitizer) in your frontend:
Cons: You manage HTML rendering and sanitization yourself.
Option B — Portable Text (recommended for production Studio UX)
Convert HTML to Portable Text in your handler using@portabletext/block-tools and your schema’s block types. This gives editors a native Sanity editing experience after the initial import.
Pros: Native Studio editing, consistent with other Sanity content.Cons: More setup — conversion quality varies by HTML complexity; test with real Sight AI output. If you go this route, replace
bodyHtml: article.content in the example with a htmlToBlocks() call keyed to your block schema. Sanity’s guide on integrating external data sources covers the sync-plugin pattern in more depth.
Image handling
Sanity expects images in its asset library, not external CDN URLs. Follow these rules to avoid duplicate assets:- First delivery for an
article.id— downloadmain_image_urland upload to Sanity (as in the example above) - Subsequent deliveries — skip re-upload if the document already has
mainImage - User swaps the image in Sight AI — clear
mainImagein Sanity (or add an admin action), then re-sync from Sight AI
Category mapping
Sight AI sendsarticle.category as a name string, not a Sanity document ID. In your handler you can:
- Store the name directly on a string field (simplest)
- Resolve to a category reference — query
*[_type == "category" && title == $name][0]._idand set a reference field - Use Sight AI Filters — define categories in the webhook Filters tab with
external_idvalues you map in code (the name is still what arrives in the payload today)
Publishing workflow
Manual sync
- Open an article in Sight AI
- Click Send Webhook (or Sync to CMS when webhook is active)
- Confirm the delivery in Integrations → Webhook → Monitoring
Autopilot and AI agents
When webhook is the active CMS, Autopilot and agent-driven publishes use the same delivery path automatically — no extra configuration.Trigger mode
Under webhook Advanced settings:- Manual (default) — fires when you explicitly sync, via Autopilot/agents, or bulk actions
- Automatic — also fires immediately when non-Autopilot generation completes
Field reference
Quick mapping from Sight AI webhook payload to Sanity:
Full payload spec: Webhook Integration → The payload.
Troubleshooting
401 Invalid signature
401 Invalid signature
Same causes as any webhook integration — see Webhook Troubleshooting → 401 Invalid signature. The most common mistake is hashing a re-parsed JSON body instead of the raw request string.
Articles keep duplicating in Sanity
Articles keep duplicating in Sanity
You’re likely upserting by
slug instead of article.id. Add the sightAiId field, query by it, and use createOrReplace with the existing _id. Slug renames in Sight AI must update the existing document, not create a new one.Images are multiplying in the Media library
Images are multiplying in the Media library
You’re re-uploading on every webhook delivery. Gate uploads: only fetch and upload when the Sanity document has no
mainImage yet. Sight AI re-sends the same URL on every edit and re-sync.HTML looks wrong in Sanity Studio
HTML looks wrong in Sanity Studio
You’re storing HTML in a Portable Text field (or vice versa). Either use a dedicated
bodyHtml text field, or convert HTML to blocks before writing to a body array field.403 or insufficient permissions from Sanity
403 or insufficient permissions from Sanity
Your write token lacks create/update or asset upload permissions. Regenerate a token with Editor access (or grant
create, update, and upload on the relevant document/asset types).Webhook succeeds but the live site doesn't update
Webhook succeeds but the live site doesn't update
The Sanity write succeeded, but your frontend cache hasn’t refreshed. If you use Next.js ISR, call
revalidatePath for the article and listing routes in your handler after the Sanity write. See Webhook Integration → Cache invalidation.I don't have a developer — can I still do this?
I don't have a developer — can I still do this?
Use Zapier with a Webhooks by Zapier → Catch Hook trigger and a Sanity action module. It’s faster to prototype but harder to get right for HTML bodies and featured images. Most Sanity customers work with their agency for a one-time setup.
Best practices
- Upsert by
article.id— store it assightAiIdon every document - Verify HMAC on the raw body before parsing JSON
- Return 2xx within 30 seconds — do slow work (image upload) only if it fits your timeout budget
- Don’t re-upload images on every delivery
- Use HTTPS in production — required for non-localhost webhook URLs
- Keep secrets in env vars — never commit
SANITY_WRITE_TOKENorSIGHT_AI_WEBHOOK_SECRETto git - Monitor deliveries in Sight AI under Integrations → Webhook → Monitoring
Next steps
- Webhook Integration — full payload spec, security, and retry behavior
- Autopilot — automate article generation and delivery
- Bing IndexNow — notify search engines when new URLs go live
- Sanity: Integrating external data sources — Sanity’s official sync-plugin guide