BigCommerce
Storefront
GraphQL Storefront
Overview

GraphQL Storefront API Overview

BigCommerce's GraphQL Storefront API makes it possible to power a headless storefront; see Introduction to Headless Commerce for details. The GraphQL Storefront API also lets you query storefront data from within a Stencil theme.

This graph serves as a flexible interface for building shopper experiences. For example, with the GraphQL Storefront API, it is possible to do the following:

  • Query product catalog data to help shoppers find the product they're looking for through BigCommerce's searching, filtering, and sorting capabilities.
  • Request any product's images at any resolution.
  • Ask for a signed-in customer's details, such as name, email address, and attributes.
  • Look up objects, such as categories or brands, by URL, and fetch their details.
  • Create new carts, fetch existing carts, and initiate checkout.

Additionally, by leveraging the power of GraphQL (opens in a new tab), data for multiple resources can be returned from a single API call, which simplifies integration and increases performance so that developers can focus on building delightful shopper experiences.

This article is a general overview of BigCommerce's GraphQL Storefront API; it includes sections on authentication and how to access a store's GraphQL Playground. To see specific examples of how GraphQL can be used to query storefront data, see GraphQL Storefront API Example Queries.

Stores using BigCommerce's legacy Blueprint theme framework do not support the GraphQL API and Playground.

See it in action

To see a simple example of the GraphQL Storefront API in action, check out the Bootstrap + Vanilla JS GraphQL Storefront API Example (opens in a new tab) hosted on GitHub. This example shows how a static HTML site can render dynamic product information using the GraphQL Storefront API.

Open the link and click submit with the sample data in the form. To see the example page with your store's data, create a GraphQL Storefront API token against your store and paste the token into the example form. Be sure to create a token valid for this origin: https://bigcommerce.github.io.

Accessing the GraphQL Playground

To access the GraphQL Storefront API Playground and documentation, sign in to your store (opens in a new tab) and navigate to Settings > API> Storefront API Playground.

The GraphQL Storefront API Playground will open.

GraphQL Storefront API Playground

If the Storefront API Playground link is not visible, this may be because your store is not using a Stencil theme. Apply a Stencil theme to use the GraphQL Storefront API.

Using the GraphQL Playground

To use the request runner, input queries on the left side and then click the Play button. Query results will be displayed on the right side.

GraphQL Playground Query

The following is an example query to get you started.

Example query
query MyFirstQuery {
  site {
    settings {
      storeName
    }
    products {
      edges {
        node {
          name
          sku
          prices {
            retailPrice {
              value
              currencyCode
            }
            price {
              value
              currencyCode
            }
          }
        }
      }
    }
  }
}

To explore the storefront GraphQL schema, checkout the Docs and Explorer tabs on the right.

GraphQL Playground Docs

You may also explore the graph visually using our GraphQL Explorer (opens in a new tab).

Authentication

GraphQL Storefront API requests are authenticated with JWT bearer tokens sent using the HTTP Authorization header.

Example Authorization header using cURL
curl 'https://{bigcommerce_storefront_domain}.com/graphql'\
  # ...
  -H 'authorization: Bearer {token}'\
  # ...

Creating a token

Use the Create a storefront token REST endpoint to request JWT bearer tokens that authenticate requests to the GraphQL Storefront API. Add a token creation scope to the store-level or app-level API account you use to generate tokens.

This type of token is the most appropriate for use directly within web browsers. If you're creating a token for an application that will make server-to-server requests to the GraphQL Storefront API, a Customer Impersonation Token may be more appropriate for your use case. This special token is not necessary if you only wish to query information from an anonymous shopper's perspective.

For security reasons, GraphQL Storefront API tokens are scoped to particular CORS (opens in a new tab) origins, so you must supply the origin(s) on which you intend to use the token in order for requests from browsers to work correctly. If you do not supply any CORS origins for your token, the API will reject requests originating from web browsers, although you can still use it in other contexts.

Example request: Create a GraphQL Storefront API token
POST https://api.bigcommerce.com/stores/{{STORE_HASH}}/v3/storefront/api-token
x-auth-token: {{access_token}}
accept: application/json
content-type: application/json
 
