> ## 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.

# Send Search Events

> Ingest storefront / personalization events (standard Shopify pixel events and custom `glood:search:*` attribution events). Shop is taken from `x-shop`. Auth: `Authorization: Bearer <gl_sf_...>` + `x-shop`.

<ResponseExample>
  ```json 200 theme={null}
  {
    "ok": true
  }
  ```

  ```json 400 - missing identity theme={null}
  {
    "ok": false,
    "error": "At least one of visitor_id or client_id is required"
  }
  ```

  ```json 400 - validation theme={null}
  {
    "ok": false,
    "error": [
      {
        "message": "\"channel\" must be one of [HYDROGEN, HEADLESS, MOBILE]",
        "path": ["channel"],
        "type": "any.only",
        "context": { "label": "channel", "key": "channel" }
      }
    ]
  }
  ```
</ResponseExample>

## Event payload structure

Every request posts one event in the same envelope. All fields are snake\_case. The full
request body:

```json theme={null}
{
  "channel": "HEADLESS",
  "visitor_id": "gl_s_uid_9f2c",
  "client_id": "c_18a4",
  "customer_id": "7234891234567",
  "session_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "page_type": "search",
  "page_url": "https://your-store.com/search?q=shoe",
  "cart_identifier": "cart-token?key=abc123",
  "cart": { "cost": { "totalAmount": { "amount": 49.99, "currencyCode": "USD" } } },
  "customer": { "id": "7234891234567", "email": "jane@example.com", "phone": "+14155550100" },
  "customer_privacy": {
    "analytics_processing_allowed": true,
    "marketing_allowed": true,
    "preferences_processing_allowed": true,
    "sale_of_data_allowed": false
  },
  "event": {
    "id": "b7f91c2e-1d44-4b50-8888-8dd25736052a",
    "client_id": "c_18a4",
    "name": "<event name>",
    "type": "standard | custom",
    "timestamp": "2026-08-05T10:30:00.000Z",
    "context": {
      "document": {
        "title": "Search",
        "referrer": "https://your-store.com/",
        "character_set": "UTF-8",
        "location": {
          "href": "https://your-store.com/search?q=shoe",
          "pathname": "/search",
          "search": "?q=shoe",
          "hash": "",
          "host": "your-store.com",
          "hostname": "your-store.com",
          "origin": "https://your-store.com",
          "port": "",
          "protocol": "https:"
        }
      },
      "navigator": {
        "user_agent": "Mozilla/5.0 ...",
        "language": "en-US",
        "languages": ["en-US", "en"],
        "cookie_enabled": true
      },
      "window": { "screen": { "width": 1920, "height": 1080 } }
    },
    "data": {},
    "custom_data": {}
  }
}
```

### Top-level fields

| Field              | Type   | Required | Description                                                                                                                                                     |
| ------------------ | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `channel`          | string | ✓        | `HYDROGEN`, `HEADLESS`, or `MOBILE`                                                                                                                             |
| `event`            | object | ✓        | The event envelope (below)                                                                                                                                      |
| `visitor_id`       | string | ✓\*      | Anonymous persistent visitor UID. \*At least one of `visitor_id` / `client_id` is required                                                                      |
| `client_id`        | string | ✓\*      | Client/device id, persists across sessions                                                                                                                      |
| `customer_id`      | string | —        | Shopify customer id when logged in                                                                                                                              |
| `session_id`       | string | —        | Browsing-session id — the unit of funnel and attribution analytics. The server generates a UUID when absent; send a stable one per visit for accurate analytics |
| `page_type`        | string | —        | Page type the event fired from                                                                                                                                  |
| `page_url`         | string | —        | URL the event fired from                                                                                                                                        |
| `cart_identifier`  | string | —        | Cart token/key identifier (`<token>?key=<key>`)                                                                                                                 |
| `cart`             | object | —        | Cart state at event time (Shopify cart shape)                                                                                                                   |
| `customer`         | object | —        | Customer info at event time (`id`, `email`, `phone`)                                                                                                            |
| `customer_privacy` | object | —        | Consent flags: `analytics_processing_allowed`, `marketing_allowed`, `preferences_processing_allowed`, `sale_of_data_allowed` (booleans)                         |

