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

# Content Search: Execute Search

> Content Search API endpoint to run semantic searches across blog articles, knowledge base pages, and other content.

## Authorization

<ParamField header="X-Storefront-Access-Token" type="string" required>
  Token-based authentication header in the form of `<YOUR_LAYERS_TOKEN>`.
</ParamField>

## Headers

<ParamField header="Content-Type" type="string" default="application/json" required />

<ParamField header="Accept" type="string" default="application/json" required />

## Path parameters

<ParamField path="searchQuery" type="string" required>
  The url-encoded search query.
</ParamField>

## Body

<ParamField body="content_type" type="string">
  Filter results by content type. Supported values: `"article"` and `"page"`. When omitted, all content types are searched and results from both articles and pages are returned together.
</ParamField>

<ParamField body="pagination" type="Pagination Object" description="Specifies the page number and limit for pagination.">
  <Expandable title="pagination">
    <ParamField body="page" type="int" min="1" max="100">
      The current page of results to fetch.
    </ParamField>

    <ParamField body="limit" type="int" min="1" max="100">
      The max results to fetch per page
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="tuning" type="object" description="Fine-tune ranking behavior for this request.">
  Override default ranking weights for content search.

  <Expandable title="Properties">
    <ParamField body="textualWeight" type="number">
      Weight for textual (semantic text) similarity in ranking, between `0` and `1`. Required when `visualWeight` is provided.
    </ParamField>

    <ParamField body="visualWeight" type="number">
      Weight for visual (image) similarity in ranking, between `0` and `1`. Required when `textualWeight` is provided.
    </ParamField>

    <ParamField body="topK" type="integer">
      Number of candidate results to retrieve before re-ranking, between `1` and `100`.
    </ParamField>

    <ParamField body="rankingWeightOverrides" type="object">
      Override the default ranking model weights for this request. Each key is a signal group name and the value is a weight between `0` and `1`. Content search supports the following groups:

      * `semantic` — controls how much text and image similarity contribute to the score.
      * `freshness` — controls how much publication recency contributes to the score.

      When provided, the weights are normalized so they sum to 1.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="identity" type="object">
  User identity information for tracking and personalization. Automatically managed by the Storefront Pixel; required for headless integrations.

  <Expandable title="Properties">
    <ParamField body="deviceId" type="string">
      Persistent browser identifier that remains constant across sessions. Used to recognize returning visitors for long-term personalization. Automatically generated and managed by the Storefront Pixel.
    </ParamField>

    <ParamField body="sessionId" type="string">
      Temporary session identifier. Typically corresponds to the Shopify session ID and expires after inactivity or when the browser is closed.
    </ParamField>

    <ParamField body="customerId" type="string">
      Shopify customer ID for authenticated users. Only present when the user is signed in to their account.
    </ParamField>

    <ParamField body="companyLocationId" type="string">
      Shopify B2B company location GID (e.g. `gid://shopify/CompanyLocation/123456789`) for the authenticated buyer. Layers resolves the catalog assigned to the company location and uses it to scope results: only products in the catalog are returned, prices come from the catalog's price list, and excluded collections return 404. Omit for retail (DTC) traffic. See [B2B catalogs](/shopify-integration/b2b-catalogs).
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="context" type="object">
  Contextual information about the customer's session, behavior, and environment. Automatically collected by the Storefront Pixel; must be manually provided for headless integrations. See [Contextual Information](/engine/contextual-information) for implementation guidance.

  <Expandable title="Properties">
    <ParamField body="geo" type="object">
      Geographic location information for regional personalization and merchandising. Automatically determined by the platform for client-side requests based on IP address. For server-side API calls (headless integrations), you should provide this explicitly.

      <Expandable title="Properties">
        <ParamField body="country" type="string">
          Country code or name (e.g., "US", "Canada").
        </ParamField>

        <ParamField body="province" type="string">
          State or province name (e.g., "California", "Ontario").
        </ParamField>

        <ParamField body="city" type="string">
          City name (e.g., "Los Angeles", "Toronto").
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="productsInCart" type="array">
      Products currently in the customer's cart. Used to surface complementary products and influence relevance scoring.

      <Expandable title="Array Item Properties">
        <ParamField body="title" type="string" required>
          Product title.
        </ParamField>

        <ParamField body="price" type="number">
          Product price.
        </ParamField>

        <ParamField body="type" type="string">
          Product type or category.
        </ParamField>

        <ParamField body="productId" type="string">
          Product identifier. Accepts a numeric ID (e.g., `"8234567890123"`) or a Shopify GID (e.g., `"gid://shopify/Product/8234567890123"`).
        </ParamField>

        <ParamField body="variantId" type="string">
          Product variant identifier.
        </ParamField>

        <ParamField body="options" type="object">
          Product variant options (e.g., `{"Size": "11", "Color": "Red"}`).
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="productsPurchased" type="array">
      Products the customer has previously purchased. Informs recommendations and prevents over-promotion of owned items.

      <Expandable title="Array Item Properties">
        <ParamField body="title" type="string" required>
          Product title.
        </ParamField>

        <ParamField body="price" type="number">
          Product price at time of purchase.
        </ParamField>

        <ParamField body="type" type="string">
          Product type or category.
        </ParamField>

        <ParamField body="productId" type="string">
          Product identifier. Accepts a numeric ID (e.g., `"8234567890123"`) or a Shopify GID (e.g., `"gid://shopify/Product/8234567890123"`).
        </ParamField>

        <ParamField body="variantId" type="string">
          Product variant identifier.
        </ParamField>

        <ParamField body="options" type="object">
          Product variant options (e.g., `{"Size": "11", "Color": "Red"}`).
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="priorSearches" type="array">
      Recent search queries and their outcomes. Helps understand customer intent and refine relevance models.

      <Expandable title="Array Item Properties">
        <ParamField body="searchQuery" type="string" required>
          The search query text.
        </ParamField>

        <ParamField body="hadClick" type="boolean" required>
          Whether the customer clicked on any results from this search.
        </ParamField>

        <ParamField body="hasResults" type="boolean" required>
          Whether the search returned any results.
        </ParamField>

        <ParamField body="fromPage" type="string">
          The page the search was initiated from (e.g., the referring page URL or page type).
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="marketing" type="object">
      UTM parameters and marketing campaign information for attribution tracking.

      <Expandable title="Properties">
        <ParamField body="source" type="string">
          Marketing source (e.g., "google", "facebook").
        </ParamField>

        <ParamField body="medium" type="string">
          Marketing medium (e.g., "cpc", "email", "social").
        </ParamField>

        <ParamField body="campaign" type="string">
          Campaign name.
        </ParamField>

        <ParamField body="term" type="string">
          Search term or keyword.
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="customer" type="object">
      Aggregated customer behavior and purchase patterns for personalization.

      <Expandable title="Properties">
        <ParamField body="signedIn" type="boolean">
          Whether the customer is currently authenticated.
        </ParamField>

        <ParamField body="returning" type="boolean">
          Whether this is a returning customer.
        </ParamField>

        <ParamField body="numberOfOrders" type="integer">
          Total number of orders placed.
        </ParamField>

        <ParamField body="averageOrderValue" type="number">
          Average order value in store currency.
        </ParamField>

        <ParamField body="daysBetweenOrders" type="integer">
          Average days between orders.
        </ParamField>

        <ParamField body="daysSinceLastOrder" type="integer">
          Days since the most recent order.
        </ParamField>

        <ParamField body="daysSinceOldestOrder" type="integer">
          Days since the first order.
        </ParamField>

        <ParamField body="totalSpent" type="number">
          Total amount spent in store currency.
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="market" type="string">
      Explicitly set the Shopify Market for this request. Used for market-specific product availability filtering and contextual pricing. Accepts a two-letter country code (e.g., `"US"`, `"CA"`), a numeric Shopify Market ID (e.g., `"12345"`), or a Shopify Market GID (e.g., `"gid://shopify/Market/12345"`).

      When not provided, the market is automatically resolved from the `geo.country` field (or the shopper's detected country for client-side requests). If no matching market is found, the store's primary market is used as the fallback.

      **Behavior depends on the store's market application mode:**

      * **Strict** — Products are filtered to only those available in the resolved market, and market-specific pricing is applied
      * **Pricing only** — The full catalog remains visible, but variant prices are swapped to market-specific values where available
      * **Off** — Market resolution is skipped entirely; base catalog and base pricing are used for all shoppers
    </ParamField>

    <ParamField body="shoppingChannel" type="string" default="web">
      The shopping channel the customer is browsing from. Used for channel-specific merchandising, sorting, and analytics segmentation. Automatically detected from request headers when not provided (e.g., mobile app requests via Tapcart or Canvas are detected as `"app"`).

      **Accepted values:**

      * `"web"` — Standard web browser (default)
      * `"app"` — Mobile app (e.g., Tapcart, Canvas)
    </ParamField>

    <ParamField body="custom" type="object">
      Custom contextual data specific to your implementation. Structure is flexible and can contain any key-value pairs relevant to your use case.
    </ParamField>
  </Expandable>
</ParamField>

## Response

<ResponseField name="results" type="array">
  Array of content items matching the search query. Results can include both articles and pages when no `content_type` filter is applied. Each item includes:

  <Expandable title="Content item properties">
    <ResponseField name="__typename" type="string">
      The content type identifier. Returns `"Article"` for blog articles or `"Page"` for Shopify pages.
    </ResponseField>

    <ResponseField name="content_type" type="string">
      The content type: `"article"` or `"page"`.
    </ResponseField>

    <ResponseField name="content_id" type="number">
      The unique identifier for the content item.
    </ResponseField>

    <ResponseField name="title" type="string">
      The content title.
    </ResponseField>

    <ResponseField name="handle" type="string">
      The URL handle for the content item.
    </ResponseField>

    <ResponseField name="summary_text" type="string">
      The content summary with HTML tags stripped (except images).
    </ResponseField>

    <ResponseField name="author" type="string">
      The author name. For pages, this may be `null`.
    </ResponseField>

    <ResponseField name="tags" type="array">
      Array of tags associated with the content item. For pages, this is an empty array.
    </ResponseField>

    <ResponseField name="image" type="object">
      The featured image.

      <Expandable title="Properties">
        <ResponseField name="url" type="string">
          The image URL.
        </ResponseField>

        <ResponseField name="width" type="number">
          The image width in pixels.
        </ResponseField>

        <ResponseField name="height" type="number">
          The image height in pixels.
        </ResponseField>

        <ResponseField name="altText" type="string">
          The image alt text.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="published_at" type="string">
      ISO 8601 timestamp of when the content was published.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="query" type="string">
  The search query that was executed.
</ResponseField>

<ResponseField name="contentType" type="string">
  The content type filter applied, if any.
</ResponseField>

<ResponseField name="totalResults" type="number">
  The total number of results matching the search query.
</ResponseField>

<ResponseField name="page" type="number">
  The current page number.
</ResponseField>

<ResponseField name="totalPages" type="number">
  The total number of pages.
</ResponseField>

<ResponseField name="resultsPerPage" type="number">
  The number of results per page.
</ResponseField>

### Response headers

| Header           | Description                                                                                                                     |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `x-request-id`   | A unique identifier (ULID) for the request. Use it to correlate requests across your infrastructure or when contacting support. |
| `x-layers-build` | The Layers build version that served the request.                                                                               |

## Supported content types

Content search indexes two types of Shopify content:

| Content type | `__typename` | Description                                                                               |
| ------------ | ------------ | ----------------------------------------------------------------------------------------- |
| **Articles** | `"Article"`  | Blog posts from your Shopify blog. Includes author, tags, and blog association.           |
| **Pages**    | `"Page"`     | Shopify pages (e.g., About Us, FAQ, Size Guide). Includes featured images when available. |

When you omit the `content_type` parameter, results from both articles and pages are returned together, ranked by a unified scoring model. Use the `__typename` field to distinguish between content types when rendering results.

## Search behavior

Content search uses a configurable ranking model to score and rank results. The default model combines three signal groups:

| Signal group         | Default weight | What it measures                                                  |
| -------------------- | -------------- | ----------------------------------------------------------------- |
| **Semantic (text)**  | 50%            | How closely the content text matches the meaning of the query     |
| **Semantic (image)** | 20%            | How closely the content's images match the query                  |
| **Freshness**        | 30%            | How recently the content was published (newer items score higher) |

Scores from each signal group are normalized using min-max scaling across the result set, then combined into a single ranking score using a weighted linear combination.

You can override these weights per-request using the `tuning.rankingWeightOverrides` parameter. For product search testing, use [Test text search](/help/evaluate/test-text-search) in Lab.

## Error handling

When search processing fails (e.g., due to rate limits or service issues), the API returns an empty result set with `totalResults: 0` rather than throwing an error. This ensures graceful degradation of the search experience.

<ResponseExample>
  ```json Response theme={null}
  {
      "query": "sustainable fashion tips",
      "contentType": null,
      "resultsPerPage": 20,
      "totalResults": 14,
      "page": 1,
      "totalPages": 1,
      "results": [
          {
              "__typename": "Article",
              "content_type": "article",
              "content_id": 12345678901,
              "title": "10 Ways to Build a Sustainable Wardrobe",
              "handle": "sustainable-wardrobe-tips",
              "summary_text": "Discover practical tips for creating an eco-friendly wardrobe that's both stylish and sustainable.",
              "author": "Emma Green",
              "tags": ["sustainability", "fashion", "eco-friendly"],
              "image": {
                  "url": "https://cdn.shopify.com/s/files/1/0588/3677/9194/articles/sustainable-fashion.jpg",
                  "width": 1200,
                  "height": 630,
                  "altText": "Sustainable Fashion Guide"
              },
              "published_at": "2024-06-01T12:00:00Z"
          },
          {
              "__typename": "Page",
              "content_type": "page",
              "content_id": 98765432101,
              "title": "Our Sustainability Commitment",
              "handle": "sustainability",
              "summary_text": "Learn about our commitment to ethical sourcing and sustainable materials across all product lines.",
              "author": null,
              "tags": [],
              "image": {
                  "url": "https://cdn.shopify.com/s/files/1/0588/3677/9194/files/sustainability-hero.jpg",
                  "width": 1600,
                  "height": 900,
                  "altText": "Sustainability page hero"
              },
              "published_at": "2024-03-15T10:00:00Z"
          }
      ]
  }
  ```
</ResponseExample>

## Usage example

```bash cURL (all content types) theme={null}
curl -X POST "https://app.uselayers.com/api/storefront/v1/search/content/sustainable%20fashion/execute" \
  -H "X-Storefront-Access-Token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "pagination": {
      "page": 1,
      "limit": 20
    },
    "context": {
      "geo": {
        "country": "US"
      },
      "shoppingChannel": "web"
    },
    "identity": {
      "sessionId": "abc123",
      "deviceId": "device-uuid"
    }
  }'
```

```bash cURL (pages only) theme={null}
curl -X POST "https://app.uselayers.com/api/storefront/v1/search/content/return%20policy/execute" \
  -H "X-Storefront-Access-Token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "content_type": "page",
    "pagination": {
      "page": 1,
      "limit": 20
    }
  }'
```

<Note>
  **Content sync**: Articles and pages are automatically synced from Shopify via webhooks and bulk operations. Only published content without the `seo.hidden` metafield is included in search results.
</Note>
