Invental/ Writing/ Custom Shopify app development
Shopify — 18 · Jul · 2026 · 10 min read

Anatomy of a custom Shopify app.

"Add a widget to a Shopify store" sounds like an afternoon. A real, installable, App-Store-ready app is four moving parts — a storefront extension, an admin, a backend, and the compliance reviewers actually check. Here's the whole shape of one.

DK
Daniyar K.
Anna L.
18 · Jul · 2026
[ FIG. 002 ] — Shopify · App INV-S-2026-07-18 The whole
stack.

A merchant came to us wanting an interactive product-recommendation quiz — the kind that asks a shopper a few questions and points them to the right product — installable on their store, configurable without a developer, and clean enough to pass Shopify's App Store review. On the surface, "add a quiz widget to a Shopify store" reads like a one-afternoon job. The finished thing was four separate moving parts, most of which a shopper never sees.

Our earlier notes covered designing inside the checkout sandbox. This is the other ninety percent of Shopify work: the storefront widget, the admin app the merchant configures it in, the backend it talks to, and the compliance layer that decides whether Shopify lets you ship at all. Here's the anatomy, using that build as the map — with the client and the product kept anonymous.


§ 01The four parts of a real app

A shippable Shopify app is rarely one thing. This one had four, and the split is typical:

You can't skip any of them and still call it an app. The interesting engineering is in how they connect — securely, and without leaking anything into the merchant's theme or your own infrastructure.

§ 02The storefront: theme app extensions

The single most common question we get: how do you add a custom widget to a Shopify store without editing theme code? The answer is a theme app extension. The merchant installs your app, opens the theme editor, and drags your "app block" into any section of any page. They configure it — API key, colours, layout — through settings you define. No Liquid editing, no risk to their theme, and it survives theme updates because it lives in your app, not their template.

The block is a Liquid file plus a schema. The schema is what turns into the merchant-editable settings panel in the theme editor:

{%- comment -%} blocks/quiz_widget.liquid {%- endcomment -%}
<div id="quiz-root"
     data-api-key="{{ block.settings.api_key }}"
     data-accent="{{ block.settings.accent }}"></div>
<script src="{{ 'quiz.js' | asset_url }}" defer></script>

{% raw %}{%- schema -%}{% endraw %}
{
  "name": "Product Quiz",
  "target": "section",
  "settings": [
    { "type": "text",  "id": "api_key", "label": "API key" },
    { "type": "color", "id": "accent",  "label": "Accent colour", "default": "#111" },
    { "type": "select","id": "layout",  "label": "Layout",
      "options": [{"value":"inline","label":"Inline"},{"value":"modal","label":"Modal"}] }
  ]
}
{% raw %}{%- endschema -%}{% endraw %}

The widget itself we built as Web Components with Lit — framework-agnostic on purpose. A Lit element drops into a Shopify theme, a plain HTML page, or a partner's site with the same one-line embed, so the same UI serves the App Store distribution and any bespoke placement without a rewrite.

§ 03The admin: an embedded app on Remix + Polaris

Configuration doesn't belong in a settings text field on the storefront — it belongs in the Shopify admin, where the merchant already works. So the second part is an embedded admin app, and the stack here is fairly settled in 2026: Remix with @shopify/shopify-app-remix, App Bridge for the embedded frame, and Polaris for the UI so it looks like a native part of Shopify rather than a bolt-on.

That framework handles the parts you don't want to hand-roll: the OAuth install flow, session storage (we back it with Prisma), and the scaffolding for talking to Shopify. For the data, you use the GraphQL Admin API — and it's worth running Shopify's codegen so those queries are typed end to end, the same discipline we apply everywhere else. The admin app is where the merchant picks which products the quiz can recommend (a Polaris ResourcePicker) and where that mapping gets written, which brings us to the two mechanisms that make the whole thing hang together.

§ 04The bridge: App Proxy & metafields

Two Shopify features do the connective work, and knowing them is most of the battle.

Metafields are structured data attached to the shop (or to products, customers, orders). We define a metafield for the quiz's product mapping in the admin app, write it once, and read it from the storefront — so configuration is set by the merchant, stored on Shopify, and available to the widget without a separate database round-trip. Metafields are also how you keep merchant-editable config out of your code entirely.

App Proxy is how the storefront widget talks to your backend securely. Shopify proxies requests from yourstore.com/apps/quiz/... through to your app, signed so you can verify they genuinely came from Shopify. The widget never sees your backend URL or a secret; it just calls a path on the merchant's own domain, and Shopify does the rest. On the app side you verify the proxy signature before trusting anything — which is the same posture you need for the part reviewers care about most.

The feature is the easy part. A shippable Shopify app is a storefront widget, an admin, a backend, and the compliance reviewers actually check.

— Build retro, Shopify app project

§ 05The backend & the compliance layer

The backend does two jobs. The first is the obvious one: integrate the external recommendation API, serve the widget's data, handle uploads and polling — a fairly ordinary Node/Express (or Remix loader) service. The second is the one first-time app builders skip and then fail review for: the mandatory GDPR/compliance webhooks.

Every public Shopify app must implement three webhooks — customers/data_request, customers/redact, and shop/redact — and every incoming webhook must be verified with an HMAC signature before you act on it. Skip the verification and you're processing unauthenticated requests; skip the webhooks and you don't ship. It's a small amount of code that carries a lot of the review weight:

// Verify every Shopify webhook before trusting it
import crypto from "crypto";

function verify(req) {
  const hmac = req.get("X-Shopify-Hmac-Sha256") || "";
  const digest = crypto
    .createHmac("sha256", process.env.SHOPIFY_API_SECRET)
    .update(req.rawBody, "utf8")
    .digest("base64");
  // timing-safe compare — never a plain ===
  return crypto.timingSafeEqual(Buffer.from(hmac), Buffer.from(digest));
}

We run this compliance surface as its own small, hardened service, so the requirement is met cleanly and doesn't tangle with the product code. Security headers, a timing-safe comparison, and the three redaction handlers — boring, and non-negotiable.

§ 06Getting through App Store review

If you're distributing through the Shopify App Store rather than as a one-store custom app, review is a gate, and it's less about the feature than about doing the plumbing correctly. The checklist that actually matters:

We built and shipped this one review-ready — extension, admin, backend, compliance, and submission artifacts — so the merchant's path to the App Store was a formality rather than a rebuild.

Most "Shopify developers" can build the widget. Fewer can wire the admin, the App Proxy, and the compliant backend into something that actually passes review.
— Why merchants come to us for the whole app

— End of essay. Building on Shopify? We've built the whole stack. Start a project →

← Related essay

Notes on designing Shopify checkout extensions.

Shopify · 7 min · 28 Feb
Next essay →

Typed from day one: why we start every project in TypeScript.

Engineering · 8 min · 2026

Need a custom Shopify app?

Theme extensions, embedded admin apps, App Proxy backends, App-Store-ready — we build the whole stack, not just the widget. Let's talk about yours.

Book an intro call