{
  "channel_id": 1,            // integer (must be a valid channel ID on the store)
  "expires_at": 1602288000,   // when the token will expire, as an integer unix timestamp (in seconds)
  "allowed_cors_origins": [   // array of origins (up to 2 origins per token are allowed)
    "https://example.com"
  ]
}
  • Generally speaking, this type of GraphQL Storefront API token is not considered sensitive, and it is safe to expose in web browsers, for example, in HTML documents. This token can only expose information that an individual shopper is already privy to when browsing a storefront or allow them to perform actions that shoppers can perform (e.g. creating a shopper cart).
  • It is possible to create a long-lived token that does not expire, which is appropriate if you wish to create a token once and store it in an application environment.
  • In the interest of a better security posture, it is recommended to create shorter-lived tokens and rotate them periodically by calling this API to generate a new one before the old one expires.

Using auto-generated tokens in Stencil themes

Client code in BigCommerce Stencil themes can be passed a token at render time with the {{settings.storefront_api.token}} Handlebars property, making it unnecessary to generate a token using the Admin API before using the Storefront API.

This auto-generated token has an expiry period of 24-48 hours and will periodically rotate before expiration.

Customer impersonation tokens

You can use Customer Impersonation Tokens to authenticate requests to the GraphQL Storefront API in server-to-server and headless interactions. Add the Storefront API Customer Impersonation Tokens scope to the store-level or app-level API account you use when you Create a customer impersonation token.

Example request: Create a customer impersonation token
POST https://api.bigcommerce.com/stores/{{STORE_HASH}}/v3/storefront/api-token-customer-impersonation
x-auth-token: {{access_token}}
accept: application/json
content-type: application/json
 
{
  "channel_id": 1, // integer (must be a valid channel ID on the store)
  "expires_at": 1602288000 // when the token will expire, as an integer unix timestamp (in seconds)
}

Customer impersonation token-authenticated requests made to the GraphQL Storefront API may query store information from the perspective of ANY customer by specifying the customer ID using the x-bc-customer-id header sent with the GraphQL POST request. Customer-specific data such as product pricing & availability, customer account details, and other parameters will change to reflect the specified customer's data.

Unlike typical GraphQL Storefront API tokens, Customer impersonation tokens are sensitive and should, therefore never be exposed publicly, for example, to JavaScript or HTML. You should not use these tokens for front-end requests. They should be treated with the same care as other application secrets, just as you might treat an OAuth access token for BigCommerce's REST APIs. Requests using these tokens originating from a web browser will be rejected.

It is not necessary to generate a new token for each customer ID. You may use a single token at any given time for your application, and specify the customer ID for each request via request headers.

Consider this sample request using a Customer Impersonation token to run a request in the context of customer ID 123.

Example request: Query as customer 123
curl 'https://store.com/graphql' -H 'authorization: Bearer TOKEN_GOES_HERE' -H 'x-bc-customer-id: 123' --data-binary '{"query":"query CustomerInformation {\n  customer {\n    firstName\n    lastName\n    email\n  }\n}"}'
  • If your token were to become compromised and you wish to sever the Storefront API connection for your token, you can use the Revoke a token endpoint. Only use this in emergencies, and do not revoke tokens unnecessarily. Instead, use a shorter expiration and allow them to expire naturally.

Customer login

If you're using the GraphQL Storefront API from a browser, for example, on top of your Stencil storefront, you can use the Customer Login mutation to sign in to a customer account with an email address and a password. This will set a session cookie in the browser, which will authenticate the customer account on future requests.

A customer can only sign in to their account on one device. When running the customer login mutation for a session on a new device, a customer is automatically signed out.

Example query: login mutation
mutation Login($email: String!, $pass: String!) {
  login(email: $email, password: $pass) {
    result
    customer {
      entityId
      firstName
      lastName
      email
    }
  }
}

This mutation is also useful for server-to-server or headless storefront applications using a Customer Impersonation Token. For example, this interface can validate a customer's email address + password to power a login form. When the credentials are correct, and the mutation returns successfully, you can take the resulting customer ID and store it in a session to use in the x-bc-customer-id header in future requests for that shopper.

