Let's talk
Menu

Commerce / Shopify

Commerce shaped around the business.

Drag or use arrow keys to orbit

Shopify development

Custom storefronts, apps, and integrations that fit the operating model behind the checkout.

What we build

Useful from
day one.

ShopifyHydrogenReactGraphQL

Custom storefronts

Fast, accessible buying experiences without fighting the platform’s strengths.

Private apps

Purpose-built workflows connect catalogue, inventory, fulfilment, and support.

Safe extension

Theme and app work stays maintainable through upgrades and seasonal change.

The route to production

Clear steps.
Visible progress.

01

Discover

We map the real workflow, risks, users, and success measure before choosing an implementation.

02

Build

Working software lands in visible increments, with the hardest assumptions tested first.

03

Prove

We validate against production-shaped data, failure paths, performance, and real use.

04

Ship

Deployment, monitoring, documentation, and a clean handover are part of the build.

View all services ↗

Verified client reviews

In their words.

“Rapid and great work, with high technical knowledge. Highly recommend.”
Andy WaughCharlestown, Australia · 5.0 ★
“I recommend him due to his thoroughness and quality.”
Jordan GreggNew City, USA · 4.7 ★

Before you ask

Questions,
answered.

Which kind of Shopify app do we actually need?

Probably not a public one. An app created inside the merchant's own admin hands you an Admin API token in minutes, but it cannot be embedded, cannot use App Bridge and cannot ship a single extension. The moment you need UI inside the admin, a checkout extension, a Function or a theme app block, you need an app created in the Partner Dashboard — and setting its distribution to custom installs it on exactly one store through a link, with no App Store review. One client sat in review for eleven weeks for an app that synced one merchant's ERP; switching them to custom distribution took an afternoon.

Is Shopify customisable enough for our requirement?

In three of its four layers, and the fourth is fenced by design. Presentation and merchandising belong in the theme, which is the cheapest ground you will build on. State and logic belong in an app. Decisions inside Shopify's own cart maths are Functions. Checkout is a walled garden of defined extension points. The same sentence in a requirements document can be three days in the theme, three weeks as an app plus a Function, or a plan question at checkout, so sorting requirements into those layers before quoting is most of the estimate.

Why can a Function not call our ERP for live pricing?

Because Functions are sealed. They compile to WebAssembly and execute inside Shopify's own request path with no network access, a hard instruction budget and an input contract you declare as a query against the cart. Pricing that depends on a live call therefore cannot be computed while the buyer waits. You precompute it, write it to a metafield Shopify can already see, and let the Function read it. Pulling that decision forward is the single most common rework we do on Shopify projects.

What breaks first at real order volume?

The rate limiter, and it does not count requests. The GraphQL Admin API meters calculated query cost against a leaky bucket, so a query asking for 250 of anything with nested objects underneath can be rejected outright rather than throttled. Blind exponential backoff makes it worse, because the bucket is per shop: three workers backing off together wake up together and drain it again. We read the throttle status on every response and use bulk operations past a few thousand records — one nightly product sync went from six hours with regular limiter trips to about twenty minutes.

Are Shopify webhooks reliable?

They are at-least-once, out of order, and occasionally absent. Deduplicate on the webhook ID header with a unique column, compare the payload timestamp against what you already hold and drop anything older, and verify the HMAC over the raw request bytes before any JSON parsing — a framework that re-serialises the body breaks the signature check only for payloads carrying non-ASCII characters, so the bug reproduces solely for customers whose names have accents. Shopify also retries a failing endpoint for roughly 48 hours and then deletes the subscription with no email, which is the mechanism behind an app that stopped syncing sometime last week.

Do we still need a nightly reconciler if we have webhooks?

Yes. Webhooks are the fast path and the reconciler is the correct path. Every Shopify integration we run in production has both: a nightly job that re-reads everything updated since the last cursor and repairs the difference, so a dropped event or a deleted subscription becomes a delay rather than a silent divergence between your systems and the store.

Can you add our widget to the storefront with a script tag?

You can, and the plan has an expiry date printed on it. Script tags leave orphaned script calls in the theme after uninstall, which merchants find months later and blame on whoever touched the theme last, and checkout.liquid has already been retired in favour of checkout UI extensions. Theme app extensions are the replacement: the app ships a block, the merchant drags it into the theme editor where they want it, it is versioned alongside the app, and it disappears cleanly on uninstall.

Our access token is in an environment file and has never expired. Is that a problem?

It is the riskiest line in half the Shopify integrations we inherit, and the flow that produced it is gone. Since the start of 2026, new custom apps are created in the Dev Dashboard and the credential is requested at runtime rather than pasted anywhere. Apps installed on stores your own organisation owns use a client credentials grant that returns a token valid for about 24 hours, so code treating the token as fixed configuration works on the first night and returns 401 on the second. Token acquisition belongs behind one function that refreshes ahead of expiry.

How do scope changes work now?

As a release, not a checkbox. A new scope ships in a new app version and the store has to approve the added access before any request that needs it will work. We saw a team ship a feature and the scope it required in the same deploy, then spend an afternoon on access-denied errors from a query that was correct. Deploy the scope, confirm the grant, then ship the code that depends on it — and request only the scopes you can justify line by line, because security reviewers at larger merchants read those lists and the narrowest list gets approved fastest.

Can you migrate a legacy custom app without downtime?

Yes, and there is no need to rush it, because legacy admin-created apps still run. We build the new app alongside the old one with identical scopes, install it on a development store first, move one job at a time onto the new token while the legacy token still serves everything else, and move webhooks last — deduplicating on resource ID and timestamp rather than delivery ID, because each event arrives once per app while both are subscribed. The migration is finished only when a request made with the old token returns 401.

From the journal

Further reading.

Start with a paragraph, a Figma, or a Loom.

Build this properly.Reply within one business day · one clear scope · one fixed number