Embedded app OAuth using token exchange (unstable_newEmbeddedAuthStrategy) rather than the traditional full-page redirect
shopify-app-starter-remix — Remix Starter Template
By Ecom-Swift-LLC
A Remix-based embedded Shopify app starter with token-exchange OAuth, Prisma session storage, three mandatory GDPR webhooks, and Billing API plan gating, plus unit tests.
Explore the design
Compare the page layouts and mobile experience. Open any screenshot for a closer look.
Actual screenshot captured by the server browser.
All pages & views 3
Screenshots show visual appearance; interactive behavior may differ.
What stands out
A quick read of the recorded project description.
Built-in routes for the three mandatory GDPR webhooks, plus lifecycle webhooks such as uninstall and scope changes
Prisma session storage defaults to SQLite; switching to Postgres/MySQL/MongoDB only requires changing the datasource
Billing plan gating and a plan selection interface, with the plan catalog centralized in app/lib/plans.ts
25 Vitest cases for logic such as shop domain normalization, the plan catalog, and webhook topic mapping
The README explicitly lists what the template does not do, including that GDPR handlers only log and do not delete data
Template Details
This is a Remix starter for embedded Shopify apps, maintained by Ecom Swift LLC and licensed under MIT. It centralizes configuration work common in early custom app development: OAuth (using token exchange rather than the traditional full-page redirect), session storage, and billing are configured in app/shopify.server.ts; sessions are persisted via Prisma, using SQLite by default; it includes lifecycle webhooks such as app/uninstalled and scope changes, as well as the three GDPR webhooks required for App Store review (customers/data_request, customers/redact, shop/redact).
The project includes an embedded app shell (AppProvider, NavMenu, error boundary), a sample page that performs a real Admin GraphQL query, billing plan gating and a plan selection interface, plus a public login form and OAuth callback route. Non-trivial logic is extracted into app/lib/ as framework-agnostic functions, with 25 Vitest cases covering shop domain normalization, the billing plan catalog, and mapping webhook topics to route names.
It should be clear that the GDPR webhook handlers only verify requests and log payloads; they do not actually delete data, because the template itself does not store customer PII. customers/data_request and customers/redact contain TODO markers, and only shop/redact actually deletes the Session records for that shop. The template is not App Store review-ready out of the box; billing configuration uses the classic per-plan mode rather than Shopify App Pricing in the Partner Dashboard, and no CI, Docker, or deployment target is included. The UI uses @shopify/polaris (React) rather than Polaris Web Components, and npm has marked that package as deprecated. The author states that validation was performed with tsc --noEmit, npm run build, and npm test, and was not run against a live shop in CI.
Is it right for your project?
Use Cases
- Building a custom app from scratch that needs to be embedded in the Shopify admin and use OAuth
- Adding the three GDPR webhook routes required for App Store review to an existing app
- Integrating Shopify Billing API per-plan subscriptions and gating logic into a Remix project
- Using it as a teaching or internal team baseline for how token exchange, Prisma sessions, and webhook routes are organized
Suitable For
- Developers building Shopify custom apps with Remix and Node.js
- Shopify Partners who need a working OAuth, session, and billing skeleton quickly
- Teams that want to start from MIT-licensed code and decide hosting and database themselves
Getting started & customization
Use these recorded setup notes alongside the repository instructions for your chosen version.
- 1
Requires Node.js 18+, npm, and a Shopify Partner account with a development store (all available for free)
- 2
Run git clone, npm install, install @shopify/cli globally, shopify app config link, npm run setup, and npm run dev in that order
- 3
To run only logic tests, you can just run npm install and npm test; no Shopify CLI or Partner account is needed
- 4
Do not continue using the default SQLite in production; modify the datasource in prisma/schema.prisma as described in the README
- 5
Before launch, verify with shopify app dev against your own development store; the template has not been run against a live shop in CI
License & source material
Usage conditions & limitations
Free to use · keep license noticeThis entry covers the free version in the public repository under the MIT license; the free scope applies to that version's code and does not imply that external services or third-party assets are free.
Must comply with when using
- You may use, modify, commercialize, and distribute this version's code for free.
- When distributing copies or substantial portions of the code, retain the original author's copyright notice and the full MIT license notice.
- The code is provided as is; warranties and limitations of liability are governed by the original license and applicable law.
Additional costs & items to verify
- Use requires Node.js 18+, npm, and a Shopify Partner account with a development store; the Partner account and development store are free, but you must register and sign in to the Partner Dashboard to run the full workflow.
- You need to link the local directory to an app record in the Partner Dashboard, which depends on the official Shopify CLI and a Partner account, i.e., external service dependencies.
- The default SQLite is only for zero-configuration demos; the README explicitly does not recommend it for production, and you must replace the database for production.
- The template is not App Store review-ready out of the box; before launch you still need to add review requirements such as a privacy policy and permission explanations yourself.
- The GDPR webhook handlers only verify requests and log payloads; they do not perform data deletion. customers/data_request and customers/redact have TODOs, and you need to integrate customer data lookup and deletion logic yourself.
- The repository provides no CI, Docker, or deployment target; you must choose and configure hosting for the Node process yourself.
- The UI uses the @shopify/polaris (React) package, which npm has marked as deprecated, rather than Polaris Web Components; note this before making a long-term investment.
- The author has not run validation against a live shop in CI; before launch you need to test with your own development store.
- Demo images, fonts, icons, and other third-party assets must be checked against their respective licenses; you cannot judge solely by the code's MIT license.
- External services such as domains, hosting, databases, payments, or AI may incur separate charges.
View Original Text Basis
Permission is hereby granted, free of charge
Original License Text
Requires Node.js 18+, npm, and a Partner account with a development store (both free).
Original README
shopify app config link # links this folder to an app record in your Partner Dashboard
Original README
No, and you shouldn't — it's here so the template runs with zero external setup.
Original README
Not App Store review-ready as-is.
Original README
The GDPR webhook handlers verify the request and log the payload — they don't erase anything
Original README
No CI, no Docker, no deploy target committed.
Original README
`@shopify/polaris` (React), not Polaris web components.
Original README
https://github.com/Ecom-Swift-LLC/shopify-app-starter-remix/blob/main/LICENSEhttps://github.com/Ecom-Swift-LLC/shopify-app-starter-remix/blob/main/README.mdNot deployed or run against a live store by us in CI.
Original README
Compiled by DeepSeek based on repository license and README ·2026-10-01. Results only cover the materials read; dependencies, images, fonts, and subsequent term changes are subject to their respective original texts.
Project checks & description sources
Template Information
- Source platforms
- GitHub
- Documentation and maintenance reference score
- More documented · 80 / 100
- Technologies
- Remix · React
- Website type
- Starter
How this score is calculated
Our heuristic uses license records (up to 30), a demo link (12), a preview (10), stars (15), recorded maintenance (15), description completeness (8), feature records (5) and classification data (5). It is not a code, security or performance test, or a Google score. A link does not establish tested functionality.
What to verify for this project
- Repository update recorded
- 2026-09-22
- Screenshot last checked
- 2026-10-01
A demo link is listed. Check it with your own content and viewport sizes; its presence does not confirm that forms, authentication or payments work.
The catalog identifies Remix as the primary stack. Check the actual dependency manifest and lockfile for versions and hosting requirements. These notes use recorded metadata, not a code audit or a deployment test.
Use a selection guide →How this description was prepared
AI-assisted description based on catalog records and repository material. Repository authors are not automatically the reviewers of this description.
Automatically checked against source and license rules; no manual editorial review.
Inspect the recorded source material
SHA-256: 494b9339fe77961f6a526c56bc3e1fd7ba464e880e4ca1359d683058a1aa5e60
2026-10-01T14:56:43.611Z
Source file / repository# shopify-app-starter-remix
An embedded Shopify app starter (Remix): OAuth via token exchange, Prisma-backed sessions, all three mandatory GDPR webhooks wired up from day one, and Billing API plan gating — documented with the gotchas the official scaffold leaves for you to hit yourself, and with the parts that can be unit tested actually tested.
We built this because every custom-app engagement starts the same way: `shopify app init`, then an hour of rediscovering which future flags still exist, that billing config now has to be in the line-item shape, and that the GDPR webhooks the App Store will reject you for skipping aren't in the default scaffold at all. This is that hour, done once.
**Free audit for your own store while you're here:** [audit.ecomswiftllc.com](https://audit.ecomswiftllc.com/?utm_source=github&utm_medium=repo&utm_campaign=shopify-app-starter-remix) checks SEO, speed, CRO and AI-visibility in one pass.
## What's inside
| Piece | File(s) |
| --- | --- |
| Shopify app config: OAuth, token exchange, session storage, billing | [`app/shopify.server.ts`](app/shopify.server.ts) |
| Prisma session storage (SQLite by default) | [`prisma/schema.prisma`](prisma/schema.prisma), [`app/db.server.ts`](app/db.server.ts) |
| Embedded app shell: `AppProvider`, `NavMenu`, error boundary | [`app/routes/app.tsx`](app/routes/app.tsx) |
| Example authenticated page (runs a real Admin GraphQL query) | [`app/routes/app._index.tsx`](app/routes/app._index.tsx) |
| Billing plan gate + plan-picker UI | [`app/routes/app.billing.tsx`](app/routes/app.billing.tsx), [`app/lib/plans.ts`](app/lib/plans.ts) |
| Public login form + OAuth callback routes | [`app/routes/auth.login/`](app/routes/auth.login), [`app/routes/auth.$.tsx`](app/routes/auth.$.tsx) |
| App lifecycle webhooks (uninstall, scope change) | [`app/routes/webhooks.app.uninstalled.tsx`](app/routes/webhooks.app.uninstalled.tsx), [`app/routes/webhooks.app.scopes_update.tsx`](app/routes/webhooks.app.scopes_update.tsx) |
| The 3 **mandatory** GDPR webhooks | [`app/routes/webhooks.customers.data_request.tsx`](app/routes/webhooks.customers.data_request.tsx), [`.customers.redact.tsx`](app/routes/webhooks.customers.redact.tsx), [`.shop.redact.tsx`](app/routes/webhooks.shop.redact.tsx) |
| Shop-domain validation for the login form | [`app/lib/shop-domain.ts`](app/lib/shop-domain.ts) |
## Example output
```
$ npm run dev
# Shopify CLI opens a tunnel, prints an install link, and updates
# shopify.app.toml's application_url + redirect_urls for you.
Install the app on your dev store → OAuth via token exchange → lands on
/app, which runs:
query ShopName {
shop { name email }
}
and renders it in a Polaris Card. Click "Billing" in the nav → billing.check()
finds no active subscription → redirects to Shopify's plan-approval page →
approve (free on a dev store) → redirected back to /app/billing showing
"Active plan: Starter".
```
## Features
- **Written and type-checked against what's actually installed, not what the docs say.** `@shopify/[email protected]` made line-item billing and managed-pricing support permanent — the old flat `{ amount, currencyCode, interval }` billing config and the `expiringOfflineAccessTokens` future flag both fail `tsc` now. This repo's `billing` config uses the current `lineItems` shape; run `npx tsc --noEmit` yourself and it's clean.
- **All three mandatory GDPR webhooks, not just `app/uninstalled`.** `customers/data_request`, `customers/redact`, and `shop/redact` are commonly missing from hand-rolled starters and are a real App Store rejection reason — see [what it does NOT do](#what-it-does-not-do) for exactly how much they do and don't implement.
- **The non-trivial logic is unit tested, not just eyeballed.** Shop-domain normalization (handles a bare shop name, a full domain, or a pasted `admin.shopify.com/store/...` URL), the billing plan catalogue, and the webhook-topic-to-route-name mapping live in [`app/lib/`](app/lib) as framework-free functions with 25 Vitest cases.
- **Token exchange, not the classic OAuth redirect.** `unstable_newEmbeddedAuthStrategy: true` is set — the auth strategy Shopify now recommends for embedded apps, instead of the older full-page redirect dance.
- **SQLite by default, one field to change for Postgres/MySQL/MongoDB.** Session storage is `@shopify/shopify-app-session-storage-prisma`; the `Session` model and its adapter don't change, only `prisma/schema.prisma`'s `datasource` block does.
## Installation
Requires Node.js 18+, npm, and a Partner account with a development store (both free).
```bash
git clone https://github.com/Ecom-Swift-LLC/shopify-app-starter-remix.git
cd shopify-app-starter-remix
npm install
npm install -g @shopify/cli # if you don't already have it
shopify app config link # links this folder to an app record in your Partner Dashboard
npm run setup # prisma generate + migrate
npm run dev # opens a tunnel, prints an install link
```
Or run the logic tests on their own, no Shopify CLI or Partner account required:
```bash
npm install
npm test
```
## Usage
- **Add a page:** drop a file in `app/routes/` following Remix's flat-file convention (`app.<name>.tsx` for an embedded page under the nav). Call `authenticate.admin(request)` first in every loader/action — see [`app/routes/app._index.tsx`](app/routes/app._index.tsx).
- **Add a webhook:** add the topic to `shopify.app.toml`'s `[[webhooks.subscriptions]]`, then create `app/routes/webhooks.<topic-with-dots>.tsx` with an action-only route calling `authenticate.webhook(request)`. [`app/lib/webhook-topics.ts`](app/lib/webhook-topics.ts) has the naming convention as a tested function, not just a comment.
- **Change or add a billing plan:** edit [`app/lib/plans.ts`](app/lib/plans.ts)'s `PLANS` object, then mirror the `key` and `lineItems` shape in the `billing` config in `app/shopify.server.ts` — the plan-picker UI in `app.billing.tsx` reads `PLANS` directly, so a new plan shows up with no other changes.
- **Swap the database:** change `prisma/schema.prisma`'s `datasource.provider`/`url` to Postgres/MySQL/MongoDB, run `npx prisma migrate dev`. Nothing else references SQLite directly.
## What it does NOT do
- **The GDPR webhook handlers verify the request and log the payload — they don't erase anything, because this template stores no customer PII of its own.** `customers/data_request` and `customers/redact` have `TODO` markers exactly where you wire in a lookup once your app adds a table keyed to a customer. `shop/redact` *does* do real work — it deletes the shop's `Session` rows — since sessions are the one thing this template actually stores per-shop.
- **Not App Store review-ready as-is.** Wiring the mandatory webhooks is necessary, not sufficient — review also checks your privacy policy, scope justification, and the app's actual behavior on install/uninstall.
- **The Billing API config here is the classic per-plan model, not "Shopify App Pricing."** As of 2026 Shopify is steering new public apps toward pricing that lives in the Partner Dashboard instead of your code — see the note at the top of `app/lib/plans.ts` for which one fits your app.
- **No CI, no Docker, no deploy target committed.** `shopify app deploy` handles the Shopify-side config; hosting the Node process (Fly, Railway, Render, your own box) is a separate decision this repo doesn't make for you.
- **`@shopify/polaris` (React), not Polaris web components.** It's what the current Shopify-maintained Remix template still ships and it works, but npm flags the package itself as deprecated in favor of the web-component version — worth knowing before you invest heavily in Polaris React components.
- **Not deployed or run against a live store by us in CI.** Verified with `npx tsc --noEmit`, `npm run build`, and `npm test` (25 passing) against the exact dependency versions in `package-lock.json` — run `shopify app dev` against your own development store before shipping to production.
## FAQ
**Why does `billing.request` redirect even on a free dev store?**
`isTest: true` (set from `NODE_ENV`) tells Shopify to create the subscription in test mode — the merchant still goes through the approval screen, but no card is ever charged. Development and Partner-org test stores can't be charged real money regardless.
**Why is `app/lib/plans.ts` not `.server.ts` like the other lib files?**
`app.billing.tsx`'s component reads `PLANS` directly to render the plan cards, and Remix's Vite plugin strips `.server.ts` imports from the client bundle — importing one from a component is a build error, not a silent bug. `plans.ts` holds no secret, so it's fine to ship to the browser.
**Do I have to use SQLite in production?**
No, and you shouldn't — it's here so the template runs with zero external setup. Swap `prisma/schema.prisma`'s datasource, per [Usage](#usage) above.
**Where's the `app/routes.ts` route-config file?**
There isn't one — this template deliberately keeps `v3_routeConfig: false` in `vite.config.ts` and uses Remix's classic flat-file route discovery (`app.billing.tsx` → `/app/billing`). Turning that flag on requires migrating to the newer explicit route-config API.
If you'd rather have a custom Shopify app built and maintained than run one yourself, our [free Shopify tools](https://www.ecomswiftllc.com/free-tools) and [store audit](https://audit.ecomswiftllc.com/?utm_source=github&utm_medium=repo&utm_campaign=shopify-app-starter-remix) are a good starting point, or reach out directly — contact details below.
## Related Shopify tools
- [`shopify-webhook-toolkit`](https://github.com/EcomswiftLLC/shopify-webhook-toolkit) — verify, log and replay Shopify webhooks locally while building out the handlers this template stubs.
- [`shopify-checkout-ui-extensions`](https://github.com/Ecom-Swift-LLC/shopify-checkout-ui-extensions) — four tested Checkout UI Extensions to pair with an app built from this starter.
- [`shopify-metafields-manager`](https://github.com/Ecom-Swift-LLC/shopify-metafields-manager) — CLI for the metafield definitions and bulk import an app like this often needs.
- [`shopify-order-export-cli`](https://github.com/Ecom-Swift-LLC/shopify-order-export-cli) — Admin GraphQL order export + revenue reporting, same pagination/retry patterns this template's `admin.graphql` calls would need at scale.
- [`shopify-api-python-client`](https://github.com/EcomswiftLLC/shopify-api-python-client) — the same idea (Admin API client, cost-aware retries) for a Python stack instead of Node.
- [`shopify-audit-mcp`](https://github.com/EcomswiftLLC/shopify-audit-mcp) — the store audit as an MCP tool for Claude, Cursor and other MCP clients.
## Contributing
Issues and PRs welcome — an `app/routes.ts` variant for teams who want the newer route-config API, a Postgres `docker-compose.yml` for local dev, more `app/lib/` coverage, and reports of breakage against newer `@shopify/shopify-app-remix` releases are all useful.
## Roadmap
- An example `app/routes/webhooks.products.update.tsx` showing a filtered webhook subscription (`shopify.app.toml`'s `filter` field).
- A worked usage-based billing example using `createUsageRecord`, alongside the recurring plans already here.
- GitHub Actions workflow running `tsc --noEmit`, `npm test`, and `shopify app config link --client-id` validation on every PR.
## License
MIT © Ecom Swift LLC
## Need help?
This project is maintained by **Ecom Swift LLC**, a Shopify Partner.
- 🛍️ Shopify Partner Directory: https://www.shopify.com/partners/directory/partner/waowy
- ✉️ Email: [email protected]
- 💬 WhatsApp: https://wa.me/16312511767
---
Want a custom Shopify app built on this foundation instead of building it yourself? [Get a free store audit](https://audit.ecomswiftllc.com/?utm_source=github&utm_medium=repo&utm_campaign=shopify-app-starter-remix) (SEO, speed, CRO, AI visibility) or browse our other [free Shopify tools](https://www.ecomswiftllc.com/free-tools). We're **Ecom Swift LLC**, a Shopify Partner Agency — [www.ecomswiftllc.com](https://www.ecomswiftllc.com).
Explore similar templates
Compare previews and descriptions within the same stack and category.

medusa2-starter
A Turborepo monorepo starter that pairs a Medusa2 backend with a Remix frontend, including a Coffee Roast themed storefront, Stripe payments, and Express Checkout setup notes. It supports unlimited products, collections, categories, and tags, and uses TypeScript with Biome.
Remix · E-commerce

remix-knowledge-base
A Remix-based knowledge base starter kit with Tailwind CSS and Prisma, offering Tiptap WYSIWYG and Monaco Markdown editors, multiple knowledge bases, multi-language support, drafts, SEO settings, simple statistics, and Supabase image storage.
Remix · Starter

docs-starter
A Remix-based documentation site starter with content from the Hygraph headless CMS, styled with Tailwind CSS. It supports rich text editing, automatic table of contents, custom embeds, preview mode, and SEO output.
Remix · Documentation

directed-stack
Directed Stack is an MIT-licensed Remix starter that uses Directus as a headless CMS for authentication, blog, pages, and backend storage. It includes cookie-session email/password auth, an /api/healthcheck endpoint, Tailwind, Markdoc rendering with custom components, Prettier, ESLint, and TypeScript.
Remix · Starter

remix-wasmer-starter
A Remix-based static site starter for Wasmer Edge. It uses getStaticPaths() to generate the root path at build time, sets serverBuildTarget to "wasmer" in remix.config.js, and outputs static assets to build/client for direct static hosting.
Remix · Starter

tailwind-remix-starter
A free, MIT-licensed Remix starter maintained by themesberg that combines Remix, React, Tailwind CSS, and Flowbite React into a ready-to-develop project skeleton.
Remix · Starter
