> ## Documentation Index
> Fetch the complete documentation index at: https://docs.glood.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Recommendations API

> Complete reference for useRecommendations, the standalone headless functions, and the RecommendationsApp methods

# Recommendations API

Reference for fetching recommendation sections and sending attribution events. For a guided walkthrough, see [Loading Recommendations](/for-developers/glood-hydrogen-sdk/recommendations).

## useRecommendations()

React hook that fetches recommendation sections for the current page. Must be used within a `<GloodProvider>` whose client has the recommendations app registered.

### Signature

```typescript theme={null}
function useRecommendations(
  params: GetSectionsParams,
  options?: UseRecommendationsOptions
): UseRecommendationsResult
```

### Parameters

`params` is a [`GetSectionsParams`](/for-developers/glood-hydrogen-sdk/api-reference/signatures#getsectionsparams) — `pageType` is required; `pageUrl`, `locale`, and `clientId` default to browser values in the browser. `options` accepts a single `skip?: boolean` (default `false`) to hold fetching until required params are ready.

### Returns — UseRecommendationsResult

| Attribute        | Type                            | Description                                                                        |
| ---------------- | ------------------------------- | ---------------------------------------------------------------------------------- |
| `sections`       | `RecommendationSection[]`       | Sections with full product data. Empty array while loading or when none configured |
| `data`           | `SectionsResponse \| null`      | Full API response (`request_id`, `experience`, `visit_id`, `config`, ...)          |
| `loading`        | `boolean`                       | `true` while the request is in flight                                              |
| `error`          | `Error \| null`                 | `GloodApiError` on API failures, `Error` on setup problems                         |
| `refetch`        | `() => void`                    | Re-run the request with the same params                                            |
| `trackRender`    | `(track: SectionTrack) => void` | Send a `glood:section:render` attribution event                                    |
| `trackView`      | `(track: SectionTrack) => void` | Send a `glood:section:view` attribution event                                      |
| `trackClick`     | `(track: SectionTrack) => void` | Send a `glood:section:click` attribution event                                     |
| `trackAddToCart` | `(track: SectionTrack) => void` | Send a `glood:section:add_to_cart` attribution event                               |

### Basic Usage

```tsx theme={null}
import { useRecommendations } from '@glood/hydrogen';

const { sections, loading, error } = useRecommendations({
  pageType: 'product_page',
  productId: '8977367564515',
});
```

### With All Options

```tsx theme={null}
const { sections, data, loading, error, refetch, trackClick } =
  useRecommendations(
    {
      pageType: 'cart',
      cartProductIds: ['8977367564515', '9311227838783'],
      cartValue: '199.00',
      currency: 'USD',
      customerId: '7412356789',
      sections: [218966], // only this section
    },
    { skip: false },
  );
```

## Standalone Functions

Isomorphic functions for the v2/v3 headless suite. Use them in Hydrogen route loaders (SSR) or anywhere you need the API without a React component. Every function takes `options: HeadlessRequestOptions` as its first argument.

### Endpoints

Each function POSTs to a path under the client's main endpoint (default `https://storefront.glood.ai`), versioned by `options.version` (default `3`):

| Function                        | Method + Path                                                | Version             |
| ------------------------------- | ------------------------------------------------------------ | ------------------- |
| `fetchHeadlessInit`             | `POST /api/storefront/v3/headless/init`                      | v3 only             |
| `fetchRecommendationSections`   | `POST /api/storefront/v3/headless/sections`                  | v3 only             |
| `sendHeadlessEvent`             | `POST /api/storefront/v3/headless/events`                    | v3 only             |
| `fetchRecommendations`          | `POST /api/storefront/v{version}/headless/recommendations`   | v2 or v3 (dispatch) |
| `fetchV3Recommendations`        | `POST /api/storefront/v3/headless/recommendations`           | v3                  |
| `fetchV2Recommendations`        | `POST /api/storefront/v2/headless/recommendations`           | v2                  |
| `fetchAutomaticRecommendations` | `POST /api/storefront/v3/headless/recommendations/automatic` | v3 only             |
| `fetchTopRecommendations`       | `POST /api/storefront/v3/headless/recommendations/top`       | v3 only             |

<Note>
  v3-only functions throw if `options.version` is explicitly `2` (they will not silently upgrade). v3 requests send `Authorization: Bearer <apiKey>` + `x-shop`; v2 authenticates by the `x-shop` header alone (no bearer token).
</Note>

### HeadlessRequestOptions

The first argument to every standalone function — `apiKey` (required for v3) and `myShopifyDomain` are required; `endpoint`, `version` (default `3`), and `debug` are optional. See the full field table in [Signatures → HeadlessRequestOptions](/for-developers/glood-hydrogen-sdk/api-reference/signatures#headlessrequestoptions).

### fetchRecommendationSections()

Fetch recommendation sections with full product data (v3). Works server-side and in the browser; the `useRecommendations` hook uses this internally.

```typescript theme={null}
async function fetchRecommendationSections(
  options: HeadlessRequestOptions,
  params: GetSectionsParams
): Promise<SectionsResponse>
```

The second argument is the same [`GetSectionsParams`](#parameters--getsectionsparams) as the hook, except `pageUrl` and `locale` are **required outside the browser** (there are no defaults on the server).

```typescript theme={null}
import { fetchRecommendationSections } from '@glood/hydrogen';

export async function loader({ request, params, context }) {
  const recommendations = await fetchRecommendationSections(
    {
      apiKey: context.env.GLOOD_API_KEY,
      myShopifyDomain: 'your-store.myshopify.com',
    },
    {
      pageType: 'product_page',
      pageUrl: request.url,
      locale: 'en-US',
      productId: params.productId,
    },
  ).catch(() => null);

  return { recommendations };
}
```

### fetchHeadlessInit()

Bootstrap a headless session (v3 only): server-issued `visit_id`/`user_id`, visitor history, shop `config` and storefront `token`. In the browser, `clientId` and `pageUrl` default from the cookie/`window`. `GloodProvider` calls this automatically on mount — use it directly only for custom bootstrapping.

```typescript theme={null}
async function fetchHeadlessInit(
  options: HeadlessRequestOptions,
  params?: InitParams
): Promise<InitResponse>
```

`InitParams`: `userId?`, `clientId?`, `customerId?`, `pageType?`, `pageUrl?` — all optional.

### sendHeadlessEvent()

Send a single interaction event to the events ingestion endpoint (v3 only). In the browser, `channel` (`'hydrogen'`), `sessionId` and `clientId` are filled in when omitted; the server requires `session_id` and one of `client_id`/`user_id`.

```typescript theme={null}
async function sendHeadlessEvent(
  options: HeadlessRequestOptions,
  params: HeadlessEventParams
): Promise<HeadlessEventResponse>
```

`HeadlessEventParams` centers on the `event` object (`{ id, name, type: 'standard' | 'custom', timestamp, data? | customData? }`) plus optional `channel`, `sessionId`, `clientId`, `userId`, `customerId`, `experience`, `pageType`, `pageUrl`. Any extra fields (`cart`, `customer`, `customer_privacy`, ...) pass through in the API's snake\_case wire format. Returns `{ ok: boolean, ... }`.

<Warning>
  `event.timestamp` must be an ISO 8601 string within ±2 days of now (server rule).
</Warning>

### fetchRecommendations()

Version-aware dispatch: routes to v2 or v3 by `options.version` (default `3`). Prefer `fetchV2Recommendations` / `fetchV3Recommendations` when you want the concrete return type without narrowing.

```typescript theme={null}
async function fetchRecommendations(
  options: HeadlessRequestOptions,
  params: RecommendationsParams
): Promise<RecommendationsResponse | V2RecommendationsResponse>
```

### fetchV3Recommendations()

Multi-query, anchor-based recommendations (v3). Each query in `params.queries` is a `RecommendationQuery` (`{ id, recommendationType, productIds, view, maxRecommendations?, creationType? }`, up to 10 anchor product ids per query). Results are keyed by each query's `id`.

```typescript theme={null}
async function fetchV3Recommendations(
  options: HeadlessRequestOptions,
  params: RecommendationsParams
): Promise<RecommendationsResponse>
```

`RecommendationsParams`: `queries: RecommendationQuery[]`, plus optional `clientId`, `userId`, `customerId`.

### fetchV2Recommendations()

Multi-query similar-products recommendations (v2 — shop-header auth only, no bearer token).

```typescript theme={null}
async function fetchV2Recommendations(
  options: HeadlessRequestOptions,
  params: V2RecommendationsParams
): Promise<V2RecommendationsResponse>
```

`V2RecommendationsParams`: `{ queries: RecommendationQuery[] }`. Response data is keyed by query id: `{ serve_id, products }`.

### fetchAutomaticRecommendations()

Single-anchor, cursor-paginated similar-products recommendations (v3 only).

```typescript theme={null}
async function fetchAutomaticRecommendations(
  options: HeadlessRequestOptions,
  params: AutomaticRecommendationsParams
): Promise<AutomaticRecommendationsResponse>
```

`AutomaticRecommendationsParams`: `productIds: number[]`, `view: RecommendationView`, optional `recommendationType` (only `'similar_products'`), `maxRecommendations`, `filter`, `pagination: { cursor?, limit? }`. Returns `{ status, serve_id, pagination: { cursor, hasMore? }, products }`.

### fetchTopRecommendations()

Anchorless, strategy-ranked, faceted catalog recommendations (v3 only).

```typescript theme={null}
async function fetchTopRecommendations(
  options: HeadlessRequestOptions,
  params: TopRecommendationsParams
): Promise<TopRecommendationsResponse>
```

`TopRecommendationsParams`: `strategy: 'BESTSELLERS' | 'NEW_ARRIVALS'` (uppercase), `view: RecommendationView`, optional `strategyOptions: { salesTimePeriod?: 7 | 15 | 30, bestsellerMetric? }`, `query` (full-text catalog search), `filter`, `facets: TopFacet[]` (`'vendor' | 'product_type' | 'tag' | 'price'`), `pagination`. Returns `{ status, serve_id, strategy, pagination, products, facets? }`.

### runHeadlessInit()

Session-bootstrap helper used internally by `GloodProvider`: runs `fetchHeadlessInit` from a `GloodClient`, persisting/replaying the visitor id cookies. No-op (resolves `null`) for v2 clients.

```typescript theme={null}
async function runHeadlessInit(
  client: GloodClient
): Promise<InitResponse | null>
```

### headlessRequest()

Low-level POST primitive. Builds `${endpoint}/api/storefront/v{version}/headless/{resource}`, applies the per-version auth headers, and throws `GloodApiError` on a non-2xx response. The higher-level functions above are built on it.

```typescript theme={null}
async function headlessRequest<T>(
  resource: string,
  body: Record<string, any>,
  options: HeadlessRequestOptions
): Promise<T>
```

### Errors — GloodApiError

Thrown by every standalone function on any non-2xx response:

```typescript theme={null}
class GloodApiError extends Error {
  /** HTTP status code, e.g. 401 */
  readonly status: number;

  /** Parsed JSON error body, e.g. { error: 'Invalid authentication' } */
  readonly body: unknown;
}
```

```typescript theme={null}
import { GloodApiError } from '@glood/hydrogen';

try {
  await fetchRecommendationSections(options, params);
} catch (error) {
  if (error instanceof GloodApiError && error.status === 401) {
    // Invalid or mismatched API key
  }
}
```

## RecommendationsApp

The app instance registered via `client.use(recommendations())`. Retrieve it from the client for advanced usage:

```typescript theme={null}
import { RecommendationsApp } from '@glood/hydrogen';

const app = client.getApp('recommendations') as RecommendationsApp;
```

### Methods

Alongside `getSections`, the app exposes `getInit`, `getRecommendations`,
`getAutomaticRecommendations`, `getTopRecommendations`, `sendEvent`, and the
`trackRender` / `trackView` / `trackClick` / `trackAddToCart` attribution
helpers. See the full method list with signatures in
[App Modules → RecommendationsApp Methods](/for-developers/glood-hydrogen-sdk/api-reference/app-modules#recommendationsapp-methods).

```typescript theme={null}
const data = await app.getSections({ pageType: 'home' });

app.trackClick({
  section: '218966',
  sectionServeId: data.sections[0].section_serve_id,
  products: [{ productId: '9311227838783' }],
});
```

<Note>
  Attribution events respect the app's pixel configuration: if `pixel.enabled` is `false`, they are not sent.
</Note>

## SectionTrack Object

Links an attribution event to the exact section render it came from. Pass `sectionServeId` (the `section_serve_id` from the sections response) to tie the event to a specific render. See the full field table in [Signatures → SectionTrack](/for-developers/glood-hydrogen-sdk/api-reference/signatures#sectiontrack).

```typescript theme={null}
const track: SectionTrack = {
  section: '218966',
  sectionServeId: '56a98d2d-a014-4dd7-ab2d-1a5191b84262',
  requestId: '671778ec-8382-4d9e-9671-fb91daccf049',
  page: 'product_page',
  parent: { productId: '8977367564515' },
  products: [
    { productId: '9311227838783', variantId: '48792371233087', quantity: 1 },
  ],
};
```

## Response Shape — SectionsResponse

```typescript theme={null}
interface SectionsResponse {
  /** Unique id for this request — pass to attribution events */
  request_id: string;

  /** Sections with full product data */
  sections: RecommendationSection[];

  /** Current product details (product pages), or null */
  product: Record<string, any> | null;

  /** Shopify storefront access token from the shop config */
  token: string | null;

  /** Shop configuration (currency, money format, integrations, ...) */
  config: Record<string, any>;

  /** Assigned A/B experience id — persisted to localStorage automatically */
  experience: string | null;

  /** Unique id for this visit */
  visit_id: string | null;
}
```

See [TypeScript Types](/for-developers/glood-hydrogen-sdk/api-reference/types#recommendations-api-types) for the full `RecommendationSection` and `SectionProduct` definitions.

### Example Response

```json theme={null}
{
  "request_id": "671778ec-8382-4d9e-9671-fb91daccf049",
  "sections": [
    {
      "id": 218966,
      "section_serve_id": "56a98d2d-a014-4dd7-ab2d-1a5191b84262",
      "page_type": "home",
      "experience_id": 27647,
      "layout": "horizontal_grid",
      "location": "MainContent",
      "type": "bestsellers",
      "position": 3,
      "title": "Bestsellers",
      "extra": {},
      "discount_config": { "enabled": false },
      "show_discount_label": false,
      "translations": {},
      "products": [
        {
          "product_id": 9311227838783,
          "title": "The Collection Snowboard: Oxygen",
          "handle": "the-collection-snowboard-oxygen",
          "vendor": "Hydrogen Vendor",
          "product_type": "snowboard",
          "tags": "Premium, Snow",
          "price": 1025,
          "compare_at_price": null,
          "image": { "url": "https://cdn.shopify.com/..." },
          "options": [
            { "id": 1, "name": "Title", "values": ["Default Title"], "position": 1 }
          ],
          "variants": [
            {
              "variant_id": 48792371233087,
              "title": "Default Title",
              "price": 1025,
              "compare_at_price": null,
              "sku": "",
              "selected_options": [{ "name": "Title", "value": "Default Title" }]
            }
          ],
          "metafields": []
        }
      ],
      "cursor": null,
      "hasMore": false
    }
  ],
  "product": null,
  "token": "shpat_...",
  "config": { "shop": { "currency": "USD", "money_format": "${{amount}}" } },
  "experience": "27647",
  "visit_id": "fc300769-ea40-43d9-8bf3-6b721913fea8"
}
```

## See Also

* [Loading Recommendations Guide](/for-developers/glood-hydrogen-sdk/recommendations) - Walkthrough with rendering patterns
* [Recommendations Example](/for-developers/glood-hydrogen-sdk/examples/recommendations) - Complete working page
* [TypeScript Types](/for-developers/glood-hydrogen-sdk/api-reference/types) - All type definitions
* [Event System](/for-developers/glood-hydrogen-sdk/api-reference/event-system) - How attribution events are transmitted
