Skip to content

CMS and deploy webhooks

The loop needs to know when a change went live. Every site gets a hook URL; a publish, a theme deploy or a release posted there is written to the site’s change log, the site audit’s findings it plausibly addresses move to implemented with the CMS as the actor, and the next run confirms or refutes them. A Fix a page or Foundations play passes its acceptance check once a run no longer finds its issue, and its verdict window opens from there. Results reach Slack, Teams, email and the issue in your tracker.

On the site’s page, Changes from your CMS, press Enable. The panel shows the hook URL (with a per-site token in it), fields for the providers that sign their calls, and two choices:

  • Also mark open findings: by default only accepted findings (and refuted ones, for a retry) are marked when their page changes; open ones are left for a person to triage.
  • Queue a change run after events go quiet: half an hour after the last event, at most once a day, within the plan’s allowance. A theme deploy is the case that matters: one deploy changes every page of a type.

Rotate issues a new token and invalidates the old URL. Remove hook deletes it.

Event Findings marked
a page (a URL, or a list of URLs) page-scoped findings on exactly those URLs
a template (theme deploy, layout change) template-scoped and site-scoped findings
a site (a release, no detail) template-scoped and site-scoped findings

A page event never marks a template finding: one edited post is not evidence that a template was fixed. The event and what it marked are visible in the change log and in the audit log.

Any deploy step can POST JSON to the hook URL:

Terminal window
curl -X POST "$VERCATUS_HOOK_URL" -H "content-type: application/json" \
-d '{ "kind": "page", "urls": ["/pricing", "https://www.example.com/docs/setup"], "note": "release 2026.09.3" }'

kind is page, template or site; urls may be paths or absolute; note and topic are free text kept with the event; source (or the header X-Vercatus-Source) names the system. Bodies over 512 KB are refused. The URL’s token is the only authentication for this shape, so treat it as a secret.

No plugin from the directory is needed. Either paste the snippet below into a code-snippets plugin or the theme’s functions.php, or download it as a single-file plugin, zip it and upload it under Plugins, Add new, Upload:

vercatus-changes.php

Set VERCATUS_HOOK_URL in wp-config.php (or at the top of the file) to the site’s hook URL. It sends a page event when a post, page or product is published or updated, and a template event when the theme is switched or the customiser is saved. Requests are non-blocking; publishing is not slowed.

In the Shopify admin, Settings, Notifications, Webhooks: create subscriptions for products/update, collections/update, pages/update, articles/update and themes/publish, format JSON, pointing at the hook URL. Copy the signing secret shown under the webhooks list into Shopify webhook secret in Vercatus. Every call is verified against it (X-Shopify-Hmac-Sha256); unsigned or mismatched calls are refused. Product, collection, page and article events become page events on the storefront’s URL; a theme publish becomes a template event.

Settings, Webhooks: a webhook on entry publish and unpublish, URL the hook URL, and a custom header X-Vercatus-Secret set to a value you also paste into Contentful shared secret in Vercatus. The entry’s slug field (or path / url) becomes the page URL through the URL template ({origin}/{type}/{slug}, with {id} available) or, when no template is set, by finding the sitemap URL that ends in the slug. An entry without a resolvable URL is recorded as a site event.

Manage, API, Webhooks: a GROQ-powered webhook on create, update and delete, URL the hook URL, with a secret; paste the same secret into Sanity webhook secret. Calls are verified against the sanity-webhook-signature header. Include _id, _type and slug in the projection; the URL is resolved the same way as for Contentful.

A deploy changes every page of a type at once, so it is a template event that names the commit. With Queue a change run on, the check follows ten minutes after the deploy rather than thirty, and its alert, its run page and the runs list say which deploy it checked, how many pages it checked and where AI crawlers are newly refused, or that “the deploy changed nothing the machines see”, which a deploy is always worth one line for. Builds still going and pings are answered and ignored.

  • GitHub: repository Settings, Webhooks: payload URL the hook URL, content type JSON, a secret; events Deployment statuses (a successful deployment is the event; a push is recorded as a site change). Paste the secret into GitHub webhook secret; calls are verified against X-Hub-Signature-256.
  • Vercel: team Settings, Webhooks: URL the hook URL, event Deployment Succeeded, the project. Paste the secret Vercel shows into Vercel webhook secret; calls are verified against x-vercel-signature. Preview deployments are ignored; production ones count.
  • Netlify: site Settings, Notifications, Outgoing webhook on Deploy succeeded, URL the hook URL, with a JWS secret. Paste it into Netlify JWS secret; calls are verified against X-Webhook-Signature and the body hash it carries. Deploys to contexts other than production are ignored.

The hook tells Vercatus a change shipped. To tell the search engines that crawl on request, a deploy step can also send the changed, added and deleted URLs to IndexNow: a submission to one endpoint is shared with all participating engines, which include Microsoft Bing, Naver, Seznam.cz, Yandex and Yep. Google is not one of them, so use Search Console for Google. Put a key file at the site root (a text file named after the key, holding the key) and post the URLs as JSON to https://api.indexnow.org/IndexNow. Bing says IndexNow keeps information fresh across search and AI experiences, and Copilot answers draw on the Bing index.

A publish says “this URL changed”, not “the finding was addressed”. A page republished for a typo marks its accepted findings implemented, and the next run will refute them; the effect estimate reports whether the page’s content actually changed, so those cases read as what they are. Headless systems know entries, not URLs; the template or the sitemap lookup has to be right for page events to match. Template events are broad by design.