Documentation Index
Fetch the complete documentation index at: https://docs.trysight.ai/llms.txt
Use this file to discover all available pages before exploring further.
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
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.
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.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:
| Sanity field | Sight AI source | Notes |
|---|---|---|
title | article.title | Required |
slug | article.slug | Use { _type: 'slug', current: article.slug } |
bodyHtml or body | article.content | See Body content options |
excerpt | article.summary | Optional |
seo.title | article.seo_title | Optional |
seo.description | article.seo_meta_description | Optional |
mainImage | article.main_image_url | Upload to Sanity assets — see Image handling |
category | article.category | String or reference — map in your handler |
authorName | article.author_name | Optional string |
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
| Variable | Example |
|---|---|
SANITY_PROJECT_ID | abc123de |
SANITY_DATASET | production |
SANITY_WRITE_TOKEN | sk... |
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
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.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.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:| Sight AI path | Sanity field (example) |
|---|---|
article.id | sightAiId (upsert key) |
article.slug | slug.current |
article.title | title |
article.content | bodyHtml or body (Portable Text) |
article.summary | excerpt |
article.seo_title | seo.title |
article.seo_meta_description | seo.description |
article.main_image_url | mainImage (asset reference) |
article.category | category (string or ref) |
article.author_name | authorName |
article.target_keyword | targetKeyword (optional custom field) |
article.is_featured | featured (boolean) |
article.published_at | publishedAt (datetime) |
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