npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@athleticgreens/customer-api-client

v0.0.2

Published

Shopify Customer API Client - A lightweight JS client to interact with Shopify's Customer Account API

Readme

Customer API Client

The Customer API Client manages OAuth authentication and provides methods to interact with the Shopify Customer Account API. It handles the complete PKCE OAuth flow and makes authenticated GraphQL requests on behalf of logged-in customers.

Getting started

Using your preferred package manager, install this package in a project:

yarn add @shopify/customer-api-client
npm install @shopify/customer-api-client --s
pnpm add @shopify/customer-api-client

CDN

The UMD builds of each release version are available via the unpkg CDN

<script src="https://unpkg.com/@shopify/customer-api-client@latest/dist/umd/customer-api-client.min.js"></script>

<script>
  const client = ShopifyCustomerAPIClient.createCustomerApiClient({...});
</script>

Initialization

The client supports two OAuth client types:

  • Public clients (browser/mobile apps) — use PKCE for security. Do not provide clientSecret.
  • Confidential clients (server-side apps) — can securely store a clientSecret. Use Basic Auth on token requests; PKCE is omitted.

Public client (browser / mobile)

import {createCustomerApiClient} from '@shopify/customer-api-client';

const client = createCustomerApiClient({
  storeDomain: 'your-shop-name.myshopify.com',
  clientId: 'your-oauth-client-id',
  redirectUri: 'https://your-app.example.com/auth/callback',
});

Confidential client (server-side)

[!WARNING] clientSecret must never be exposed in a browser environment. Only use confidential clients in server-side code.

import {createCustomerApiClient} from '@shopify/customer-api-client';

const client = createCustomerApiClient({
  storeDomain: 'your-shop-name.myshopify.com',
  clientId: 'your-oauth-client-id',
  clientSecret: 'your-oauth-client-secret',
  redirectUri: 'https://your-app.example.com/auth/callback',
});

The client performs two discovery requests immediately on construction (they are not awaited until first use):

  • GET https://{storeDomain}/.well-known/openid-configuration — provides the OAuth endpoints (authorization_endpoint, token_endpoint, end_session_endpoint)
  • GET https://{storeDomain}/.well-known/customer-account-api — provides the GraphQL API URL (graphql_api)

createCustomerApiClient() parameters

| Property | Type | Description | | --------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | storeDomain | string | The domain of the store. Can be the Shopify myshopify.com domain or a custom store domain. | | apiVersion? | string | The default API version to use for all requests (e.g. '2026-01'). Can be overridden per request via options.apiVersion. | | clientId | string | Your app's OAuth client ID. | | clientSecret? | string | Your app's OAuth client secret. When provided, the client operates as a confidential client: token requests use Authorization: Basic instead of PKCE, and code_challenge is omitted from the authorization URL. Never expose this value in a browser environment. | | redirectUri | string | The URI to redirect to after authorization. Must match one of the redirect URIs configured for your app. | | clientName? | string | Name of the client. Included in request headers as X-SDK-Variant-Source. | | retries? | number | The number of HTTP request retries if the request was abandoned or the server responded with a Too Many Requests (429) or Service Unavailable (503) response. Default value is 0. | | customFetchApi? | (url: string, init?: {method?: string, headers?: HeaderInit, body?: string}) => Promise<Response> | A replacement fetch function used for all client network requests. By default, the client uses the global fetch. | | logger? | (logContent: HTTPResponseLog \| HTTPRetryLog) => void | A logger function that accepts log content objects. |

Client properties

| Property | Type | Description | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | config | CustomerApiClientConfig | Configuration for the client. | | getHeaders | (headers?: Record<string, string>) => Record<string, string> | Returns Customer API specific headers. If additional headers are provided, they are merged into the returned headers object. | | setTokens | (tokenSet: CustomerTokenSet) => void | Stores a token set in the client. Call this to restore tokens after a page reload. | | getTokens | () => CustomerTokenSet \| null | Returns the currently stored token set, or null if no tokens have been set. | | getAuthorizationUrl | (params?: GetAuthorizationUrlParams) => Promise<GetAuthorizationUrlResult> | Generates an authorization URL. For public clients, includes PKCE params and returns a codeVerifier to store. For confidential clients, PKCE is omitted and codeVerifier is undefined. | | exchangeCode | (params: ExchangeCodeParams) => Promise<CustomerTokenSet> | Exchanges an authorization code for a token set. Automatically calls setTokens() with the result. codeVerifier is required for public clients. | | refreshToken | (params?: RefreshTokenParams) => Promise<CustomerTokenSet> | Refreshes the access token using a refresh token. Uses the stored refresh token if params.refreshToken is not provided. Calls setTokens() with the result. | | getLogoutUrl | (params?: {idToken?: string; postLogoutRedirectUri?: string}) => Promise<string> | Returns the end-session URL. Uses the stored idToken if params.idToken is not provided. | | fetch | (operation: string, options?: CustomerRequestOptions) => Promise<Response> | Fetches data from the Customer Account API. Uses the stored access token unless options.customerAccessToken is provided. | | request | <TData>(operation: string, options?: CustomerRequestOptions) => Promise<ClientResponse<TData>> | Requests data from the Customer Account API and returns a normalized response object. Uses the stored access token unless options.customerAccessToken is provided. |

