Summary
authenticate.webhook() unconditionally performs a session storage lookup (loadSession) on every webhook request, even when the handler never uses session or admin. For high-volume webhook topics this is unnecessary overhead that can saturate database connection pools under burst load.
Current behaviour
In authenticate/webhooks/authenticate.js:
const sessionId = api.session.getOfflineId(check.domain);
const session = await config.sessionStorage.loadSession(sessionId); // always runs
This DB query runs after HMAC validation on every webhook request, regardless of whether the caller uses the returned session or admin context.
Problem
Some webhook topics never need to call back to the Shopify Admin API. For example, a PRODUCTS_UPDATE subscription may only need to read the payload and write to its own database — admin and session are never touched.
Under burst conditions (e.g. a merchant bulk-updating 50–200 products), this produces 50–200 concurrent loadSession DB queries purely to build an admin client that will never be used. On a typical deployment with a connection pool of 5–15, those queries queue up and starve the rest of the application.
Proposed API
An optional flag (or separate method) that skips the session lookup and returns only the HMAC-verified context:
// Option A — flag
const { shop, topic, payload } = await authenticate.webhook(request, {
loadSession: false
});
// session and admin would be undefined/absent on the return type
// Option B — separate method
const { shop, topic, payload } = await authenticate.webhookHmacOnly(request);
The HMAC verification itself must still run — this is only a request to make the session storage call opt-in (or opt-out) rather than unconditional.
Workaround
It is possible to replicate the HMAC check manually using Node's createHmac and skip authenticate.webhook() entirely for these topics, but this requires re-implementing validation logic that the library already owns and should not be the responsibility of app developers.
Impact
Any app with high-volume webhook topics that do not call the Admin API. Unless some pre-filtering using request headers can be done prior to auth, the full auth overhead including db connection is required every time.
Summary
authenticate.webhook()unconditionally performs a session storage lookup (loadSession) on every webhook request, even when the handler never usessessionoradmin. For high-volume webhook topics this is unnecessary overhead that can saturate database connection pools under burst load.Current behaviour
In
authenticate/webhooks/authenticate.js:This DB query runs after HMAC validation on every webhook request, regardless of whether the caller uses the returned session or admin context.
Problem
Some webhook topics never need to call back to the Shopify Admin API. For example, a PRODUCTS_UPDATE subscription may only need to read the payload and write to its own database — admin and session are never touched.
Under burst conditions (e.g. a merchant bulk-updating 50–200 products), this produces 50–200 concurrent loadSession DB queries purely to build an admin client that will never be used. On a typical deployment with a connection pool of 5–15, those queries queue up and starve the rest of the application.
Proposed API
An optional flag (or separate method) that skips the session lookup and returns only the HMAC-verified context:
The HMAC verification itself must still run — this is only a request to make the session storage call opt-in (or opt-out) rather than unconditional.
Workaround
It is possible to replicate the HMAC check manually using Node's createHmac and skip authenticate.webhook() entirely for these topics, but this requires re-implementing validation logic that the library already owns and should not be the responsibility of app developers.
Impact
Any app with high-volume webhook topics that do not call the Admin API. Unless some pre-filtering using request headers can be done prior to auth, the full auth overhead including db connection is required every time.