Shopify App Security: What the App Review Actually Checks
Alexander Mercer
Sep 1, 2026
Most teams treat Shopify's app review as a formality at the end of the build. It is not. It is a security audit conducted by someone who has seen every shortcut before, and the majority of first-submission rejections we see are not feature problems or design problems. They are security problems, and almost all of them are decisions made in the first week of development that nobody revisited.
The frustrating part is that the requirements are not secret. They are published, they are stable, and they are entirely achievable. What catches teams out is that the review checks whether your app behaves correctly under conditions your happy-path testing never produces: a forged request, an expired session, a merchant who uninstalls and reinstalls, a webhook delivered twice.
Request every scope you need, and nothing else
Access scopes are the first thing a reviewer looks at, and over-requesting is the single most common rejection reason. If your app asks for write_customers but only ever reads customer names for a display label, that is a finding. The reviewer does not have to prove you misuse the data; the burden is on you to justify why the scope is necessary at all.
The practical discipline is to build the scope list last rather than first. Start with the narrowest set that makes your core flow work, run the app, and add a scope only at the moment something genuinely fails without it. Teams that do the opposite — copy a broad scope string from a tutorial on day one and never trim it — end up unable to explain half the list at review time.
Watch for the protected customer data tiers in particular. Reading name, email, phone or address now requires an explicit justification per field, and "we might need it later" is not one. If a field is aspirational, ship without it and request it in a later version once you can point at the feature that consumes it.
Verify HMAC on everything, including the things you forgot
Every request Shopify sends you carries a signature, and every one of them has to be verified before your code acts on the payload. Teams reliably remember this for the OAuth callback and reliably forget it somewhere else — most often on webhooks, app proxy requests, or the GDPR mandatory endpoints that were scaffolded once and never touched again.
The verification itself must be a constant-time comparison. Using a plain equality check on the computed digest leaks timing information, and while it is unlikely anyone is mounting a timing attack against your inventory sync, it is exactly the kind of detail a reviewer reads as a signal about the rest of the codebase.
An unverified webhook endpoint is not a theoretical risk either. It is an unauthenticated public URL that mutates merchant data on request. Anyone who guesses the path can drive it.
Session tokens, not cookies
Embedded apps run inside an iframe in the Shopify admin, and third-party cookie behaviour in modern browsers makes cookie-based sessions unreliable at best and broken at worst. Shopify's answer is session tokens: short-lived JWTs issued by App Bridge, sent with each request, verified server-side against your app secret.
The part teams get wrong is treating the token as an identity claim and stopping there. A valid signature tells you the request came from Shopify. It does not tell you the shop in the token is a shop your app is actually installed on, that the installation is still active, or that this shop is entitled to the resource being requested. All three need checking, every time.
Tokens are also deliberately short-lived — around a minute. Any design that caches one and reuses it, or that stores it somewhere durable, is fighting the mechanism rather than using it.
The GDPR webhooks are not optional and are not decorative
Every public app must implement three mandatory webhooks: customers/data_request, customers/redact, and shop/redact. Reviewers test them. Returning 200 and doing nothing is a rejection, because the endpoint being reachable is not the requirement — the requirement is that the data actually gets produced or destroyed.
shop/redact is the one that exposes sloppy data modelling. It fires 48 hours after uninstall and obliges you to delete that shop's data. If your schema scattered shop-scoped rows across a dozen tables with no consistent foreign key, you will discover it here, under time pressure, rather than during design.
Handle these the same way you handle any other webhook: verify the HMAC, respond fast, do the work asynchronously. A redaction that takes ninety seconds inline will time out and be retried, and now you have a concurrency problem on top of a compliance one.
Assume every webhook arrives twice
Shopify guarantees at-least-once delivery. That is not a caveat in the documentation to be skimmed past; it is a design constraint. A webhook handler that charges a card, sends an email, or increments a counter without an idempotency key will eventually do it twice, and the merchant will notice before you do.
The fix is unglamorous and reliable: record the X-Shopify-Webhook-Id, check it before processing, and make the check and the work atomic. It costs one table and one index.
Respond within five seconds regardless. Shopify does not care that your handler is doing useful work; it cares that you acknowledged receipt. Acknowledge first, queue the work, process it out of band.
“Almost every security finding at app review traces back to a decision made in week one that nobody revisited.”
HelloDevs
What to do before you submit
Re-derive your scope list
Strip the manifest back to nothing and add scopes one at a time until the app works. Whatever you did not have to add, you did not need.
Grep for every request entry point
Enumerate every route Shopify can call — OAuth, webhooks, app proxy, GDPR endpoints — and confirm each one verifies its signature before touching the payload.
Test the uninstall and reinstall loop
Install, uninstall, reinstall. Stale access tokens and orphaned shop rows surface here and nowhere else.
Replay a webhook
Send the same payload twice and confirm the second one is a no-op. If it is not, you do not have idempotency, you have luck.
Prove the redaction actually redacts
Fire shop/redact against a test shop and then go looking for its data. If you can still find it, so can a reviewer.
The underlying point
None of this is difficult work. It is unrewarding work, which is a different problem — it produces nothing a merchant can see, so it loses every prioritisation argument against a visible feature until the day the submission comes back rejected and the release slips by three weeks.
Treat the review requirements as the specification they are, not as a checklist to satisfy at the end. The apps that pass first time are not the ones with the best security review process. They are the ones that never accumulated the debt in the first place.
This is the ground we cover on every build in our Shopify app development work — including the review submission itself. If you have an app stuck in review, or one you would rather not get stuck, tell us what you are building.
Alexander Mercer
Senior Tech Writer at HelloDevs
Alexander covers software engineering culture, design systems, and frontend developer experience. When not writing, you can find him debugging React or exploring typography design.
Stay Updated
Get raw, honest dev-first tutorials and tech blog articles delivered straight to your inbox once a week.
Our guide
- A Shopify development agency builds and maintains the parts of a store Shopify does not give you out of the box. That means custom themes, apps, integrations with your other systems, and ongoing fixes. HelloDevs does all of this and also publishes its own Shopify apps.
- Yes. We work with merchants across North America, Europe, and Asia. Our process is async-first with scheduled overlap hours, so time zones have never been a blocker for a project.
- It depends on scope. Theme customisations typically start in the low four figures; custom apps and full builds range higher. After a free audit we give you a fixed quote — no hourly surprises.
- Absolutely. Private (custom) apps are a large part of our work — from small workflow automations to full ERP integrations that only your store uses.
- Every project ships with a support window, and most clients stay on a maintenance retainer: monitoring, Shopify update compatibility, and a direct line to the same developers who built it.
- Continuity and coverage. An agency gives you review processes, backup when someone is unavailable, and accumulated platform experience across many stores — with one point of accountability.
Didn't Got your answer?
If you still have questions or need further assistance, feel free to reach out to our team. We're here to help you every step of the way.
Our talk
Let's Connect!
Tell us your requirements and get a professional developer response.




