Customer Account API
The Customer Account API is a public API that allows you to access your Shopify store's customer data, such as customer profiles, addresses, and order history. It is designed to be used in client-side applications, such as a Nuxt frontend. To use the Customer Account API, you need to obtain a client id. Confidential client authentication is currently not supported, so a client secret is not required.
Setup
For the type generation to work correctly, make sure to install the @shopify/hydrogen package for the appropriate version of the API
you are using (e.g. @shopify/hydrogen@2026.4.0 for API version 2026-04).
npm install @shopify/hydrogen
For the customer account authentication flow, also make sure to install the nuxt-auth-utils package:
npm install nuxt-auth-utils
Then, once configured, you can use the Customer Account API in your Nuxt application via the useCustomerAccount
and useCustomerAccountData composables. The useCustomerAccount composable is available to both server and client-side.
Authentication
The module provides built-in routes for the OAuth authentication flow. You do not need to create these routes yourself.
To authenticate with Shopify, your app needs to have a publicly accessible URL where Shopify can redirect the user after they log in.
This means that the authentication flow will not work when running the app in development mode with nuxt dev, since the app is only accessible at localhost.
To work around this, you can use a tunneling service like ngrok to create a public URL for your local development server.
Logging in
To initiate the login flow, redirect the user to /_auth/customer-account/callback:
<script setup lang="ts">
function login() {
navigateTo('/_auth/customer-account/callback')
}
</script>
<template>
<button @click="login">Log in</button>
</template>
Logging out
To log the user out, redirect them to /_auth/customer-account/logout:
<script setup lang="ts">
function logout() {
navigateTo('/_auth/customer-account/logout')
}
</script>
<template>
<button @click="logout">Log out</button>
</template>
Checking login status
The module uses nuxt-auth-utils under the hood to manage the session.
You can use its composables to check whether a user is currently authenticated:
<script setup lang="ts">
const { loggedIn, user } = useUserSession()
</script>
<template>
<div v-if="loggedIn">
<p>Logged in as {{ user?.email }}</p>
</div>
<div v-else>
<button @click="navigateTo('/_auth/customer-account/callback')">
Log in
</button>
</div>
</template>
Once the user is authenticated, you can use the useCustomerAccount and useCustomerAccountData composables
to fetch customer data from the Customer Account API.
Usage
Client-side
useCustomerAccount
When setting the clientId for the customer account client in the module configuration, you can use
the useCustomerAccount composable in your client-side code. For example, in a page component:
<script setup lang="ts">
const customerAccount = useCustomerAccount()
const { data } = await customerAccount.request(`#graphql
query GetCustomer {
customer {
firstName
lastName
}
}
`)
</script>
<template>
<div v-if="data">
<h1>{{ data.customer.firstName }} {{ data.customer.lastName }}</h1>
</div>
</template>
You can also wrap use the useCustomerAccount composable in another composable, to build an abstracted
data fetching method:
export const useCustomerData = () => {
const customerAccount = useCustomerAccount()
return customerAccount.request(`#graphql
query GetCustomer {
customer {
firstName
lastName
}
}
`)
}
This way, you can reuse the useCustomerData composable in multiple places in your application.
By default, each request from the client side is proxied through the Nitro server.
This behaviour can be customized by setting proxy: false in the customer account client config.
useCustomerAccountData
You can wrap the useCustomerAccount call with Nuxt's useAsyncData composable to integrate into the hybrid rendering model.
To shorten the syntax, the module provides a composable called useCustomerAccountData that automatically does this for us:
<script setup lang="ts">
const { data: customer } = await useCustomerAccountData('customer', `#graphql
query GetCustomer {
customer {
id
firstName
lastName
}
}
`, {
transform: (data) => data?.customer,
})
</script>
<template>
<div v-if="customer">
<h1>Welcome, {{ customer.firstName }} {{ customer.lastName }}</h1>
</div>
</template>
Standard features of useAsyncData such as caching, revalidation, and error handling are all available when using useCustomerAccountData.
You can also use transform, pick, and other options to further customize the behavior of the data fetching.
Server-side
When setting the clientId for the customer account client in the module configuration,
you can use the useCustomerAccount composable in your server-side code.
For example, in a server route:
export default defineEventHandler((event) => {
const id = getRouterParam(event, 'id')
const customerAccount = useCustomerAccount()
return customerAccount.request(`#graphql
query GetOrder($id: ID!) {
order(id: $id) {
id
name
lineItems {
edges {
node {
title
quantity
}
}
}
}
}
`, {
variables: {
id: `gid://shopify/Order/${id}`,
}
})
})
Using validation
Using Nitro's built-in input validation, you can match the variables of your GraphQL queries before sending them to the API.
For this example we'll use the Zod library, but you can use any validation library you like.
First, install the validation library:
npm install zod
Then, import it and create a schema:
import { z } from 'zod'
const schema = z.object({
id: z.string().min(1).transform((value) => `gid://shopify/Order/${value}`),
})
transform method is used here to convert a simple string input into the format required by the Shopify API.
In this case, it takes an order ID and transforms it into the global ID format that Shopify expects.Next, we can use Nitro's built-in getValidatedRouterParams utility to validate the id route parameter:
import { z } from 'zod'
const schema = z.object({
id: z.string().min(1).transform((value) => `gid://shopify/Order/${value}`),
})
export default defineEventHandler(async (event) => {
const variables = await getValidatedRouterParams(event, schema.parse)
const customerAccount = useCustomerAccount()
const query = `#graphql
query GetOrder($id: ID!) {
order(id: $id) {
id
name
lineItems {
edges {
node {
title
quantity
}
}
}
}
}
`
return storefront.request(query, { variables })
})
Now we can call the API at /api/customer/order/[id] with the following variables:
// Requests /api/customer/order/1031437189199
const response = await useFetch('/api/customer/order/1031437189199')
With the validation, requests will fail before reaching Shopify if the variable id is not a valid string.