The GraphQL Client is a lightweight, generic client for interacting with any of Shopify’s GraphQL APIs. It provides core GraphQL functionality including request handling, streaming responses, and automatic retries.
For most use cases, use the Admin API Client or Storefront API Client instead. Use this client when you need direct control over the API URL and headers, or when working with custom GraphQL endpoints.
Installation
npm install @shopify/graphql-client
CDN Usage
You can use the UMD build via CDN:
< script src = "https://unpkg.com/@shopify/[email protected] /dist/umd/graphql-client.min.js" ></ script >
< script >
const client = ShopifyGraphQLClient . createGraphQLClient ({
url: 'https://shop.myshopify.com/api/2025-01/graphql.json' ,
headers: {
'Content-Type' : 'application/json' ,
'X-Shopify-Storefront-Access-Token' : 'token' ,
},
});
</ script >
Basic Setup
import { createGraphQLClient } from '@shopify/graphql-client' ;
const client = createGraphQLClient ({
url: 'https://your-shop.myshopify.com/api/2025-01/graphql.json' ,
headers: {
'Content-Type' : 'application/json' ,
'X-Shopify-Storefront-Access-Token' : 'your-token' ,
},
retries: 1 ,
});
Configuration Options
The complete GraphQL API endpoint URL
Headers to include in all requests (e.g., authentication, content-type)
Number of retry attempts for failed requests (max: 3)
Custom fetch implementation for Node.js or other environments
Logger function for debugging and monitoring
Making Requests
Using request()
The request() method returns a normalized response:
const productQuery = `
query ProductQuery($handle: String!) {
product(handle: $handle) {
id
title
handle
}
}
` ;
const { data , errors , extensions } = await client . request ( productQuery , {
variables: {
handle: 'sample-product' ,
},
});
if ( errors ) {
console . error ( 'Error:' , errors . message );
} else {
console . log ( 'Product:' , data . product );
}
Using fetch()
The fetch() method returns the raw Response object:
const shopQuery = `
query {
shop {
name
email
}
}
` ;
const response = await client . fetch ( shopQuery );
if ( response . ok ) {
const { data , errors , extensions } = await response . json ();
console . log ( 'Shop:' , data . shop . name );
}
Response Types
ClientResponse
The GraphQL response data. Type is TData if provided, otherwise any
API or network errors (excludes UserErrors)
Additional response metadata and context
ResponseErrors
HTTP response status code
Error message description
Array of GraphQL errors from the API
Raw Response object from fetch
Streaming Responses
Use requestStream() for operations with the @defer directive:
const productQuery = `
query ProductWithDefer($handle: String!) {
product(handle: $handle) {
id
handle
... @defer(label: "details") {
title
description
}
}
}
` ;
const responseStream = await client . requestStream ( productQuery , {
variables: { handle: 'sample-product' },
});
for await ( const response of responseStream ) {
const { data , errors , extensions , hasNext } = response ;
console . log ( 'Received data:' , data );
if ( ! hasNext ) {
console . log ( 'Stream complete' );
break ;
}
}
@defer Required : The requestStream() method only works with operations containing the @defer directive. For regular operations, use request() instead.
Stream Response Type
Currently available data (may be partial)
Whether more data is coming in the stream
Request Options
All request methods accept an options object:
GraphQL operation variables
Override the default API URL for this request
Additional or override headers for this request
Override retry count for this request (0-3)
Keep connection alive when page unloads before request completes
AbortSignal for canceling the request
Advanced Usage
const { data } = await client . request ( query , {
variables: { handle: 'product' },
headers: {
'X-Custom-Header' : 'value' ,
},
});
Override URL Per Request
const { data } = await client . request ( query , {
variables: { handle: 'product' },
url: 'https://shop.myshopify.com/api/unstable/graphql.json' ,
});
Request Retries
const { data } = await client . request ( query , {
retries: 2 , // Retry up to 2 times on 429/503 errors
});
Keepalive Requests
Prevent request cancellation when page unloads:
const { data } = await client . request ( analyticsQuery , {
keepalive: true ,
});
Request Cancellation
const controller = new AbortController ();
const promise = client . request ( query , {
signal: controller . signal ,
});
// Cancel the request
controller . abort ();
Server-Side Usage
For Node.js environments, provide a custom fetch implementation:
import { createGraphQLClient } from '@shopify/graphql-client' ;
import { fetch as nodeFetch } from 'node-fetch' ;
const client = createGraphQLClient ({
url: 'https://shop.myshopify.com/api/2025-01/graphql.json' ,
headers: {
'Content-Type' : 'application/json' ,
'X-Shopify-Storefront-Access-Token' : 'token' ,
},
customFetchApi: nodeFetch ,
});
Client Properties
Client configuration object {
url : string ,
headers : Record < string , string | string [] > ,
retries : number
}
fetch
(operation, options?) => Promise<Response>
Makes a raw fetch request and returns the Response
request
<TData>(operation, options?) => Promise<ClientResponse<TData>>
Makes a request and returns a normalized response
requestStream
<TData>(operation, options?) => Promise<AsyncIterator<ClientStreamResponse<TData>>>
Makes a streaming request for operations with @defer
Error Handling
Network Errors
const { data , errors } = await client . request ( query );
if ( errors ) {
if ( errors . networkStatusCode === 401 ) {
console . error ( 'Unauthorized' );
} else if ( errors . networkStatusCode === 429 ) {
console . error ( 'Rate limited' );
} else if ( errors . networkStatusCode === 503 ) {
console . error ( 'Service unavailable' );
}
}
GraphQL Errors
const { data , errors } = await client . request ( query );
if ( errors ?. graphQLErrors ) {
errors . graphQLErrors . forEach (( error ) => {
console . error ( 'GraphQL Error:' , error . message );
console . error ( 'Path:' , error . path );
console . error ( 'Extensions:' , error . extensions );
});
}
Stream Errors
const stream = await client . requestStream ( query );
for await ( const response of stream ) {
if ( response . errors ) {
console . error ( 'Stream error:' , response . errors . message );
break ;
}
console . log ( 'Data:' , response . data );
}
Logging
Monitor requests and retries:
const client = createGraphQLClient ({
url: 'https://api.example.com/graphql' ,
headers: { 'Content-Type' : 'application/json' },
logger : ( log ) => {
if ( log . type === 'HTTP-Response' ) {
console . log ( 'Response:' , log . content . response . status );
} else if ( log . type === 'HTTP-Retry' ) {
const { retryAttempt , maxRetries } = log . content ;
console . log ( `Retry ${ retryAttempt } / ${ maxRetries } ` );
}
},
});
Log Types
Sent when an HTTP response is received {
type : 'HTTP-Response' ,
content : {
requestParams : [ url , init ],
response : Response
}
}
Sent when the client retries a request {
type : 'HTTP-Retry' ,
content : {
requestParams : [ url , init ],
lastResponse : Response ,
retryAttempt : number ,
maxRetries : number
}
}
HTTP-Response-GraphQL-Deprecation-Notice
HTTPResponseGraphQLDeprecationNotice
Sent when deprecated fields are used {
type : 'HTTP-Response-GraphQL-Deprecation-Notice' ,
content : {
requestParams : [ url , init ],
deprecationNotice : string
}
}
Utility Functions
The GraphQL Client also exports utility functions:
API Version Utilities
import {
getCurrentSupportedApiVersions ,
validateApiVersion ,
} from '@shopify/graphql-client' ;
// Get currently supported API versions
const versions = getCurrentSupportedApiVersions ();
console . log ( versions ); // ['2024-10', '2025-01', '2025-04', 'unstable']
// Validate an API version
validateApiVersion ({
client: 'My Client' ,
currentSupportedApiVersions: versions ,
apiVersion: '2025-01' ,
logger : ( log ) => console . warn ( log ),
});
Domain Validation
import { validateDomainAndGetStoreUrl } from '@shopify/graphql-client' ;
const url = validateDomainAndGetStoreUrl ({
client: 'My Client' ,
storeDomain: 'shop.myshopify.com' ,
});
console . log ( url ); // 'https://shop.myshopify.com'
Type Safety
Use TypeScript generics for type-safe responses:
interface Product {
id : string ;
title : string ;
handle : string ;
}
interface ProductQueryResponse {
product : Product ;
}
const { data } = await client . request < ProductQueryResponse >(
productQuery ,
{ variables: { handle: 'shoe' }}
);
// data.product is typed as Product
console . log ( data ?. product . title );
Best Practices
Use Specific Clients : For Admin or Storefront APIs, prefer the dedicated clients as they handle authentication and URL formatting automatically.
Retry Strategy : Retries only occur for abandoned requests or 429/503 status codes. Configure appropriate retry counts based on your use case.
Browser vs Server : When using in Node.js, always provide a custom fetch API like node-fetch.
Examples
Admin API
const client = createGraphQLClient ({
url: 'https://shop.myshopify.com/admin/api/2025-01/graphql.json' ,
headers: {
'Content-Type' : 'application/json' ,
'X-Shopify-Access-Token' : 'admin-token' ,
},
});
Storefront API
const client = createGraphQLClient ({
url: 'https://shop.myshopify.com/api/2025-01/graphql.json' ,
headers: {
'Content-Type' : 'application/json' ,
'X-Shopify-Storefront-Access-Token' : 'storefront-token' ,
},
});
Custom GraphQL Endpoint
const client = createGraphQLClient ({
url: 'https://my-custom-api.com/graphql' ,
headers: {
'Content-Type' : 'application/json' ,
'Authorization' : 'Bearer custom-token' ,
},
});
Next Steps
Admin API Client Use the Admin API-specific client
Storefront API Client Use the Storefront API-specific client