As a security best practice, you should inject the email address & password using GraphQL query variables. This prevents the password from being exposed in the query itself. In the GraphQL Playground, you can set the variables for the request.

GraphQL Playground Query Variables

You can use a logout mutation to sign out of a customer account:

Example query: logout mutation
mutation Logout {
  logout {
    result
  }
}

This will clear the session cookie, which has the effect of logging out the shopper, and future GraphQL requests will be from the perspective of an anonymous shopper.

Querying within a BigCommerce storefront

You can make GraphQL Storefront API calls directly from within a Stencil theme or from a script in the store's Script Manager (opens in a new tab).

The following example request uses the {{settings.storefront_api.token}} Handlebars object and JavaScript's Fetch API (opens in a new tab):

The fetch request's credentials property must be set to same-origin.

Example request: GraphQL query using Stencil auto-generated token
<script>
fetch('/graphql', {
  method: 'POST',
  credentials: 'same-origin',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer {{ settings.storefront_api.token }}' // use auto-generated token
  },
  body: JSON.stringify({
    query: `query MyFirstQuery {
      site {
        settings {
          storeName
        }
        products {
          edges {
            node {
              name
              sku
              defaultImage {
                url(width: 1280)
              }
            }
          }
        }
      }
    }`
  })
})
.then(res => res.json())
.then(data => console.log(data)) // will log JSON result to browser console
.catch(error => console.error(error));
</script>

You can limit the number of items retrieved for the nodes that return multiple items. See the section on pagination later in this article.

Client libraries like Apollo (opens in a new tab) offer features that can simplify GraphQL implementations, such as declarative data fetching (opens in a new tab), state management (opens in a new tab), and caching (opens in a new tab) for more consistent UI components. For an example of adding Apollo Client to the Cornerstone theme, check out this Cornerstone commit (opens in a new tab) on GitHub.

Pagination

The GraphQL Storefront API follows the GraphQL Cursor Connections Specification (opens in a new tab) for pagination. If this is your first time working with GraphQL pagination, see Apollo's Blog Post "Explaining GraphQL Connections" (opens in a new tab) for an accessible introduction. If you've worked with other GraphQL APIs, pagination on BigCommerce should look familiar.

For example, consider the following query for a store's first three products (notice first: 3 passed to products):

Example query: first three products
query paginateProducts {
  site {
    products (first: 3) {
      pageInfo {
        startCursor
        endCursor
        hasNextPage
      }
      edges {
        cursor
        node {
          entityId
          name
        }
      }
    }
  }
}

You can run this query against an example storefront using the GraphQL Playground.

The results look something like the following:

Example response: first three products
{
  "data": {
    "site": {
      "products": {
        "pageInfo": {
          "startCursor": "YXJyYXljb25uZWN0aW9uOjA=",
          "endCursor": "YXJyYXljb25uZWN0aW9uOjI=",
          "hasNextPage": true
        },
        "edges": [
          {
            "cursor": "YXJyYXljb25uZWN0aW9uOjA=",
            "node": {
              "entityId": 80,
              "name": "Orbit Terrarium - Large"
            }
          },
          {
            "cursor": "YXJyYXljb25uZWN0aW9uOjE=",
            "node": {
              "entityId": 81,
              "name": "Shower Curtain"
            }
          },
          {
            "cursor": "YXJyYXljb25uZWN0aW9uOjI=",
            "node": {
              "entityId": 82,
              "name": "Chambray Towel"
            }
          }
        ]
      }
    }
  }
}

Notice the edge corresponding to entityId: 81 has a cursor of YXJyYXljb25uZWN0aW9uOjE=. We can pass that cursor to the after parameter to get the three products after entityId: 81:

Example query using cursor
query paginateProducts {
  site {
    products (first: 3, after: "YXJyYXljb25uZWN0aW9uOjE=") {
      pageInfo {
        startCursor
        endCursor
        hasNextPage
      }
      edges {
        cursor
        node {
          entityId
          name
        }
      }
    }
  }
}

The results will look something like this (notice the last product entityId: 82 is now the first product):

