Skip to main content

Webflow publish webhook

Site Health can automatically rescan a site every time you publish it in Webflow. This is what makes "did my latest publish break anything?" a solved problem — there's always a fresh post-publish scan to compare against.

How it works

Webflow fires a site_publish event whenever a site is published (including staging publishes). Site Health's /api/webhooks/webflow endpoint receives the event, verifies the signature against your Webflow workspace's secret, looks up the site by its Webflow site ID, and enqueues a scan on the BullMQ scan queue.

Scans are deduplicated — if a scan is already queued or running for that site, the webhook is a no-op. Back-to-back publishes never pile up multiple in-flight scans per site.

When you connect a Webflow workspace via Settings → Webflow connections → Connect Webflow, Site Health asks for the sites:write scope. If granted, the webhook is registered for every site in the workspace automatically — no manual setup required.

To verify, open a site's detail page → Settings → Integrations. The webhook status shows "Registered" with the webhook ID.

Manual setup

If automatic registration failed (typically because the OAuth app was connected before the webhook scope was added, or you granted only read scopes), register it manually per site:

  1. In Webflow, open the site → Site Settings → Apps & Integrations → Webhooks.
  2. Click Add webhook.
  3. Trigger type: Site publish.
  4. Webhook URL: https://sitehealth.octagramlabs.com/api/webhooks/webflow.
  5. Click Save.

Publish the site once to confirm. Within a few seconds, a new scan should appear in Site Health with status queuedrunningcomplete.

Deduplication behavior

The webhook handler calls createAndEnqueueScan(). That function throws SCAN_ALREADY_ACTIVE if a scan for the site is already in queued or running status. The webhook handler catches this and returns 200 to Webflow (so Webflow doesn't retry) but logs scan_already_active.

Practical implication: if you publish, publish again 30 seconds later, and publish a third time 5 minutes later, you'll get one scan from the first publish (which covers all the changes since it scans the live site) and possibly a second scan from the third publish if the first finished in time. You never get three scans competing.

Use the budget-check API in CI to fail deploys when a post-publish scan drops below budget. Use the Claude.ai connector with prompts like "did anything regress since the last publish?" — the get_regression_report MCP tool compares the latest webhook-triggered scan against the previous one.

Troubleshooting

Publishes aren't triggering scans. In Webflow, open Site Settings → Apps & Integrations → Webhooks and confirm a site_publish webhook is listed with the Site Health URL. If it's missing, register it manually (steps above). If it's listed but not firing, click into it — Webflow shows recent deliveries and their response codes. A 401 or 403 means the signature check failed (reconnect the Webflow workspace in Site Health to refresh the secret).

Webhook fires but no scan appears. Check the Site Health scans list for the site. A scan with status failed means the worker picked it up but Lighthouse errored (usually a site down, redirect loop, or robots.txt blocking Lighthouse). The worker retries up to 3 times before marking the scan failed.

Multiple publishes, only one scan. Expected — see the deduplication section above. If you need a scan for every single publish, that's not currently supported; consider comparing scans via the regression report instead.

"Unknown site" in webhook logs. The Webflow site ID in the event payload doesn't match any site in Site Health. Usually means the site was disconnected from Site Health but the webhook is still registered in Webflow. Either reconnect the site or delete the webhook in Webflow's UI.

Signature verification failing. Happens if your Webflow workspace OAuth token was rotated (reconnected in Webflow's dashboard) without reconnecting inside Site Health. Go to Settings → Webflow connections → Reconnect.