---
updatedAt: 2026-09-07T11:12:40.000Z
agentTools:
  projectIndex: https://docs.nacelle.com/llms.txt
---

# Version 1.x

## Adding to a project

### Install

Begin by installing the Storefront SDK in your Node.js project:

```
npm i @nacelle/storefront-sdk
```

### Get credentials from the Nacelle Dashboard

Retrieve the **Storefront Endpoint**  and **Public Storefront Token** from the Nacelle Dashboard:

[block:image]
{
  "images": [
    {
      "image": [
        "https://files.readme.io/32833f0-nacelle_dashboard_storefront_api_credentials_sans_key_create_credentials_copy_highlight.png",
        "nacelle dashboard storefront api credentials sans key create credentials copy highlight.png",
        "A screenshot from the Nacelle Dashboard's Space Settings > API Details page. The Storefront API section contains fields for \"Storefront Endpoint\" and \"Public Storefront Token.\" Each of these fields has a copy button on the right side of the field. Clicking this button copies the value of the field."
      ],
      "align": "center",
      "caption": "The **Storefront Endpoint**  and **Public Storefront Token** can be copied with a press of a button."
    }
  ]
}
[/block]

### Initialize the SDK

Import the SDK and initialize it with your Storefront Endpoint and Public Storefront Token from the Nacelle Dashboard.

```typescript
import Storefront from '@nacelle/storefront-sdk';

const client = Storefront({
  storefrontEndpoint: '<your-storefront-endpoint>',
  token: '<your-public-storefront-token>',
  locale: 'en-US', // Optional, defaults to 'en-US'
  currencyCode: 'USD' // Optional, defaults to 'USD'
});
```

## Querying Data

### Products

The `products` method accepts an object with the following properties to define the options of the query:

* **nacelleEntryIds** - (`string[]`, Optional) An array of `product.nacelleEntryId`s, which are unique IDs assigned to products by Nacelle.

* **handles** - (`string[]`, Optional) An array of product handles.

* **locale** - (`string`, Optional, default: `'en-US'`) An IETF locale.

* **maxReturnedEntries** - (`Number`, Optional) Sets an upper limit on the number of returned products.

* **edgesToNodes** - (`boolean`, Optional, default: `true`) Sets whether the method returns `Product` objects or `ProductEdge` objects. When `false`, `ProductEdge` objects are returned. `ProductEdge`s have a `cursor` and `node`. The `cursor` value can be used for paginating; the `node` contains the product data.

* **cursor** - (`string`, Optional) Returned entries will come after this cursor value.

* **startAfterEntryId** - (`string`, Optional) Returned entries will come after this specified ID. Uses deprecated `products` Storefront API query. If you need to paginate requests, it is recommended to use the `cursor` values returned when `edgesToNodes` is `false`.

* **advancedOptions** - (`object`, Optional)
  * **entriesPerPage** - (`number`, Optional) The SDK is configured to automatically request entries in batches. The number of entries it will attempt to request at a time can be optionally tuned using this parameter.

#### Products examples

```typescript
// Get all products in a space
await client.products();

// Get the first 5 products.
await client.products({
  maxReturnedEntries: 5
});

// Get products by handles.
await client.products({
  handles: ['product-1', 'product-2']
});

// Get products after a specified ID.
await client.products({
  startAfterEntryId: 'someNacelleEntryId'
});

// Using cursors to manually retrieve paginated results
const batchOne = await client.products({
  maxReturnedEntries: 5,
  edgesToNodes: false
});

const batchTwo = await client.products({
  maxReturnedEntries: 5,
  edgesToNodes: false,
  cursor: batchOne.at(-1).cursor
});

// When using Typescript
const [firstProductEdge] = await client.products({
  maxReturnedEntries: 5,
  edgesToNodes: false
});
const { cursor, edge } = firstProductEdge as ProductEdge;
const { naceleEntryId } = edge;

const [firstProduct] = await client.products({ maxReturnedEntries: 5 });
const { nacelleEntryId } = firstProduct as Product;
```

### Product collections

The `productCollections` method accepts an object with the following properties to define the options of the query

* **nacelleEntryIds** - (`string[]`, Optional) An array of `productCollection.nacelleEntryId`s, which are unique IDs assigned to product collections by Nacelle.

* **handles** - (`string[]`, Optional) An array of product collection handles.

* **locale** - (`string`, Optional, default: `'en-US'`) An IETF locale.

* **maxReturnedEntries** - (`number`, Optional) Sets an upper limit on the number of returned collections.