CustomerApiClientConfig properties

| Name | Type | Description | | ------------- | -------------------------- | ---------------------------------------------------------------- | | storeDomain | string | The normalized store domain URL | | apiVersion? | string | The default API version set at initialization | | clientId | string | The OAuth client ID | | clientSecret? | string | The OAuth client secret (confidential clients only) | | redirectUri | string | The OAuth redirect URI | | clientName? | string | The provided client name | | headers | Record<string, string> | The base headers generated by the client during initialization |

CustomerRequestOptions properties

| Name | Type | Description | | --------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | customerAccessToken? | string | An access token to use for this request. Overrides the stored token. If neither this option nor a stored token is available, the method throws an error. | | variables? | Record<string, any> | Variable values needed in the GraphQL operation. | | apiVersion? | string | Overrides the API version in the discovered GraphQL URL for this request (e.g. '2024-10'). | | headers? | Record<string, string> | Custom headers to include in the API request. | | retries? | number | Alternative number of retries for the request. Retries only occur for requests that were abandoned or if the server responds with a Too Many Request (429) or Service Unavailable (503) response. Minimum value is 0 and maximum value is 3. |

CustomerTokenSet

| Name | Type | Description | | -------------- | -------- | ----------------------------------------------------------- | | accessToken | string | The customer access token used to authenticate API requests | | refreshToken? | string | Token used to obtain a new access token when it expires | | expiresIn? | number | Number of seconds until the access token expires | | idToken? | string | OpenID Connect ID token for the customer session |

GetAuthorizationUrlParams

| Name | Type | Description | | ------- | -------- | -------------------------------------------------------------------------------------------- | | scope? | string | OAuth scopes to request. Defaults to openid email customer-account-api:full | | state? | string | Random string to prevent CSRF attacks. Generated automatically if not provided. | | nonce? | string | Random string for replay attack prevention. Generated automatically if not provided. |

GetAuthorizationUrlResult

| Name | Type | Description | | ------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------ | | url | string | The authorization URL to redirect the customer to | | codeVerifier? | string | The PKCE code verifier. Only present for public clients. Store this securely and pass it to exchangeCode(). | | state | string | The state parameter used in the authorization request | | nonce | string | The nonce parameter used in the authorization request |

ClientResponse<TData>

| Name | Type | Description | | ----------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | data? | TData \| any | Data returned from the Customer Account API. If TData was provided to the function, the return type is TData, else it returns type any. | | errors? | ResponseErrors | Errors object that contains any API or network errors that occurred while fetching the data from the API. It does not include any UserErrors. | | extensions? | Record<string, any> | Additional information on the GraphQL response data and context. |

ResponseErrors

| Name | Type | Description | | ------------------ | ---------- | --------------------------------------------------- | | networkStatusCode? | number | HTTP response status code | | message? | string | The provided error message | | graphQLErrors? | any[] | The GraphQL API errors returned by the server | | response? | Response | The raw response object from the network fetch call |

Usage examples

Complete OAuth PKCE flow

import {createCustomerApiClient} from '@shopify/customer-api-client';

const client = createCustomerApiClient({
  storeDomain: 'your-shop-name.myshopify.com',
  clientId: 'your-oauth-client-id',
  redirectUri: 'https://your-app.example.com/auth/callback',
});

// Step 1: Generate the authorization URL and redirect the customer
const {url, codeVerifier, state, nonce} = await client.getAuthorizationUrl();

// Store codeVerifier and state securely (e.g., in sessionStorage) before redirecting
sessionStorage.setItem('codeVerifier', codeVerifier);
sessionStorage.setItem('oauthState', state);
window.location.href = url;

// Step 2: On the callback page, exchange the authorization code for tokens
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
const returnedState = urlParams.get('state');

const savedState = sessionStorage.getItem('oauthState');
const savedCodeVerifier = sessionStorage.getItem('codeVerifier');

if (returnedState !== savedState) {
  throw new Error('State mismatch — possible CSRF attack');
}

const tokenSet = await client.exchangeCode({
  code,
  codeVerifier: savedCodeVerifier,
});

