--- title: createCustomerClient description: >- > Caution: > This component is in an unstable pre-release state and may have breaking changes in a future release. The `createCustomerClient` function creates a GraphQL client for querying the [Customer Account API](https://shopify.dev/docs/api/customer). It also provides methods to authenticate and check if the user is logged in. See an end to end [example on using the Customer Account API client](https://github.com/Shopify/hydrogen/tree/main/examples/customer-api). api_version: 2023-10 api_name: hydrogen source_url: html: 'https://shopify.dev/docs/api/hydrogen/2023-10/utilities/createcustomerclient' md: >- https://shopify.dev/docs/api/hydrogen/2023-10/utilities/createcustomerclient.md --- # create​Customer​Client Caution This component is in an unstable pre-release state and may have breaking changes in a future release. The `createCustomerClient` function creates a GraphQL client for querying the [Customer Account API](https://shopify.dev/docs/api/customer). It also provides methods to authenticate and check if the user is logged in. See an end to end [example on using the Customer Account API client](https://github.com/Shopify/hydrogen/tree/main/examples/customer-api). ## create​Customer​Client([input1](#props-propertydetail-input1)​) ### Parameters * input1 CustomerClientOptions required ### Returns * CustomerClient ### CustomerClient * login () => Promise\ Start the OAuth login flow. This function should be called and returned from a Remix action. It redirects the user to a login domain. * authorize (redirectPath?: string) => Promise\ On successful login, the user is redirect back to your app. This function validates the OAuth response and exchanges the authorization code for an access token and refresh token. It also persists the tokens on your session. This function should be called and returned from the Remix loader configured as the redirect URI within the Customer Account API settings. * isLoggedIn () => Promise\ Returns if the user is logged in. It also checks if the access token is expired and refreshes it if needed. * logout () => Promise\ Logout the user by clearing the session and redirecting to the login domain. It should be called and returned from a Remix action. * query \(query: RawGqlString, options?: { variables: Record\; }) => Promise\ Execute a GraphQL query against the Customer Account API. Usually you should first check if the user is logged in before querying the API. * mutate \(mutation: RawGqlString, options?: { variables: Record\; }) => Promise\ Execute a GraphQL mutation against the Customer Account API. Usually you should first check if the user is logged in before querying the API. ### CustomerClientOptions * session The client requires a session to persist the auth and refresh token. By default Hydrogen ships with cookie session storage, but you can use \[another session storage]\(https://remix.run/docs/en/main/utils/sessions) implementation. ```ts HydrogenSession ``` * customerAccountId Unique UUID prefixed with \`shp\_\` associated with the application, this should be visible in the customer account api settings in the Hydrogen admin channel. ```ts string ``` * customerAccountUrl The account URL associated with the application, this should be visible in the customer account api settings in the Hydrogen admin channel. ```ts string ``` * customerApiVersion Override the version of the API ```ts string ``` * request The object for the current Request. It should be provided by your platform. ```ts CrossRuntimeRequest ``` * waitUntil The waitUntil function is used to keep the current request/response lifecycle alive even after a response has been sent. It should be provided by your platform. ```ts ExecutionContext ``` ```ts { /** The client requires a session to persist the auth and refresh token. By default Hydrogen ships with cookie session storage, but you can use [another session storage](https://remix.run/docs/en/main/utils/sessions) implementation. */ session: HydrogenSession; /** Unique UUID prefixed with `shp_` associated with the application, this should be visible in the customer account api settings in the Hydrogen admin channel. */ customerAccountId: string; /** The account URL associated with the application, this should be visible in the customer account api settings in the Hydrogen admin channel. */ customerAccountUrl: string; /** Override the version of the API */ customerApiVersion?: string; /** The object for the current Request. It should be provided by your platform. */ request: CrossRuntimeRequest; /** The waitUntil function is used to keep the current request/response lifecycle alive even after a response has been sent. It should be provided by your platform. */ waitUntil?: ExecutionContext['waitUntil']; } ``` ### HydrogenSession * get ```ts (key: string) => string ``` * set ```ts (key: string, value: string) => void ``` * unset ```ts (key: string) => void ``` * commit ```ts () => Promise ``` ```ts export interface HydrogenSession { get: (key: string) => string | undefined; set: (key: string, value: string) => void; unset: (key: string) => void; commit: () => Promise; } ``` ### CrossRuntimeRequest * url ```ts string ``` * method ```ts string ``` * headers ```ts { [key: string]: any; get?: (key: string) => string; } ``` ```ts { url?: string; method?: string; headers: { get?: (key: string) => string | null | undefined; [key: string]: any; }; } ``` ### CustomerClient * login Start the OAuth login flow. This function should be called and returned from a Remix action. It redirects the user to a login domain. ```ts () => Promise ``` * authorize On successful login, the user is redirect back to your app. This function validates the OAuth response and exchanges the authorization code for an access token and refresh token. It also persists the tokens on your session. This function should be called and returned from the Remix loader configured as the redirect URI within the Customer Account API settings. ```ts (redirectPath?: string) => Promise ``` * isLoggedIn Returns if the user is logged in. It also checks if the access token is expired and refreshes it if needed. ```ts () => Promise ``` * logout Logout the user by clearing the session and redirecting to the login domain. It should be called and returned from a Remix action. ```ts () => Promise ``` * query Execute a GraphQL query against the Customer Account API. Usually you should first check if the user is logged in before querying the API. ```ts (query: RawGqlString, options?: { variables: Record; }) => Promise ``` * mutate Execute a GraphQL mutation against the Customer Account API. Usually you should first check if the user is logged in before querying the API. ```ts (mutation: RawGqlString, options?: { variables: Record; }) => Promise ``` ```ts { /** Start the OAuth login flow. This function should be called and returned from a Remix action. It redirects the user to a login domain. */ login: () => Promise; /** On successful login, the user is redirect back to your app. This function validates the OAuth response and exchanges the authorization code for an access token and refresh token. It also persists the tokens on your session. This function should be called and returned from the Remix loader configured as the redirect URI within the Customer Account API settings. */ authorize: (redirectPath?: string) => Promise; /** Returns if the user is logged in. It also checks if the access token is expired and refreshes it if needed. */ isLoggedIn: () => Promise; /** Logout the user by clearing the session and redirecting to the login domain. It should be called and returned from a Remix action. */ logout: () => Promise; /** Execute a GraphQL query against the Customer Account API. Usually you should first check if the user is logged in before querying the API. */ query: ( query: RawGqlString, options?: {variables: Record}, ) => Promise; /** Execute a GraphQL mutation against the Customer Account API. Usually you should first check if the user is logged in before querying the API. */ mutate: ( mutation: RawGqlString, options?: {variables: Record}, ) => Promise; } ``` Examples ### Examples * #### Example code ##### Description I am the default example ##### JavaScript ```jsx import {createCustomerClient__unstable} from '@shopify/hydrogen'; import * as remixBuild from '@remix-run/dev/server-build'; import { createRequestHandler, createCookieSessionStorage, } from '@shopify/remix-oxygen'; export default { async fetch(request, env, executionContext) { const session = await HydrogenSession.init(request, [env.SESSION_SECRET]); /* Create a Customer API client with your credentials and options */ const customer = createCustomerClient__unstable({ /* Runtime utility in serverless environments */ waitUntil: (p) => executionContext.waitUntil(p), /* Public Customer Account API token for your store */ customerAccountId: env.PUBLIC_CUSTOMER_ACCOUNT_ID, /* Public account URL for your store */ customerAccountUrl: env.PUBLIC_CUSTOMER_ACCOUNT_URL, request, session, }); const handleRequest = createRequestHandler({ build: remixBuild, mode: process.env.NODE_ENV, /* Inject the customer account client in the Remix context */ getLoadContext: () => ({customer}), }); return handleRequest(request); }, }; class HydrogenSession { static async init(request, secrets) { const storage = createCookieSessionStorage({ cookie: { name: 'session', httpOnly: true, path: '/', sameSite: 'lax', secrets, }, }); const session = await storage.getSession(request.headers.get('Cookie')); return new this(storage, session); } get(key) { return this.session.get(key); } destroy() { return this.sessionStorage.destroySession(this.session); } flash(key, value) { this.session.flash(key, value); } unset(key) { this.session.unset(key); } set(key, value) { this.session.set(key, value); } commit() { return this.sessionStorage.commitSession(this.session); } } ``` ##### TypeScript ```tsx import {createCustomerClient__unstable} from '@shopify/hydrogen'; import * as remixBuild from '@remix-run/dev/server-build'; import { createRequestHandler, createCookieSessionStorage, type SessionStorage, type Session, } from '@shopify/remix-oxygen'; export default { async fetch( request: Request, env: Record, executionContext: ExecutionContext, ) { const session = await HydrogenSession.init(request, [env.SESSION_SECRET]); /* Create a Customer API client with your credentials and options */ const customer = createCustomerClient__unstable({ /* Runtime utility in serverless environments */ waitUntil: (p) => executionContext.waitUntil(p), /* Public Customer Account API client ID for your store */ customerAccountId: env.PUBLIC_CUSTOMER_ACCOUNT_ID, /* Public account URL for your store */ customerAccountUrl: env.PUBLIC_CUSTOMER_ACCOUNT_URL, request, session, }); const handleRequest = createRequestHandler({ build: remixBuild, mode: process.env.NODE_ENV, /* Inject the customer account client in the Remix context */ getLoadContext: () => ({customer}), }); return handleRequest(request); }, }; class HydrogenSession { constructor( private sessionStorage: SessionStorage, private session: Session, ) {} static async init(request: Request, secrets: string[]) { const storage = createCookieSessionStorage({ cookie: { name: 'session', httpOnly: true, path: '/', sameSite: 'lax', secrets, }, }); const session = await storage.getSession(request.headers.get('Cookie')); return new this(storage, session); } get(key: string) { return this.session.get(key); } destroy() { return this.sessionStorage.destroySession(this.session); } flash(key: string, value: any) { this.session.flash(key, value); } unset(key: string) { this.session.unset(key); } set(key: string, value: any) { this.session.set(key, value); } commit() { return this.sessionStorage.commitSession(this.session); } } ``` ## Related [- createStorefrontClient](https://shopify.dev/docs/api/hydrogen/2023-10/utilities/createstorefrontclient)