Example response using cursor
{
  "data": {
    "site": {
      "products": {
        "pageInfo": {
          "startCursor": "YXJyYXljb25uZWN0aW9uOjI=",
          "endCursor": "YXJyYXljb25uZWN0aW9uOjQ=",
          "hasNextPage": true
        },
        "edges": [
          {
            "cursor": "YXJyYXljb25uZWN0aW9uOjI=",
            "node": {
              "entityId": 82,
              "name": "Chambray Towel"
            }
          },
          {
            "cursor": "YXJyYXljb25uZWN0aW9uOjM=",
            "node": {
              "entityId": 83,
              "name": "Hand & Body Cream"
            }
          },
          {
            "cursor": "YXJyYXljb25uZWN0aW9uOjQ=",
            "node": {
              "entityId": 84,
              "name": "Room Spray"
            }
          }
        ]
      }
    }
  }
}

This same approach can be used to slice any GraphQL connection and paginate through the slices using startCursor and endCursor. For example, the following query gets the first thirty brands:

Example query using slices
query brands {
  site {
    brands (first: 30) {
      pageInfo {
        startCursor
        endCursor
      }
      edges {
        cursor
        node {
          name
        }
      }
    }
  }
}

And given the following results:

Example response using slices
{
  "data": {
    "site": {
      "brands": {
        "pageInfo": {
          "startCursor": "YXJyYXljb25uZWN0aW9uOjA=",
          "endCursor": "YXJyYXljb25uZWN0aW9uOjM="
        },
        "edges": [
          {
            "cursor": "YXJyYXljb25uZWN0aW9uOjA=",
            "node": {
              "name": "Sagaform"
            }
          },
          ...
        ]
      }
    }
  }
}

You can retrieve the next thirty by making a new query and passing in the endCursor from the first page of results:

Example query using slices and cursor
query brands {
  site {
    brands (first: 30, after:"YXJyYXljb25uZWN0aW9uOjM=")  {
      pageInfo {
        startCursor
        endCursor
      }
      edges {
        cursor
        node {
          name
        }
      }
    }
  }
}

If first is not specified, a query returns only 10 items by default.

Complexity limits

Complexity scores estimate the load that a single GraphQL request may generate. BigCommerce calculates the complexity score using an algorithm before executing the call, based on the provided query.

The API sets a complexity limit of 10,000 for each request to prevent excessive loads. Because all work is generated per request, the limit is fixed per request, regardless of the number of requests sent.

When you send a valid GraphQL request, the API returns the query complexity as an integer using the HTTP response header X-Bc-Graphql-Complexity .

If a query's complexity score exceeds the complexity limit, an error response similar to the following appears:

Example response with complexity error
{
  "errors": [
    {
      "message": "The query is too complex as it has a complexity score of 12230 out of 10000. Please remove some elements and try again"
    }
  ]
}

The complexity limit error is usually caused by queries with a large quantity of deeply nested objects; for example, this query requests four different product collections together with their prices, variants, options, and option values.

Example query with excessive complexity
query {
  site {
    products(first: 50) {
      edges {
        node {
          ...ProductFields
        }
      }
    }
    featuredProducts(first:50) {
      edges {
        node {
          ...ProductFields
        }
      }
    }
    newestProducts(first:50) {
      edges {
        node {
          ...ProductFields
        }
      }
    }
    bestSellingProducts(first:50) {
      edges {
        node {
          ...ProductFields
        }
      }
    }
  }
}
 
fragment ProductFields on Product {
  name
  prices {
    price {
      value
      currencyCode
    }
    retailPrice {
      value
      currencyCode
    }
  }
  variants(first: 250) {
    edges {
      node {
        entityId
        depth {
          value
          unit
        }
        sku
      }
    }
  }
  productOptions(first: 50) {
    edges {
      node {
        displayName
        ... on MultipleChoiceOption {
          values(first: 50) {
            edges {
              node {
                label
                entityId
              }
            }
          }
        }
      }
    }
  }
}

You can easily reduce the complexity of this query by changing the number of products queried in each collection from first:50 to first:10:

Example query with limited complexity
query {
  site {
    products(first:10) { // <--- reducing quantity requested reduces complexity score
      // ...
    }
  }
}

Filter arguments and character limits don't contribute to complexity.

