Storefront API Access

Introduction

Nimstrata's Storefront API allows merchants with composable commerce solutions to send events, retrieve search results and recommendations, and request autocomplete suggestions.

Hydrogen, Oxygen, and other custom headless storefront solutions can call Nimstrata and Shopify APIs directly.

📖 Nimstrata's Storefront API Documentation
https://storefront.retailconnect.app/docs
📖 Shopify's Storefront API Documentation
https://shopify.dev/docs/api/storefront


Theme Installation API Access Card

The Theme Installation page includes an API Access card with a live Search API example for the connected Shopify store.

The card shows:

  • The current Storefront API search endpoint: POST https://storefront.retailconnect.app/v1/search
  • A sample request using the store's connected Google Cloud project ID
  • The default search placement: projects/{projectId}/locations/global/catalogs/default_catalog/servingConfigs/default_search
  • A Try it out panel that sends a test search through the app

If the Google Cloud project ID is missing, set it from the Google Cloud page first.


Rate Limits

Shopify and Nimstrata's Storefront APIs handle businesses ranging from tens to millions of SKUs, so there are no explicit rate limits on the number of requests that can be sent. However, various malicious traffic prevention systems are in place and requests may receive 430 Shopify Security Rejection or 429 Too Many Requests error codes.

To avoid rate limiting, the solution should use the correct buyer IP header when calling Shopify's Storefront API. Nimstrata's Storefront API uses the shopper's IP address.


Endpoints

User Events

https://storefront.retailconnect.app/v1/event

When merchants send User Events to Nimstrata's Storefront API in addition to or instead of the Retail Cloud Connect App Pixel and App Embed, there are special requirements for search events. This is a common use case for faster AI model training or for using the Experiments tab in the Google Cloud Console for additional A/B test data.

Because AI Commerce Search uses a single API to serve search and browse events, browse events are technically search events without a search query. However, requests must send at least one page category and filter to be processed correctly. See the examples below.

System attributes and custom attributes used for filtering results should be sent to improve dynamic facet training.

User Event Examples

{
  "projectName": "your-gcp-project-name",
  "userEvent": {
    "eventType": "search",
    "visitorId": "00000000-0000-0000-0000-000000000000", // rcc-visitor-id cookie value
    "searchQuery": "search term",
    "offset": 0, // Used for pagination
    "filter": [
      {
        "field": "attributes.custom_filter",
        "value": ["Filter Value"],
        "type": "string"
      }
    ],
    "productDetails": [
      // Send all products, example shortened for brevity
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } }
    ],
    "userInfo": {
      "userAgent": "User Agent",
      "userId": "00000" // Shopify Customer ID if Logged In
    },
    "experimentIds": ["CONTROL"]
  }
}
{
  "projectName": "your-gcp-project-name",
  "userEvent": {
    "eventType": "search",
    "visitorId": "00000000-0000-0000-0000-000000000000", // rcc-visitor-id cookie value
    "searchQuery": "",
    "offset": 0, // Used for pagination
    "filter": [
      { "field": "attributes.rcc_collection_id", "value": ["123456789012"] }, // attributes.rcc_collection_id or Shopify Collection ID
      {
        "field": "attributes.custom_filter",
        "value": ["Filter Value"],
        "type": "string"
      }
    ],
    "pageCategories": ["123456789012"], // attributes.rcc_collection_id or Shopify Collection ID
    "productDetails": [
      // Send all products, example shortened for brevity
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } },
      { "product": { "id": "1234567890123" } }
    ],
    "userInfo": {
      "userAgent": "User Agent",
      "userId": "00000" // Shopify Customer ID if Logged In
    },
    "experimentIds": ["CONTROL"]
  }
}
function createUUID() {
  const s = [];
  const hexDigits = '0123456789abcdef';
  for (let i = 0; i < 36; i++) {
    s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
  }
  s[14] = '4';
  s[19] = hexDigits.substr((s[19].charCodeAt(0) & 0x3) | 0x8, 1);
  s[8] = s[13] = s[18] = s[23] = '-';
  return s.join('');
}

async function _getVisitorId(browser) {
  let ID = await browser.cookie.get('rcc-visitor-id');

  if (ID) return ID;

  ID = createUUID();
  browser.cookie.set('rcc-visitor-id', ID);

  return ID;
}