* **edgesToNodes** - (`boolean`, Optional, default: `true`) Sets whether the method returns `ProductCollection` objects or `ProductCollectionEdge` objects. When `false`, `ProductCollectionEdge` objects are returned. `ProductCollectionEdge`s have a `cursor` and `node`. The `cursor` value can be used for paginating; the `node` contains the collection data.

* **cursor** - (`string`, Optional) Returned entries will come after this cursor value.

* **startAfterEntryId** - (`string`, Optional) Returned entries will come after this specified ID. Uses deprecated `productCollections` Storefront API query. If you need to paginate requests, it is recommended to use the`cursor` values returned when `edgesToNodes` is `false`.

* **maxReturnedEntriesPerCollection** - (`number`, Optional) The number of products to be queried for each collection returned

* **advancedOptions** - (`object`, Optional)
  * **entriesPerPage** - (`number`, Optional) The SDK is configured to automatically request entries in batches. The number of entries it will attempt to request at a time can be optionally tuned using this parameter.

#### Product collections examples

```typescript
// Get the first 5 product collections.
await client.productCollections({
  maxReturnedEntries: 5
});

// Get product collections by handles.
await client.productCollections({
  handles: ['collection-1', 'collection-2']
});

// Get product collections after a specified ID.
await client.productCollections({
  startAfterEntryId: 'someNacelleEntryId'
});

// Get the first 50 products for each collection
await client.productCollections({
  maxReturnedEntriesPerCollection: 50
})

// How to access products on a collection
const collections = await client.collections();
const { products, productConnection } = collections[0];

const { nacelleEntryId } = products[0]; // An array of type `Product`

const { pageInfo, edges } = productConnection;
const { cursor, node } = edges[0];
const { nacelleEntryId } = node;
```

### Product collection entries

The `productCollectionEntries` method accepts an object with the following properties to define the options of the query:

* **collectionEntryId** - (`string`, Optional) The nacelleEntryId for the collection's products you want to query. Either collectionEntryId or handle is required.

* **handle** - (`string[]`, Optional) The handle of the collection's products you want to query.

* **locale** - (`string`, Optional, default: `'en-US'`) An IETF locale.

* **maxReturnedEntries** - (`number`, Optional) Sets an upper limit on the number of returned products.

* **edgesToNodes** - (`boolean`, Optional, default: `true`) Sets whether the method returns `Product` objects or `ProductEdge` objects. When `false`, `ProductEdge` objects are returned. `ProductEdge`s have a `cursor` and `node`. The `cursor` value can be used for paginating; the `node` contains the product data.

* **cursor** - (`string`, Optional) Returned entries will come after this cursor value.

* **startAfterEntryId** - (`string`, Optional) Returned entries will come after this specified ID. Uses deprecated `productCollections` Storefront API query. If you need to paginate requests, it is recommended to use the `cursor` values returned when `edgesToNodes` is `false`.

* **advancedOptions** - (`object`, Optional)
  * **entriesPerPage** - (`number`, Optional) The SDK is configured to automatically request entries in batches. The number of entries it will attempt to request at a time can be optionally tuned using this parameter.

#### Product collection entries examples

```typescript
// Get all the products belonging to a collection with handle 'shoes'
await client.productCollectionEntries({
  handle: 'shoes',
  maxReturnedEntries: -1
});

// Get first 20 products belonging to a collection with handle 'hats'
await client.productCollectionEntries({
  handle: 'hats',
  maxReturnedEntries: 20
})
```

### Content

The content method accepts an object with the following properties to define the options of the query:

* **nacelleEntryIds** - (`string[]`, Optional) An array of `content.nacelleEntryId`s, which are unique IDs assigned to individual content entries by Nacelle.

* **handles** - (`string[]`, Optional) An array of content handles.

* **locale** - (`string`, Optional, default: `'en-US'`) An IETF locale.

* **maxReturnedEntries** - (`number`, Optional) Sets an upper limit on the number of returned content entries.

* **edgesToNodes** - (`boolean`, Optional, default: `true`) Sets whether the method returns `Content` objects or `ContentEdge` objects. When `false`, `ContentEdge` objects are returned. `ContentEdge`s have a `cursor` and `node`. The `cursor` value can be used for paginating; the `node` contains the content data.