Example query
query {
  site {
    content {
      blog {
        posts (filters: {tags:["Most Popular"]}) { // Filter argument
          edges {
            node {
              plainTextSummary (characterLimit: 100) // Character limit
            }
          }
        }
      }
    }
  }
}

To reduce complexity, reduce the number of objects requested. For example, do the following:

  • Limit collections to a smaller page size (for example, first:10 instead of first:50).
  • Reduce the number of items in nested collections, exponentially affecting complexity.
  • Request fewer fields on objects, and don't request fields you don't need.

Mutations have a higher complexity than queries; you can only send one mutation in a single request. Pagination info also contributes to complexity.

Query depth

In addition to the complexity limit, there is a query depth limit. The limit is 16. Queries must not exceed the query depth limit and the complexity limit.

Every parent type adds an additional level of depth, as shown in the following examples.

Example query with depth of 11
query {                                 // depth 0
  site {                                // depth 1
    products {                          // depth 2
      edges {                           // depth 3
        node {                          // depth 4
          entityId                      // depth 5
          variants {                    // depth 5
            edges {                     // depth 6
              node {                    // depth 7
                entityId                // depth 8
                options {               // depth 8
                  edges {               // depth 9
                    node {              // depth 10
                      entityId          // depth 11
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
Example query with depth of six
query {                                 // depth 0
  site {                                // depth 1
    categoryTree {                      // depth 2
      ...CategoryFields                 // depth 3
      children {                        // depth 3  
        ...CategoryFields               // depth 4
        children {                      // depth 4
          ...CategoryFields             // depth 5
        }
      }
    }
  }
}
 
fragment CategoryFields on CategoryTreeItem {
  name
}

Platform limitations

BigCommerce has limits on certain portions of the platform.

PlatformLimits
Maximum banners per query50
Maximum products per query50

FAQ:

Querying for channels other than Stencil storefronts and querying from external systems

If you wish to use the GraphQL Storefront API from an external system, there are a few considerations.

  • Which channel do you wish to run requests in the context of?
  • Are you running requests from a server or a front-end application?
  • If you are running requests from a front-end application, do you need to show customer-specific information, or only anonymous information?
  • If you are running requests from a server, do you need the ability to support customer login?

As a best practice, you should create tokens that expire and rotate them regularly before their expiry. However, you are also permitted to create long-lived tokens.

Can I hide the display of a field, such as the product's price, on the storefront by toggling the setting in the control panel?

You can toggle off the show_product_price field in the control panel to prevent the display in GraphQL. The prices field returns null in the GraphQL response.

I want to run requests in the context of the store's default channel (channel ID 1)

There are two public URLs you can use to run requests:

  • The storefront's vanity URL; for example, https://example.com/graphql
  • The store's permanent URL; for example, https://store-STOREHASH.mybigcommerce.com/graphql

I want to run requests in the context of another channel

Use the channel's permanent URL in the following form: https://store-STOREHASH-CHANNELID.mybigcommerce.com/graphql.

For example, if your store hash is abc123 and your channel ID is 456, the channel's permanent URL is https://store-abc123-456.mybigcommerce.com/graphql.

For a channel's permanent URL to respond to requests, you must first create a site for the channel.

When you create a GraphQL Storefront API token, include the channel ID of the channel on which you wish to use the token. Otherwise, the server will reject your requests. See this article's section on Creating a token.

I want to run requests from a front-end application or browser. I only show anonymous information, or I do not support signing in as a customer

Use a normal GraphQL Storefront API token. You can use an anonymous fetch or XHR mode that does not send cookies along with the request. When creating your token, specify the origin from which your requests will be run in order to specify this as an allowed origin for CORS (opens in a new tab).

I want to run requests from a server, and I don't need customer impersonation abilities

Use normal GraphQL Storefront API tokens. According to the Principle of least privilege (opens in a new tab), you should not create a token that has permissions you do not need.

I want to run requests from a server, and I need to support customer login

Use a Customer Impersonation token and store it securely on your server like other secrets. When you need to run requests in the context of a particular customer (for example, if they've logged in to your application), send their BigCommerce Customer ID along with the request as the x-bc-customer-id header.

I want a list of GraphQL error messages

For a list of GraphQL error messages, see API Status Codes.

Related resources

Tools

Did you find what you were looking for?