Fixing Shopify Customer Account API Errors in Hydrogen
The Customer Account API works cleanly once it is set up correctly, and produces a small set of confusing errors when it is not. The confusing part is that most of them are session handling problems wearing the costume of an authentication problem, so developers spend hours on OAuth configuration when the actual fault is a cookie that was never written. Here are the four that come up most and what each one is really telling you.
How authentication actually works here
Worth being clear about the model before debugging it, because the errors make more sense afterwards.
The Customer Account API uses OAuth 2.0. Confidential clients running server side use the standard authorization code flow with a client secret. Public clients use Proof Key for Code Exchange to guard against interception of the authorization code. Shopify is the identity provider and hosts the login page.
In Hydrogen, createCustomerAccountClient wraps this, and it requires a session to persist the access and refresh tokens. Hydrogen ships with cookie session storage by default, though you can substitute another implementation.
That dependency on the session is where nearly everything goes wrong.
Error one, the session state does not match the state parameter
The most common one and the most misleading, because it reads like an OAuth misconfiguration.
OAuth uses a state parameter to tie the redirect back to the request that started it. Your app generates it, stores it in the session, and checks it when the customer returns. If the value coming back does not match what is in the session, the check fails.
In practice that almost always means the session was not configured correctly or was not passed into createCustomerAccountClient, so the state was never stored where the check looks for it.
There is a second cause worth knowing because it is genuinely hard to spot. The state can be created in one browsing context and checked in another. A login started inside an in-app webview, then completed in the system browser, involves two different cookie jars. The second context has no session containing the state, so the comparison fails even though nothing is misconfigured. If this only reproduces for customers arriving from Instagram or another in-app browser, that is the cause.
Error two, the customer is logged in and then is not
A customer signs in, everything works, and a few requests later they are anonymous again. No error, just an inconsistent session.
This is usually a missing session commit. Checking whether a customer is logged in can trigger an access token refresh. That refresh produces new tokens, but they only persist if the session is committed to the Set-Cookie header at the end of the loader or action. Skip the commit and the refreshed tokens exist for exactly one request and then vanish.
The rule is simple: commit the session at the end of any loader or action that performs a logged-in check, not only the ones that obviously write data. This one is easy to miss because a read looks like it should not need a write.
Error three, cookie too large
Hydrogen's default cookie session storage puts session data in a cookie, and cookies have a size limit that browsers enforce. Accumulate enough in the session, tokens plus cart state plus whatever else your app decided to keep, and you exceed it.
The symptom is a request failing on size rather than an authentication error, which sends people looking in the wrong place.
Two fixes. Reduce what you store in the session, keeping identifiers rather than whole objects. Or move to a different session storage implementation so the cookie holds only a session identifier and the data lives server side. If you are storing anything substantial per customer, the second option is where you will end up eventually, so consider it early rather than after an incident.
Error four, third-party cookie warnings on the login page
Chrome reports third-party cookies on Shopify's hosted login page, associated with hCaptcha and set with SameSite=None; Secure. Developers see this in the console during testing and reasonably worry about future browser changes to third-party cookies.
This one is not yours to fix. It is on Shopify's hosted page and involves their bot protection. Note it, do not build around it, and do not let it derail your debugging, because it is unrelated to session problems in your own application.
Getting local development working
A category of its own, because a lot of time is lost here before any real work starts.
OAuth needs the redirect URI to match exactly, which means your local environment has to be reachable at a URL registered with Shopify. That usually means a tunnel, and the URL must be registered rather than assumed. Tunnels that issue a new URL on every restart create a fresh mismatch each time, which is why the first error above appears constantly during setup and then stops once the environment stabilises.
If a login flow works in production and fails locally, check the redirect URI before anything else.
A debugging order that saves time
- Confirm the session is created and passed into the customer account client. Most state mismatches end here.
- Confirm you commit the session at the end of loaders and actions that check login status.
- Check the redirect URI matches exactly, especially locally.
- Check what you are putting in the session if you see size errors rather than auth errors.
- Reproduce in a normal browser before trusting a failure seen only in an in-app webview.
Four of those five are session handling. That is the pattern worth internalising: when Customer Account API authentication behaves strangely, suspect the session before suspecting OAuth.
Test the contexts your customers actually use
The gap between a working local build and a working production one is usually browsing context, and it is not something a normal test pass catches.
Your customers do not all arrive in a clean desktop browser. A large share arrive from an in-app browser inside Instagram, Facebook or WhatsApp, particularly in markets where social is the primary discovery channel. Those environments have their own cookie handling, and some of them hand off to the system browser partway through a flow, which is exactly the condition that breaks the OAuth state check.
Safari's tracking prevention is worth a pass too, since it treats cookies more aggressively than Chrome and will surface problems your Chrome testing never shows.
Build a short list of real contexts, desktop Chrome, mobile Safari, and at least one in-app webview, and run the full login through each before release. Finding a webview problem in testing costs an afternoon. Finding it after a campaign launch costs a day of failed logins from your highest-intent traffic.
What does session state does not match the state parameter mean?
The OAuth state value returned from Shopify does not match what your session holds. Usually the session was not configured or not passed to createCustomerAccountClient, so the state was never stored. It can also happen legitimately when login starts in one browsing context, such as an in-app webview, and completes in another with a different cookie jar.
Why does my customer keep getting logged out in Hydrogen?
Most often a missing session commit. A logged-in check can trigger a token refresh, and the refreshed tokens only persist if the session is committed to the Set-Cookie header at the end of the loader or action. Without that they last one request.
How do I fix cookie too large errors?
Store less in the session, or replace Hydrogen's default cookie session storage with an implementation that keeps data server side and puts only an identifier in the cookie. The error is about size limits rather than authentication, even though it usually surfaces during login work.
Does the Customer Account API work on all Shopify plans?
The API itself is the authentication path for headless storefronts and is not the same as connecting your own identity provider, which is Plus only. Confirm your specific requirements against current documentation before scoping, since the plan boundaries around customer accounts have moved more than once.
Should I use a custom session storage from the start?
If you are building anything beyond a simple storefront, yes. Cookie storage is fine for tokens alone and becomes a size problem as soon as you keep meaningful state per customer. Switching later is a refactor, so it is cheaper to decide early.
Get help with your headless build
Free review. Email hello@exactwhy.com with subject "Customer Account API" and describe the error plus where it happens. We respond within 4 hours. Most of these have a specific cause and we would rather tell you what it is than sell you a project.
Paid development, Rs 60,000 to Rs 2 lakh. Authentication implementation in headless builds, session architecture that survives scale, and testing across real browsing contexts including in-app webviews.
Ongoing Shopify development, Rs 20,000 to Rs 50,000 a month. For teams running a headless storefront who want an escalation path.
If you are still deciding whether headless is right at all, our Hydrogen and Liquid comparison is the better starting point, and our custom development costing covers how we scope this kind of work.