* **entryDepth** - (`number`, Optional) Sets the maximum level of content resolution depth in `content.fields`. For more details, see [Content Resolution](/docs/storefront-graphql-api-stable#content-resolution).

* **cursor** - (`string`, Optional) Returned entries will come after this cursor value.

* **startAfterEntryId** - (`string`, Optional) Returned entries will come after this specified ID. Uses deprecated content Storefront API query. If you need to paginate requests, it is recommended to use the `cursor` values returned when `edgesToNodes` is `false`.

* **type** - (`string`, Optional) Allows for querying by content type

* **advancedOptions** - (`object`, Optional)
  * **entriesPerPage** - (`number`, Optional) The SDK is configured to automatically request entries in batches. The number of entries it will attempt to request at a time can be optionally tuned using this parameter.

#### Content examples

```typescript
// Get the first 5 content entries.
await client.content({
  maxReturnedEntries: 5
});

// Get content by handles.
await client.content({
  handles: ['content-1', 'content-2']
});

// Get only articles
await client.content({ type: 'article' })
```

### Navigation

The `navigation` method returns [Navigation](/docs/navigation) data. It has no required parameters. It accepts an optional `params` object with the following properties:

* **groupId** - (`string`, Optional) The group ID is assigned to a navigation group in the Nacelle Dashboard.

#### Navigation examples

```typescript
// Get all Navigation Groups
await client.navigation();

// Get a single Navigation Group
await client.navigation({
  groupId: 'footer'
});
```

### Space properties

The `spaceProperties` method returns [Space Properties](/docs/spaces#space-properties) data. It's called without any parameters.

```typescript
// Get all Space Properties
await client.spaceProperties();
```

### Custom GraphQL query

The `query` method submits GraphQL requests to the [Nacelle Storefront GraphQL API](/docs/storefront-graphql-api-stable). It accepts an object with the following properties:

* **query** - (`string`, Required) A GraphQL [query](https://graphql.org/learn/queries).
* **variables** - (`string`, Optional) Stingified object containing any GraphQL variables used in the query.

### Custom Graphql query example

```typescript
// Get product handles from the 'collection-1' collection
const query = `
  query ProductHandles($filter: ProductCollectionFilterInput) {
    allProductCollections(filter: $filter) {
      edges {
        node {
          productConnection {
            edges {
              node {
                content {
                  handle
                }
              }
            }
          }
        }
      }
    }
  }
`;

const variables = JSON.stringify({
  filter: {
    handles: 'collection-1'
  }
});

await client.query({
  query,
  variables
});
```

### Transforming the responses of SDK methods

The Storefront SDK offers an `after`  method that lets you run arbitrary transformations or side-effects when other Storefront SDK methods are called. The `after` method is very flexible and can be a practical tool for accommodating edge cases.

The `after` method accepts two positional arguments, `method` and `callback`:

* **method** - (`string`, Required) The target method that the provided `callback` should be applied to.
* **callback** - (`function`, Required) The callback function that should run after the `method`. The callback function has the following characteristics:
  * It takes the return value of `method` as input.
  * It should return either the unaltered input or a transformed version of the input. Failure to return a value from the callback will result in the `method` returning `undefined`.
  * It can be either synchronous or asynchronous.

#### After examples

```typescript
// Example 1: Capitalizing the `product.title` of all product data returned by the `products` method

const capitalizeTitle = (words) =>
  words
    .split(' ')
    .map((word) => `${word.charAt(0).toUpperCase()}${word.slice(1)}`)
    .join(' ');

client.after('products', (products) =>
  // return a transformed version of the `products` data
  products.map((product) => ({
    ...product,
    title: capitalizeTitle(product.title)
  }))
);

await client.products(); // returns `products` with capitalized `product.title`s

// Example 2: Performing asynchronous side effects when the `content` method is called

client.after('content', async (contentEntries) => {
  const contentIds = contentEntries.map((entry) => entry.nacelleEntryId);

  // Register an event with a third-party service
  await observabilityClient.addEvent({
    type: 'content data requested',
    data: contentIds
  });

  return contentEntries; // Because we aren't transforming the data, we can return the
  // original `contentEntries` fetched by the `content` method
});

await client.content({ type: 'teamBio' }); // reports an event with the `observabilityClient`
```

### Preview mode

Preview mode can be activated in the SDK either globally or on-the-fly. To learn more, check out the [Preview Mode](/docs/preview-data#storefront-sdk) docs.

## Troubleshooting

* Syntax errors may indicate that the arguments provided to a Storefront SDK method are not correctly structured. Ensure arguments are provided in an object with the properties listed in this document.

* A `Variable "$filter" got invalid value` error occurs when the wrong data type is provided in the arguments of an SDK method. Make sure the values match the expected types described in this document.