Building Custom Shopify Apps

Building Custom Shopify Apps

A complete guide to creating, launching, and marketing your Shopify app

March 20, 202512 min read

Introduction

The Shopify ecosystem offers tremendous opportunities for developers to create custom apps that solve real problems for merchants. This guide walks through planning, building, launching, and growing a successful Shopify app with practical examples.

Why build a custom Shopify app?

  • Unlock unique merchant workflows and integrations
  • Create recurring revenue via subscription pricing
  • Differentiate with bespoke features and UX
  • Scale your product across thousands of stores

Plan your app

1) Market Research

  • Identify merchant pain points
  • Analyze competing apps and gaps
  • Define a clear value proposition
  • Decide pricing and differentiation

2) Technical Planning

  • Choose stack (Node/Remix/Next.js, PostgreSQL, Redis)
  • Design multi-tenant architecture
  • Scope Shopify Admin/Storefront API usage
  • Plan scalability, rate limits, and background jobs

Set up your environment

Prerequisites

  • Install Shopify CLI
  • Create a Partner account and dev store
  • Configure app authentication (OAuth)
  • Initialize repo and CI/CD

Project Structure (example)

app/
├─ src/
│  ├─ server/
│  │  ├─ oauth.ts
│  │  ├─ webhooks.ts
│  │  └─ shopify.ts
│  ├─ routes/
│  └─ ui/
├─ .env
└─ package.json

Build the core

1) OAuth installation flow

Node/Express example

// oauth.ts
import express from 'express'
import crypto from 'crypto'
import axios from 'axios'

const router = express.Router()

router.get('/shopify/auth', (req, res) => {
  const shop = String(req.query.shop)
  const state = crypto.randomBytes(16).toString('hex')
  const redirectUri = process.env.APP_URL + '/shopify/callback'
  const scopes = 'read_products,write_products'
  const url = 'https://' + shop + '/admin/oauth/authorize'
    + '?client_id=' + process.env.SHOPIFY_API_KEY
    + '&scope=' + scopes
    + '&redirect_uri=' + encodeURIComponent(redirectUri)
    + '&state=' + state
  res.redirect(url)
})

router.get('/shopify/callback', async (req, res) => {
  const { shop, code } = req.query as { shop: string; code: string }
  const tokenResp = await axios.post('https://' + shop + '/admin/oauth/access_token', {
    client_id: process.env.SHOPIFY_API_KEY,
    client_secret: process.env.SHOPIFY_API_SECRET,
    code,
  })
  // store tokenResp.data.access_token per shop (multi-tenant)
  res.redirect('/app')
})

export default router

2) Webhooks

Verify and handle webhook

// webhooks.ts
import crypto from 'crypto'

function isValidHmac(rawBody: string, headerHmac: string) {
  const digest = crypto
    .createHmac('sha256', process.env.SHOPIFY_API_SECRET!)
    .update(rawBody, 'utf8')
    .digest('base64')
  return crypto.timingSafeEqual(Buffer.from(headerHmac), Buffer.from(digest))
}

// Example Express handler
app.post('/webhooks/orders/create', express.raw({ type: 'application/json' }), (req, res) => {
  const hmac = String(req.get('X-Shopify-Hmac-Sha256') || '')
  if (!isValidHmac(req.body.toString(), hmac)) return res.sendStatus(401)
  const payload = JSON.parse(req.body.toString())
  // process order created event
  res.sendStatus(200)
})

3) Shopify API usage

REST example

import axios from 'axios'

async function getProducts(shop: string, token: string) {
  const url = 'https://' + shop + '/admin/api/2024-10/products.json?limit=10'
  const { data } = await axios.get(url, { headers: { 'X-Shopify-Access-Token': token } })
  return data.products
}

GraphQL example

async function getShopName(shop: string, token: string) {
  const query = "{ shop { name } }"
  const resp = await fetch('https://' + shop + '/admin/api/2024-10/graphql.json', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Shopify-Access-Token': token,
    },
    body: JSON.stringify({ query }),
  })
  const { data } = await resp.json()
  return data.shop.name
}

Testing and QA

Testing checklist

  • Unit and integration tests for API routes
  • Mock Shopify API and webhook payloads
  • Performance tests for background jobs and rate limits
  • User acceptance tests across multiple stores

Security essentials

Must-haves

  • Strict OAuth state + HMAC validation
  • Rotate and encrypt access tokens
  • Least-privilege API scopes
  • Background retry with idempotency keys

Data protection

  • Store PII securely and avoid logging secrets
  • Enforce HTTPS and signed cookies
  • Regular dependency and security audits
  • Follow Shopify's security review checklist

Deploy and launch

Prepare for launch

  • Production domain, env vars, and database
  • App listing assets and descriptions
  • Pricing plans and billing logic
  • Support processes and SLA

Submission

  • Meet app review guidelines
  • Provide test credentials and instructions
  • Resolve review feedback promptly
  • Monitor errors post-approval

Grow post-launch

Marketing

  • Content SEO and tutorials
  • Partnerships with agencies and apps
  • Email onboarding and lifecycle
  • Social proof and case studies

Maintenance

  • Regular updates and deprecation tracking
  • Performance monitoring and alerts
  • Feedback loop and roadmap
  • Churn analysis and retention

Conclusion

Building a successful Shopify app requires clear product focus, robust engineering, secure operations, and continuous iteration. With the steps above and the examples provided, you're ready to design, ship, and scale an app merchants love.

Need Help with Your Shopify App?

If you need assistance with app development or have questions about the process, I'm here to help. Let's build something amazing together.

Get in Touch