Shopify OTel Kit
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.
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.
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.
1export function instrumentWebhooks(app: Express) {2 const original = app.post.bind(app)34 app.post = ((path: string, ...handlers: RequestHandler[]) => {5 if (!path.startsWith('/webhooks/')) {6 return original(path, ...handlers)7 }89 const wrappedHandlers = handlers.map(handler =>10 async (req: Request, res: Response, next: NextFunction) => {11 const topic = req.headers['x-shopify-topic'] as string12 const shop = req.headers['x-shopify-shop-domain'] as string1314 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 })2223 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 error31 } finally {32 span.end()33 }34 })35 }36 )3738 return original(path, ...wrappedHandlers)39 }) as typeof app.post40}41
Interested in similar work?
Let's discuss how I can help bring your Shopify project to life.