GROQ Webhooks: changedAny() syntax and triggering on both create and update

9 replies
Last updated: Nov 29, 2025
Hi, I have two questions about GROQ webhooks:

changedAny syntaxLooks like the
docs here are off when you do
delta::changedAny(<more than one field>)
more. I had to do two paretheses, e.g
delta::changedAny((name, phone))
, not to get invalid GROQ.

Trigger on both update and created with changedAny So, what’s the best practice (if it exists any best practices yet :)) when registrering webhooks. I’m trying to make a webhook for a specific type of documents fire on both creation
and on update only when specific fields has changed. I’m trying
_type == "customer" && delta::changedAny((field1, field2, ...))
. This hook won’t fire on creation because if the
delta::changedAny
I guess.
So do you recommend registering two separate webhooks in this case? Or is there a way to say
“fire on both creation, and on update iff these fields changed”?
AI Update

Great questions! You're absolutely right about both issues.

changedAny Syntax with Double Parentheses

The documentation has been updated to reflect this, but you do indeed need double parentheses when using delta::changedAny() with multiple fields:

delta::changedAny((name, phone))

The inner parentheses create an array of field names, which is what the function expects.

Triggering on Both Creation and Field Changes

For your second question about firing webhooks on both document creation and updates when specific fields change, the recommended approach is to use a single webhook with a condition that checks for document creation:

_type == "customer" && (delta::changedAny((field1, field2)) || before() == null)

The before() == null check returns true when a document is being created (since there's no "before" state). You could also use before()._createdAt == null but before() == null is cleaner and works just as well.

This approach is better than two separate webhooks because:

  • It's DRY (Don't Repeat Yourself)
  • It reduces redundant HTTP requests and bandwidth usage
  • It's easier to maintain

You can also use this pattern in your webhook projection to determine if an event was a creation:

{
  "created": before() == null,
  // ... other fields
}

Note that while webhooks are great for many use cases, consider Sanity Functions for more complex event-driven logic, as they provide serverless compute directly within Sanity with native integration and better security.

Show original thread
9 replies

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?