I’m running into a weird one with a filtered products/update webhook and would love a sanity check from the community.
What I’m trying to do
I want products/update to fire only when the product has a metafield custom.trigger = true. Simple enough. The catch: sometimes we save multiple metafields at once (e.g., custom.colors, custom.shape) together with custom.trigger.
What actually happens
-
If I set only
custom.trigger = trueand save → the webhook arrives as expected. -
If I save
custom.trigger = trueand add/update other metafields in the same save (e.g., colors/shape) → no webhook is delivered. -
If I remove the filter completely, I get
products/updateon any change (so the endpoint is fine).
Environment
-
Admin API: GraphQL
2025-01 -
Topic:
PRODUCTS_UPDATE -
Metafields are product-level (not variant)
-
Namespace:
custom -
Callback: Laravel endpoint that just logs and queues a job (working fine)
$variables = [
"topic" => "PRODUCTS_UPDATE",
"webhookSubscription" => [
"callbackUrl" => "https://xxxxx.com/xxx/xxx/xxx/update",
"format" => "JSON",
"metafieldNamespaces" => ["custom"],
"filter" => "metafields.namespace:custom AND metafields.key:trigger AND metafields.value:true"
]
];
public function handle(Request $request)
{
$topic = $request->header('X-Shopify-Topic');
$shopDomain = $request->header('X-Shopify-Shop-Domain');
$webhookId = $request->header('X-Shopify-Webhook-Id');
$payload = $request->json()->all();
Log::info('Shopify webhook received', compact('topic','shopDomain','webhookId') + ['payload'=>$payload]);
// persist + queue job...
return response('OK', 200);
}
What I already tried
-
Kept the filter in the “explicit” form above (namespace/key/value).
-
Tested with and without
includeFields(and with/withoutmetafieldsincluded there). -
Double-checked that
custom.triggeris product-level, not variant. -
Read back the stored subscription with:
query {
webhookSubscriptions(first: 50) {
edges { node { id topic filter includeFields metafieldNamespaces } }
}
}
Everything matches what I create.
Repro steps
-
Create a product-level metafield
custom.trigger(boolean). -
Save product with
custom.trigger = true→products/updatearrives
-
Now, in the same save, set
custom.trigger = trueand add/update other product metafields likecustom.colorsorcustom.shape→ no webhook
I’ve attached a screenshot in my admin to illustrate: when only trigger=true exists, the webhook fires; as soon as I also add Colors/Shape (while keeping trigger true), it stops firing.
Questions
-
Is the metafield filter on
products/updateevaluated only against metafields that are present/changed in that specific event? -
If so, shouldn’t
triggerstill be present when I set it totruein the same save as other metafields? -
Do I need
includeFields: ["metafields"]for metafield filtering to work reliably, or is that unrelated? -
Has anything changed recently in how metafield writes are aggregated into
products/updatevs.metafields/update? -
If my rule is “deliver whenever the product has
trigger=true(regardless of what else changed)”, is the recommended approach to avoid the filter and just checktriggerserver-side after receiving an unfilteredproducts/update?
Happy to provide a webhook_id and timestamps if that helps. Thanks a ton for any pointers!