### The `event` object

| Field         | Type   | Required               | Description                                                                            |
| ------------- | ------ | ---------------------- | -------------------------------------------------------------------------------------- |
| `id`          | string | ✓                      | Unique event id (UUID)                                                                 |
| `name`        | string | ✓                      | Event name — a standard Shopify event name or a `glood:` custom event name (see below) |
| `type`        | string | ✓                      | `standard` or `custom`                                                                 |
| `timestamp`   | string | ✓                      | ISO 8601 event time, must be within ±2 days of now                                     |
| `context`     | object | ✓                      | Browser context — see below                                                            |
| `data`        | object | ✓ when `type=standard` | The Shopify standard event payload (may be `{}`)                                       |
| `custom_data` | object | ✓ when `type=custom`   | Must contain a `track` object (see [Glood search events](#glood-search-events))        |
| `client_id`   | string | —                      | Client id carried on the event; defaults from the top-level identity                   |

### The `context` object

All context keys are snake\_case on the wire. Unknown keys are accepted but only the fields
marked as persisted below are stored on the event; anything else is discarded at ingestion.

| Field                                                                                                                                                                                                                                                    | Required | Persisted | Description                                                                                                                                                                                                                                                                                                                                                                                               |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `navigator.user_agent`                                                                                                                                                                                                                                   | ✓        | ✓         | Client user-agent string — browser, OS, and device are derived from it server-side                                                                                                                                                                                                                                                                                                                        |
| `navigator.language`                                                                                                                                                                                                                                     | —        | ✓         | Client language (e.g. `en-US`)                                                                                                                                                                                                                                                                                                                                                                            |
| `navigator.cookie_enabled`                                                                                                                                                                                                                               | —        | ✓         | Whether cookies are enabled                                                                                                                                                                                                                                                                                                                                                                               |
| `navigator.languages`                                                                                                                                                                                                                                    | —        | —         | Accepted, not persisted                                                                                                                                                                                                                                                                                                                                                                                   |
| `document.location`                                                                                                                                                                                                                                      | —        | ✓         | Full URL breakdown — `href`, `pathname`, `search`, `hash`, `host`, `hostname`, `origin`, `port`, `protocol` — persisted as sent. Not validated as required, but always send it: analytics scope page and session funnels by `document.location.pathname` (e.g. a `page_viewed` under `/search` counts toward the search-page funnel). Events without it are accepted but can't be attributed to a surface |
| `document.title`                                                                                                                                                                                                                                         | —        | ✓         | Page title                                                                                                                                                                                                                                                                                                                                                                                                |
| `document.referrer`                                                                                                                                                                                                                                      | —        | ✓         | Referring URL                                                                                                                                                                                                                                                                                                                                                                                             |
| `document.character_set`                                                                                                                                                                                                                                 | —        | ✓         | Document character set (e.g. `UTF-8`)                                                                                                                                                                                                                                                                                                                                                                     |
| `window.screen`                                                                                                                                                                                                                                          | —        | ✓         | Screen dimensions (`width`, `height`)                                                                                                                                                                                                                                                                                                                                                                     |
| `window.inner_width`, `window.inner_height`, `window.outer_width`, `window.outer_height`, `window.page_x_offset`, `window.page_y_offset`, `window.screen_x`, `window.screen_y`, `window.scroll_x`, `window.scroll_y`, `window.location`, `window.origin` | —        | —         | Accepted, not persisted                                                                                                                                                                                                                                                                                                                                                                                   |

<Warning>
  Shopify's web pixel emits context in **camelCase** (`userAgent`, `cookieEnabled`,
  `characterSet`). The headless API is snake\_case: a body sent with `navigator.userAgent` is
  **rejected** with `"navigator.user_agent" is required`, and camelCase fields like
  `characterSet` pass validation but are silently dropped. Convert the pixel context to
  snake\_case before posting.
</Warning>

What changes per event is `event.name`, `event.type`, and where the payload lives:

* **Standard events** — Shopify standard (pixel) events. `type: "standard"`, payload in `event.data`.
* **Glood search events** — custom attribution events emitted by the Glood search app.
  `type: "custom"`, payload in `event.custom_data.track`.

### Standard search events

Any [Shopify standard event](https://shopify.dev/docs/api/web-pixels-api/standard-events)
can be forwarded: `page_viewed`, `product_viewed`, `collection_viewed`, `cart_viewed`,
`search_submitted`, `product_added_to_cart`, `product_removed_from_cart`,
`checkout_started`, `checkout_completed`, and the other checkout events. `event.data`
carries the standard event's payload as defined by Shopify. Some standard events
(`page_viewed`) have an empty `data` by design — their information lives in
`event.context.document`.

```json search_submitted theme={null}
{
  "channel": "HEADLESS",
  "visitor_id": "gl_s_uid_9f2c",
  "event": {
    "id": "b7f91c2e-1d44-4b50-8888-8dd25736052a",
    "name": "search_submitted",
    "type": "standard",
    "timestamp": "2026-08-05T10:30:00.000Z",
    "context": {
      "document": {
        "title": "Search",
        "location": { "href": "https://your-store.com/search?q=shoe", "pathname": "/search", "search": "?q=shoe" }
      },
      "navigator": { "user_agent": "Mozilla/5.0 ..." },
      "window": { "screen": { "width": 1920, "height": 1080 } }
    },
    "data": {
      "searchResult": {
        "query": "shoe"
      }
    }
  }
}
```

### Glood search events

Custom attribution events use `type: "custom"` and carry a `track` object under
`event.custom_data`. All `track` fields are optional; always send `request_id` (from the
search response) when you have it — it ties the interaction back to the serve.

| Field            | Type   | Description                                                                                    |
| ---------------- | ------ | ---------------------------------------------------------------------------------------------- |
| `request_id`     | string | `request_id` from the search response                                                          |
| `search_term`    | string | The search term                                                                                |
| `search_type`    | string | `text` or `image`                                                                              |
| `source`         | string | Where the interaction originated (e.g. `instant`, `search_page`)                               |
| `page_type`      | string | Page type of the interaction                                                                   |
| `products`       | array  | `{ product_id, variant_id?, quantity? }` — products involved                                   |
| `filters`        | array  | `{ key, value }` — filter selections (`value` is an array, or `null` when nothing is selected) |
| `checkout_token` | string | Checkout token, for conversion attribution                                                     |
| `campaign`       | string | Campaign identifier                                                                            |

The examples below show `event.name` and `event.custom_data` — the rest of the envelope is
identical to the one above.

#### glood:search\_result\_rendered

Send when search results are rendered / enter the viewport. `products` lists the rendered
results; include `filters` when the result set was rendered with facets applied:

```json theme={null}
{
  "name": "glood:search_result_rendered",
  "type": "custom",
  "custom_data": {
    "track": {
      "request_id": "req_01j8x2v9",
      "search_term": "shoe",
      "search_type": "text",
      "source": "search_page",
      "page_type": "search",
      "products": [
        { "product_id": "9311227838783" },
        { "product_id": "9311227838784" }
      ],
      "filters": [{ "key": "color", "value": ["red"] }]
    }
  }
}
```

#### glood:search\_result\_clicked

Send when a result is clicked. `products` carries the clicked product; include the filters
active at click time:

```json theme={null}
{
  "name": "glood:search_result_clicked",
  "type": "custom",
  "custom_data": {
    "track": {
      "request_id": "req_01j8x2v9",
      "search_term": "shoe",
      "search_type": "text",
      "source": "search_page",
      "products": [
        { "product_id": "9311227838783", "variant_id": "48792371233087" }
      ],
      "filters": [{ "key": "color", "value": ["red"] }]
    }
  }
}
```

#### glood:search\_filter\_appeared

Send when the filter UI is rendered for a result set. `filters` lists the facets shown, with
`value: null` while nothing is selected:

```json theme={null}
{
  "name": "glood:search_filter_appeared",
  "type": "custom",
  "custom_data": {
    "track": {
      "request_id": "req_01j8x2v9",
      "search_term": "shoe",
      "search_type": "text",
      "source": "search_page",
      "filters": [
        { "key": "color", "value": null },
        { "key": "price", "value": null }
      ]
    }
  }
}
```

#### glood:search\_filter\_updated

Send when a facet is applied or changed. `filters` carries the full current selection (not
the delta):

```json theme={null}
{
  "name": "glood:search_filter_updated",
  "type": "custom",
  "custom_data": {
    "track": {
      "request_id": "req_01j8x2v9",
      "search_term": "shoe",
      "search_type": "text",
      "source": "search_page",
      "filters": [{ "key": "color", "value": ["red", "blue"] }]
    }
  }
}
```

<Note>
  The same `track` shape is used by the other custom search events
  (`glood:instant_search_triggered`, `glood:instant_search_rendered`,
  `glood:image_search_triggered`, `glood:image_search_results_rendered`,
  `glood:search:add_to_cart`) — see the `event.name` enum in the schema for the full list.
</Note>


## OpenAPI

````yaml POST /api/storefront/v1/headless/events
openapi: 3.0.1
info:
  title: Glood.AI API Reference
  description: Glood.AI API Reference
  license:
    name: MIT
  version: 1.0.0
servers:
  - url: https://storefront.glood.ai
security:
  - bearerAuth: []
paths:
  /api/storefront/v1/headless/events:
    servers:
      - url: https://search.glood.ai
    post:
      description: >-
        Ingest storefront / personalization events (standard Shopify pixel
        events and custom `glood:search:*` attribution events). Shop is taken
        from `x-shop`. Auth: `Authorization: Bearer <gl_sf_...>` + `x-shop`.
      parameters:
        - name: x-shop
          in: header
          description: >-
            Shopify store URL. Resolves the shop for the request (headless does
            not accept `?shop=`).
          required: true
          schema:
            type: string
            example: shop.myshopify.com
      requestBody:
        description: Request body
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HeadlessSearchEventsRequest'
      responses:
        '200':
          description: Event accepted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HeadlessSearchEventsResponse'
        '400':
          description: Validation or shop error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    HeadlessSearchEventsRequest:
      type: object
      description: >-
        Storefront / personalization event ingestion. Shop is taken from the
        x-shop header (not the body). Requires `channel` and at least one of
        `visitor_id` / `client_id`.
      required:
        - channel
        - event
      properties:
        channel:
          type: string
          description: Originating storefront channel.
          enum:
            - HYDROGEN
            - HEADLESS
            - MOBILE
        event:
          type: object
          description: The event envelope.
          required:
            - id
            - name
            - type
            - timestamp
            - context
          properties:
            id:
              type: string
              description: Unique event id.
            client_id:
              type: string
              description: Client id carried on the event.
            name:
              type: string
              description: Event name.
              enum:
                - glood:customer_preference
                - cart_viewed
                - checkout_completed
                - checkout_started
                - checkout_shipping_info_submitted
                - checkout_contact_info_submitted
                - checkout_address_info_submitted
                - payment_info_submitted
                - collection_viewed
                - page_viewed
                - product_added_to_cart
                - product_removed_from_cart
                - product_viewed
                - search_submitted
                - ui_extension_errored
                - glood:section:add_to_cart
                - glood:section:click
                - glood:section:render
                - glood:section:view
                - alert_displayed
                - glood:init
                - glood:instant_search_triggered
                - glood:instant_search_rendered
                - glood:search_result_rendered
                - glood:search_result_clicked
                - glood:search_filter_appeared
                - glood:search_filter_updated
                - glood:image_search_triggered
                - glood:image_search_results_rendered
                - glood:bundle:add_to_cart
                - glood:bundle:render
                - glood:bundle:view
                - glood:bundle:click
                - glood:checkout:add_to_cart
                - glood:checkout:render
                - glood:checkout:offer_accept
                - glood:checkout:offer_reject
                - glood:checkout:click
                - glood:post_purchase:render
                - glood:search:add_to_cart
            type:
              type: string
              description: Standard Shopify pixel event or a custom Glood event.
              enum:
                - standard
                - custom
            timestamp:
              type: string
              description: ISO 8601 event time. Must be within +/- 2 days of now.
              format: date-time
            data:
              type: object
              description: Standard event payload (when `type=standard`).
            custom_data:
              type: object
              description: Custom event payload (when `type=custom`).
              properties:
                track:
                  type: object
                  description: >-
                    Search attribution payload (custom events). Carried under
                    `event.custom_data.track`.
                  properties:
                    source:
                      type: string
                      description: >-
                        Where the interaction originated (e.g. `instant`,
                        `search_page`).
                    page_type:
                      type: string
                      description: Page type of the interaction.
                    pages:
                      type: array
                      description: Pages involved.
                      items:
                        type: object
                        description: A page ref.
                        required:
                          - page_id
                        properties:
                          page_id:
                            type: string
                            description: Page id.
                    products:
                      type: array
                      description: Products involved.
                      items:
                        type: object
                        description: A tracked product.
                        required:
                          - product_id
                        properties:
                          product_id:
                            type: string
                            description: Product id.
                          variant_id:
                            type: string
                            nullable: true
                            description: Variant id.
                          quantity:
                            type: number
                            description: Quantity.
                    request_id:
                      type: string
                      description: >-
                        `request_id` from the search response, tying the event
                        to a serve.
                    filters:
                      type: array
                      description: Applied filters at interaction time.
                      items:
                        type: object
                        description: A filter selection.
                        required:
                          - key
                          - value
                        properties:
                          key:
                            type: string
                            description: Filter key.
                          value:
                            type: array
                            nullable: true
                            items:
                              oneOf:
                                - type: string
                                - type: number
                                - type: boolean
                            description: Selected value(s).
                    search_term:
                      type: string
                      description: The search term.
                    search_type:
                      type: string
                      description: Search type.
                      enum:
                        - text
                        - image
                    checkout_token:
                      type: string
                      description: Checkout token, for conversion attribution.
                    campaign:
                      type: string
                      description: Campaign identifier.
            context:
              type: object
              description: Browser context.
              required:
                - navigator
              properties:
                document:
                  type: object
                  description: Document context (referrer, title, location, ...).
                navigator:
                  type: object
                  description: Navigator context.
                  required:
                    - user_agent
                  properties:
                    user_agent:
                      type: string
                      description: Client user-agent string (required).
                window:
                  type: object
                  description: Window context (screen, ...).
        session_id:
          type: string
          description: >-
            Browsing-session id (the unit of funnel + attribution analytics).
            Optional; the server generates a uuid when absent, but send a stable
            one per visit for accurate analytics.
        visitor_id:
          type: string
          description: >-
            Anonymous persistent visitor UID. At least one of `visitor_id` /
            `client_id` is required.
        client_id:
          type: string
          description: >-
            Client/device id (persists across sessions). At least one of
            `visitor_id` / `client_id` is required.
        customer_id:
          type: string
          description: Shopify customer id when logged in.
        page_type:
          type: string
          description: Page type the event fired from.
        page_url:
          type: string
          description: URL the event fired from.
        cart_identifier:
          type: string
          description: Cart token/key identifier.
        cart:
          type: object
          description: Cart state at event time.
        customer:
          type: object
          description: Customer info at event time.
        customer_privacy:
          type: object
          description: Customer consent flags.
          properties:
            analytics_processing_allowed:
              type: boolean
              description: Analytics consent.
            marketing_allowed:
              type: boolean
              description: Marketing consent.
            preferences_processing_allowed:
              type: boolean
              description: Preferences consent.
            sale_of_data_allowed:
              type: boolean
              description: Sale-of-data consent.
    HeadlessSearchEventsResponse:
      type: object
      description: Event ingestion acknowledgement.
      properties:
        ok:
          type: boolean
          enum:
            - true
          description: Indicates the event was accepted.
    Error:
      required:
        - error
        - message
      type: object
      properties:
        error:
          type: integer
          format: int32
        message:
          type: string
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer

````