// Persist tokens for future page loads (e.g., localStorage, cookies)
localStorage.setItem('customerTokens', JSON.stringify(tokenSet));

Confidential client OAuth flow (server-side)

import {createCustomerApiClient} from '@shopify/customer-api-client';

// Server-side only — never expose clientSecret in a browser
const client = createCustomerApiClient({
  storeDomain: 'your-shop-name.myshopify.com',
  clientId: 'your-oauth-client-id',
  clientSecret: 'your-oauth-client-secret',
  redirectUri: 'https://your-app.example.com/auth/callback',
});

// Step 1: Generate the authorization URL (no PKCE — codeVerifier is undefined)
const {url, state} = await client.getAuthorizationUrl();
// Store state in the session for CSRF validation
req.session.oauthState = state;
res.redirect(url);

// Step 2: On the callback route, exchange the authorization code for tokens
// No codeVerifier needed for confidential clients
const tokenSet = await client.exchangeCode({code: req.query.code});
// Store tokens in the session or database
req.session.customerTokens = tokenSet;

Restore tokens after a page reload

const stored = localStorage.getItem('customerTokens');
if (stored) {
  client.setTokens(JSON.parse(stored));
}

Refresh an expired access token

// Uses the stored refresh token automatically if one was set via setTokens() or exchangeCode()
const newTokenSet = await client.refreshToken();

// Or pass the refresh token explicitly
const newTokenSet = await client.refreshToken({
  refreshToken: 'your-refresh-token',
});

Make an authenticated GraphQL request

const orderQuery = `
  query CustomerOrders {
    customer {
      orders(first: 5) {
        nodes {
          id
          name
          totalPrice {
            amount
            currencyCode
          }
        }
      }
    }
  }
`;

// Uses the stored access token automatically
const {data, errors, extensions} = await client.request(orderQuery);

Make a request with a per-request access token

const {data, errors} = await client.request(orderQuery, {
  customerAccessToken: 'customer-access-token',
});

Log out the customer

// Returns the end-session URL; redirect the customer to it to complete logout
const logoutUrl = await client.getLogoutUrl({
  postLogoutRedirectUri: 'https://your-app.example.com',
});

window.location.href = logoutUrl;

Set a default API version at initialization

const client = createCustomerApiClient({
  storeDomain: 'your-shop-name.myshopify.com',
  clientId: 'your-oauth-client-id',
  redirectUri: 'https://your-app.example.com/auth/callback',
  apiVersion: '2026-01',
});

// All requests use '2026-01' unless overridden
const {data, errors} = await client.request(orderQuery);

Override the API version for a single request

const {data, errors} = await client.request(orderQuery, {
  apiVersion: '2024-10',
});

Typing variables and return objects

This client is compatible with the @shopify/api-codegen-preset package. You can use that package to create types from your operations with the Codegen CLI.

There are different ways to configure codegen with it, but the simplest way is to:

  1. Add the preset package as a dev dependency to your project, for example:

    npm install --save-dev @shopify/api-codegen-preset
  2. Create a .graphqlrc.ts file in your root containing:

    import {ApiType, shopifyApiProject} from '@shopify/api-codegen-preset';
    
    export default {
      projects: {
        default: shopifyApiProject({
          apiType: ApiType.Customer,
          outputDir: './types',
        }),
      },
    };
  3. Add "graphql-codegen": "graphql-codegen" to your scripts section in package.json.

  4. Tag your operations with #graphql, for example:

    const {data, errors} = await client.request(
      `#graphql
      query CustomerOrders {
        customer {
          orders(first: 5) {
            nodes {
              id
              name
            }
          }
        }
      }`,
    );
    console.log(data?.customer.orders.nodes);
  5. Run npm run graphql-codegen to parse the types from your operations.

[!NOTE] Remember to ensure that your tsconfig includes the files under ./types!

Once the script runs, it'll create the file ./types/customer.generated.d.ts. When TS includes that file, it'll automatically cause the client to detect the types for each query.

Log Content Types

HTTPResponseLog

This log content is sent to the logger whenever an HTTP response is received by the client.

| Property | Type | Description | | -------- | ------------------------------------------------------------------------- | ----------------------------------------------------------- | | type | LogType['HTTP-Response'] | The type of log content. Is always set to HTTP-Response | | content | {requestParams: [url, init?], response: Response} | Contextual data regarding the request and received response |

HTTPRetryLog

This log content is sent to the logger whenever the client attempts to retry HTTP requests.

| Property | Type | Description | | -------- | ------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | type | LogType['HTTP-Retry'] | The type of log content. Is always set to HTTP-Retry | | content | {requestParams: [url, init?], lastResponse?: Response, retryAttempt: number, maxRetries: number} | Contextual data regarding the upcoming retry attempt. |