Back to Work
Observability Toolkit2026

Shopify OTel Kit

OpenTelemetryObservabilityTracingWebhooksNode.js

A plug-and-play OpenTelemetry instrumentation kit for Shopify apps — automatic tracing of webhook handlers, API calls, and background jobs with zero-config export to any OTel-compatible backend.

The Challenge

Shopify apps operate in a distributed environment: webhooks arrive asynchronously, Admin API calls fan out across multiple endpoints, and background jobs process data in queues. When something fails, developers are left grep-ing through logs with no way to trace a customer action across the entire processing chain.

The Solution

Built an instrumentation library that auto-instruments common Shopify app patterns: webhook receipt and processing, Admin/Storefront API calls, Prisma database queries, and queue job execution. Traces connect the full lifecycle from Shopify webhook to final database write.

Design
Code
Result
src/instrumentations/webhook.tstypescript
  1export function instrumentWebhooks(app: Express) {  2  const original = app.post.bind(app)  3  4  app.post = ((path: string, ...handlers: RequestHandler[]) => {  5    if (!path.startsWith('/webhooks/')) {  6      return original(path, ...handlers)  7    }  8  9    const wrappedHandlers = handlers.map(handler => 10      async (req: Request, res: Response, next: NextFunction) => { 11        const topic = req.headers['x-shopify-topic'] as string 12        const shop = req.headers['x-shopify-shop-domain'] as string 13 14        const span = tracer.startSpan(`shopify.webhook.${topic}`, { 15          attributes: { 16            'shopify.topic': topic, 17            'shopify.shop': shop, 18            'shopify.webhook_id': req.headers['x-shopify-webhook-id'], 19            'shopify.api_version': req.headers['x-shopify-api-version'], 20          }, 21        }) 22 23        return context.with(trace.setSpan(context.active(), span), async () => { 24          try { 25            await handler(req, res, next) 26            span.setStatus({ code: SpanStatusCode.OK }) 27          } catch (error) { 28            span.setStatus({ code: SpanStatusCode.ERROR }) 29            span.recordException(error as Error) 30            throw error 31          } finally { 32            span.end() 33          } 34        }) 35      } 36    ) 37 38    return original(path, ...wrappedHandlers) 39  }) as typeof app.post 40} 41
Scroll to explore
Tech Stack
OpenTelemetry SDKNode.jsExpress/HonoPrismaShopify APIOTLPTypeScript

Interested in similar work?

Let's discuss how I can help bring your Shopify project to life.