# storefront

Executes queries against Shopify's Storefront GraphQL API. Works the same way as the `graphql` tag, but targets the Storefront API instead of the Admin API. The response is stored in a variable for further processing.

The Storefront API provides access to public store data — products, collections, cart operations, and more — without requiring admin-level permissions.

```liquid
{% storefront query: my_query, variables: my_variables as result %}

{% if result.product %}
  {% log result.product.title %}
{% endif %}
```

#### Syntax

```liquid
{% storefront query: query_string, variables: variables_object as result_variable %}
```

#### Parameters

| Parameter   | Required | Description                                           |
| ----------- | -------- | ----------------------------------------------------- |
| `query`     | Yes      | Storefront GraphQL query string                       |
| `variables` | No       | Object containing variables for the GraphQL operation |

#### Result Object

The result contains the returned data directly accessible at the top level. Query fields are available as properties on the result variable.

If errors occur, they are available in the `errors` property:

| Property | Type       | Description                                    |
| -------- | ---------- | ---------------------------------------------- |
| `errors` | array/null | Array of error objects if the operation failed |

#### Examples

**Fetch a product by handle:**

```liquid
{% capture query %}
  query getProduct($handle: String!) {
    productByHandle(handle: $handle) {
      id
      title
      description
      priceRange {
        minVariantPrice {
          amount
          currencyCode
        }
      }
    }
  }
{% endcapture %}

{% json variables %}
  {
    "handle": "classic-tee"
  }
{% endjson %}

{% storefront query: query, variables: variables as result %}

{% if result.productByHandle %}
  {% log result.productByHandle.title %}
  {% log result.productByHandle.priceRange.minVariantPrice.amount %}
{% endif %}
```

**List products from a collection:**

```liquid
{% capture query %}
  query getCollection($handle: String!, $first: Int!) {
    collectionByHandle(handle: $handle) {
      title
      products(first: $first) {
        edges {
          node {
            id
            title
            handle
            availableForSale
          }
        }
      }
    }
  }
{% endcapture %}

{% json variables %}
  {
    "handle": "summer-sale",
    "first": 50
  }
{% endjson %}

{% storefront query: query, variables: variables as result %}

{% for edge in result.collectionByHandle.products.edges %}
  {% log edge.node.title | append: " - Available: " | append: edge.node.availableForSale %}
{% endfor %}
```

**Fetch product recommendations:**

```liquid
{% capture query %}
  query getRecommendations($productId: ID!) {
    productRecommendations(productId: $productId) {
      id
      title
      handle
      priceRange {
        minVariantPrice {
          amount
          currencyCode
        }
      }
    }
  }
{% endcapture %}

{% json variables %}
  {
    "productId": "gid://shopify/Product/{{ product_id }}"
  }
{% endjson %}

{% storefront query: query, variables: variables as result %}

{% for product in result.productRecommendations %}
  {% log product.title | append: " ($" | append: product.priceRange.minVariantPrice.amount | append: ")" %}
{% endfor %}
```

**Query with pagination:**

```liquid
{% capture query %}
  query getProducts($cursor: String) {
    products(first: 50, after: $cursor) {
      edges {
        node {
          id
          title
          availableForSale
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
{% endcapture %}

{% assign cursor = null %}
{% assign all_products = "" | split: "" %}

{% for i in (1..100) %}
  {% json variables %}
    {
      "cursor": {{ cursor | json }}
    }
  {% endjson %}

  {% storefront query: query, variables: variables as result %}

  {% for edge in result.products.edges %}
    {% assign all_products = all_products | push: edge.node %}
  {% endfor %}

  {% if result.products.pageInfo.hasNextPage %}
    {% assign cursor = result.products.pageInfo.endCursor %}
  {% else %}
    {% break %}
  {% endif %}
{% endfor %}

{% log "Total products: " | append: all_products.size %}
```

**Handle errors:**

```liquid
{% storefront query: query, variables: variables as result %}

{% if result.errors %}
  {% log "Storefront API error:" %}
  {% for error in result.errors %}
    {% log error.message %}
  {% endfor %}
{% else %}
  {% log result %}
{% endif %}
```

#### Storefront vs Admin API

| Feature   | `storefront`                               | `graphql`                                    |
| --------- | ------------------------------------------ | -------------------------------------------- |
| API       | Storefront GraphQL API                     | Admin GraphQL API                            |
| Access    | Public store data                          | Full admin access                            |
| Products  | Read-only (public fields)                  | Read/write (all fields)                      |
| Orders    | No access                                  | Full access                                  |
| Customers | No access                                  | Full access                                  |
| Cart      | Yes                                        | No                                           |
| Use case  | Public data, recommendations, availability | Data management, mutations, admin operations |

#### Notes

* Consumes 1 credit per operation
* Uses the store's API version configured in DataJet
* Storefront API errors are automatically logged to the script logs
* Variables must be a valid object (use `json` tag to construct complex variables)
* Result properties are accessed directly (e.g., `result.products`, not `result.data.products`)
* Refer to [Shopify's Storefront API documentation](https://shopify.dev/docs/api/storefront) for available queries


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.datajet-app.com/liquid/tags/storefront.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
