Skip to main content

Customer Account API Local Development

This guide is for Shopify Hydrogen storefronts. Building on Next.js? See the Next.js overview.
The Customer Account API requires OAuth 2.0 flows with HTTPS callback URLs — which means http://localhost won’t work. Hydrogen 2026.10 refuses to build a login URL over plain HTTP, so /account/login fails under npm run dev by design. This guide walks you through running the Pilot theme locally with full Customer Account API support.
The setup differs depending on your store type:
  • Paid stores (Basic, Shopify, Advanced, Plus) → use the built-in dev:https command, which serves the dev server over HTTPS and registers its URLs for you
  • Development stores (Partner/Staff) → use ngrok or Cloudflare Tunnel with manual OAuth configuration in the Headless sales channel app

How Sign-In Works

  • Hydrogen 2026.10 owns the fixed, unprefixed routes /account/login, /account/authorize, /account/refresh and /account/logout, registered in server.ts with createCustomerAccountServerHandlers(). Link to them with a plain <a> or <form>, never React Router’s <Link> or <Form>: they answer with a redirect that client-side routing cannot follow.
  • The market travels in the query string. An account page visited without a session redirects to /account/login?return_to=/de-de/account&locale=de, so the shopper signs in on Shopify’s German login page and comes back to the German market.
  • The customer’s tokens live in the signed session cookie (SESSION_SECRET).
See Step 11 of the v6 migration guide for the server code.

Prerequisites

  • A Shopify store with the Hydrogen or Headless sales channel installed
  • Customer accounts enabled in your Shopify admin
  • Shopify CLI installed (@shopify/cli 4.4.0 or later, with @shopify/cli-hydrogen 13.0.4 or later so the dev server can register its URLs for you)
  • Your Hydrogen project linked to your store (shopify hydrogen link)

Step 1: Enable Customer Accounts

  1. From your Shopify admin, go to Settings > Customer accounts
  2. Under Accounts in online store and checkout, click Edit
  3. Select Customer accounts
  4. Click Save

If you have an existing .shopify/project.json pointing to a different store, delete it first:
Then link to the correct store:
If .shopify/project.json points to a store where your account lacks Hydrogen/Headless channel access, all shopify hydrogen commands will fail with ACCESS_DENIED — including shopify hydrogen link itself.

Step 3: Pull Environment Variables

Verify your .env has these variables:
SHOP_ID is the numeric shop ID, not a GID or domain. Leave SHOP_ID and PUBLIC_CUSTOMER_ACCOUNT_API_CLIENT_ID empty to run the storefront without customer accounts.
When deploying to Shopify Oxygen, these variables are injected automatically — no manual setup needed for production.

Option A: Paid Stores (Basic to Plus)

For stores on a paid Shopify plan, use the built-in dev:https command. This is the easiest approach — it serves the dev server over HTTPS and configures OAuth automatically.
The dev:https script is already configured in the Pilot theme’s package.json — no additional setup needed.

Start the HTTPS dev server

This runs the same vite dev --port 3456 as npm run dev, with Hydrogen’s localHttps Vite plugin turned on in vite.config.ts:
The plugin does two things:
  1. Serves HTTPS locally — at https://local.tryhydrogen.dev:3456, a Shopify-owned name that resolves to 127.0.0.1, with a locally trusted certificate. On the first run it installs a local certificate authority, which may prompt for your password. To do that ahead of time, run npx hydrogen certs install.
  2. Syncs OAuth credentials — uses Shopify CLI to add the Callback URI, JavaScript Origin, and Logout URI to your storefront’s Customer Account API settings

Open the HTTPS URL

Open the HTTPS URL the dev server prints, for example https://local.tryhydrogen.dev:3456, and navigate to /account to test login. If Shopify CLI is missing, outdated or the push fails, the dev server keeps running and prints the values. Set them manually in Hydrogen > Storefront > Customer Account API settings:
Do not use http://localhost:3456 for customer account testing — OAuth redirects will fail on non-HTTPS origins.

Option B: Development Stores — Manual Tunnel Setup

For Shopify development stores (Partner/Staff), the automatic Customer Account API setup is not available. You must use a third-party tunneling service and manually configure the Customer Account API in the Headless sales channel app.

Set up a tunnel

Choose either ngrok or Cloudflare Tunnel:
Use a static ngrok domain so you don’t have to reconfigure OAuth settings every time you restart.

Configure Customer Account API

For development stores, configure this in the Headless sales channel app:
  1. Open your Shopify admin → Settings > Customer accounts
  2. Find Customer Account API and open Application setup
  3. Ensure the client type is set to Public
  4. Update the following fields with your tunnel URL:

Update Content Security Policy

In app/weaverse/csp.ts, add the tunnel domain to connectSrc:
See Content Security Policy for how these directives become the header.

Start the dev server

Then access your storefront via the tunnel URL (not localhost). Pilot honors the tunnel’s x-forwarded-proto: https header, so the login URL uses HTTPS.

Account Routes in Pilot Theme

Login, OAuth callback, token refresh and logout are handled by Hydrogen’s Customer Account handlers at /account/login, /account/authorize, /account/refresh and /account/logout, not by route files. The Pilot theme includes the account pages at app/routes/account/: Source: Pilot theme routes
Customer account pages are code-based routes — they are not editable through Weaverse Studio’s visual editor. Any layout or design changes need to be done directly in the route files.

Troubleshooting

Customer Account API requires HTTPS. Use npm run dev:https (paid stores) or set up a tunnel (dev stores). Never test account flows on http://localhost. An error like Customer Account OAuth origin must use HTTPS means you opened the site over http://.
Your .shopify/project.json is pointing to a store where you don’t have channel access. Delete it and re-link:
The Callback URI, JavaScript origin and Logout URI in your Shopify admin must exactly match the URL you are browsing, including the port (except the JavaScript origin, which has none). For paid stores using dev:https, this is synced automatically. For dev stores, update it manually. A sign-in that lands on /account?login=failed or loops back to Shopify usually has a mismatch here.
The customer’s tokens are stored in the session cookie, which server.ts must commit on every response path, including the responses of handleShopifyRoutes. Check that SESSION_SECRET is set and that your server entry commits the session as in Step 3 of the v6 migration guide.
The dev server uses port 3456 and exits when the port is taken. To free it:

Next Steps

Last modified on November 10, 2026