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

# Search Listings

A Search Listing returns collections of items — product grids, article archives, search results — with filtering, sorting, full-text search, pagination, and facets built in. Each item in the collection is shaped like a [Detail Block](/api-builder/blocks).

Manage your listings in the [API Builder](https://app.frontic.com/builder/listings) section of the admin app.

<Screenshot name="api-builder/listings-overview" caption="Search Listings in the API Builder" alt="API Builder showing a list of Search Listings with their names, connected blocks, and parameters" />

<Frame caption="Search Listings in the API Builder">
  <img src="https://mintcdn.com/frontic/hS7rYTW0C-o2HHTZ/images/api-builder/listings-overview-light.png?fit=max&auto=format&n=hS7rYTW0C-o2HHTZ&q=85&s=2d0b7ca54fa719a76ef67510499366c0" className="dark:hidden block" alt="API Builder showing a list of Search Listings with their names, connected blocks, and parameters" width="2880" height="1800" data-path="images/api-builder/listings-overview-light.png" />

  <img src="https://mintcdn.com/frontic/hS7rYTW0C-o2HHTZ/images/api-builder/listings-overview-dark.png?fit=max&auto=format&n=hS7rYTW0C-o2HHTZ&q=85&s=7d767f6626b459be32f79033bd420bd6" className="hidden dark:block" alt="API Builder showing a list of Search Listings with their names, connected blocks, and parameters" width="2880" height="1800" data-path="images/api-builder/listings-overview-dark.png" />
</Frame>

## Create a listing

Head to the [API Builder](https://app.frontic.com/builder/listings) and click **<Icon icon="plus" iconType="solid" /> Add Listing**.

<Screenshot name="api-builder/listing-create" caption="Create a new Search Listing — name and endpoint" alt="Create listing dialog with name input and auto-generated endpoint URL" view="dialog" />

<Frame caption="Create a new Search Listing — name and endpoint">
  <img src="https://mintcdn.com/frontic/xG0tT-c_zeEiwfrd/images/api-builder/listing-create-light.png?fit=max&auto=format&n=xG0tT-c_zeEiwfrd&q=85&s=a752b2a8c82a1b376d229037c626a201" className="dark:hidden block mx-auto mt-10 mb-5" style={{ maxWidth: "360px" }} alt="Create listing dialog with name input and auto-generated endpoint URL" width="1152" height="740" data-path="images/api-builder/listing-create-light.png" />

  <img src="https://mintcdn.com/frontic/xG0tT-c_zeEiwfrd/images/api-builder/listing-create-dark.png?fit=max&auto=format&n=xG0tT-c_zeEiwfrd&q=85&s=d5393b43201980cfebbb9c027437ea9a" className="hidden dark:block mx-auto mt-10 mb-5" style={{ maxWidth: "360px" }} alt="Create listing dialog with name input and auto-generated endpoint URL" width="1152" height="740" data-path="images/api-builder/listing-create-dark.png" />
</Frame>

Frontic generates an endpoint URL as you type the name.

<Warning>
  Listing names must use normal capitalized words with spaces (e.g., `Product Listing`, not `ProductListing`). Frontic derives the namespace and endpoint slug from this value — incorrect casing will break the auto-generated endpoint.
</Warning>

After the listing is created, configure it in the **Settings** and **Query** tabs — pick the [Detail Block](/api-builder/blocks) that shapes each item, define input parameters, and set up filters, sort options, full-text search, and pagination.

## Listing Settings

The **Settings** tab covers what the listing accepts as input, how results are returned, and which storage it reads from.

<Screenshot name="api-builder/listing-settings" caption="Listing Settings — input parameters, result strategy, storage connection" alt="Listing Settings tab showing Input Parameters, Result Strategy, and Storage sections" />

<Frame caption="Listing Settings — input parameters, result strategy, storage connection">
  <img src="https://mintcdn.com/frontic/hS7rYTW0C-o2HHTZ/images/api-builder/listing-settings-light.png?fit=max&auto=format&n=hS7rYTW0C-o2HHTZ&q=85&s=0d09b21e802594fdc6e8527174ab8056" className="dark:hidden block" alt="Listing Settings tab showing Input Parameters, Result Strategy, and Storage sections" width="2880" height="1800" data-path="images/api-builder/listing-settings-light.png" />

  <img src="https://mintcdn.com/frontic/hS7rYTW0C-o2HHTZ/images/api-builder/listing-settings-dark.png?fit=max&auto=format&n=hS7rYTW0C-o2HHTZ&q=85&s=1411aed8e5f2eef99d64286eec072004" className="hidden dark:block" alt="Listing Settings tab showing Input Parameters, Result Strategy, and Storage sections" width="2880" height="1800" data-path="images/api-builder/listing-settings-dark.png" />
</Frame>

### Input Parameters

Parameters let you scope a listing to a specific subset — for example, fetching products in a specific category. Parameters can be strings (a category ID) or arrays (a list of product IDs).

In the **Base Query** card inside the **Query** tab, map parameters to query criteria that filter the results.

Parameters are typically controlled by the frontend based on context (the current category, the current brand), while query options (search, filters, sorting, pagination) are controlled by the user. This separation keeps the core content gated while letting users refine results.

### Result Strategy

When the connected storage is a commerce storage, choose which level the listing returns:

* **Product level** — one row per product. Returns shared fields (name, description, brand, categories). Variant-specific data is derived via the connected block's Price, Variant Field, and Variant List fields. Use for category grids, search results, and product cards.
* **Variant level** — one row per variant. Returns variant fields (price, options, SKU, stock) plus the inherited shared fields. Use for cart line items, wishlist rows, and variant pickers.

See [Product Models](/commerce-concepts/product-models#product-level-vs-variant-level-blocks) for the full picture.

### Storage

The listing reads from a connected [Data Storage](/data-integration/data-storages). The Result Strategy above selects which level of that storage drives the rows.

## Query Settings

The **Query** tab controls how the listing can be filtered, searched, sorted, and paginated.

<Screenshot name="api-builder/listing-query" caption="Query Settings — base query, filters, search, sorting, pagination" alt="Listing Query tab showing base query, filter options, searchable fields, sorting, and pagination configuration" />

<Frame caption="Query Settings — base query, filters, search, sorting, pagination">
  <img src="https://mintcdn.com/frontic/hS7rYTW0C-o2HHTZ/images/api-builder/listing-query-light.png?fit=max&auto=format&n=hS7rYTW0C-o2HHTZ&q=85&s=2416e34944fb77c5070ef01f80c72333" className="dark:hidden block" alt="Listing Query tab showing base query, filter options, searchable fields, sorting, and pagination configuration" width="2880" height="1800" data-path="images/api-builder/listing-query-light.png" />

  <img src="https://mintcdn.com/frontic/hS7rYTW0C-o2HHTZ/images/api-builder/listing-query-dark.png?fit=max&auto=format&n=hS7rYTW0C-o2HHTZ&q=85&s=4bff553c4cfefc80c7d3f15cd220722f" className="hidden dark:block" alt="Listing Query tab showing base query, filter options, searchable fields, sorting, and pagination configuration" width="2880" height="1800" data-path="images/api-builder/listing-query-dark.png" />
</Frame>

### Base query

A pre-defined query that always applies to the listing — every request runs through these conditions before user filters are applied. Use it to scope the listing to a subset of records (e.g. only active products, only items in a specific category).

Each condition has three parts:

* **Field** — a storage field or [block field](/api-builder/blocks) to match against. The value input adapts to the field's type, so booleans, numbers, strings, and enums all get the right widget.
* **Operator** — how to compare. Available operators:
  * `equals` / `notEquals` — exact match. Works on both string and array fields — on arrays, Frontic turns it into an "includes" check under the hood. This is the operator to use when matching against a field that holds a list of values (e.g. category IDs).
  * `like` / `notLike` — partial match (contains)
  * `gt` / `gte` / `lt` / `lte` — numeric comparisons
* **Value** — a static value or a [mapped parameter](#input-parameters), set via the source toggle on the right of the input:
  * **Static** — compare against a fixed value. The widget matches the field type: a switch for booleans, a number input for integers and floats, a dropdown for enums, a text input for everything else.
  * **Mapped** — compare against an input parameter. The picker only lists parameters whose type matches the field. If exactly one matches, it's selected automatically. If none match, the picker is disabled with a "No matching parameter" hint.

Changing the field afterwards clears the value and resets the operator, so a condition can't end up with a value type that doesn't match the field.

You can add multiple conditions and choose whether records must match **all** of them or **any** of them.

<Screenshot name="api-builder/listing-base-query-card" caption="Base Query — conditions combine static values with mapped parameters" alt="Base Query card with two conditions, each showing a Field selector, an Operator selector, an inline value input, and a Static / Mapped source toggle" view="cutout" width="480px" />

<Frame caption="Base Query — conditions combine static values with mapped parameters">
  <img src="https://mintcdn.com/frontic/XvZvXnK7TnXApV9W/images/api-builder/listing-base-query-card-light.png?fit=max&auto=format&n=XvZvXnK7TnXApV9W&q=85&s=b7cfd985ee760375fdf855a6bfa33844" className="dark:hidden block mx-auto mt-5 mb-5" style={{ maxWidth: "480px" }} alt="Base Query card with two conditions, each showing a Field selector, an Operator selector, an inline value input, and a Static / Mapped source toggle" width="1672" height="490" data-path="images/api-builder/listing-base-query-card-light.png" />

  <img src="https://mintcdn.com/frontic/XvZvXnK7TnXApV9W/images/api-builder/listing-base-query-card-dark.png?fit=max&auto=format&n=XvZvXnK7TnXApV9W&q=85&s=875664d4d9c3f5e36b35f78a0c15f002" className="hidden dark:block mx-auto mt-5 mb-5" style={{ maxWidth: "480px" }} alt="Base Query card with two conditions, each showing a Field selector, an Operator selector, an inline value input, and a Static / Mapped source toggle" width="1672" height="490" data-path="images/api-builder/listing-base-query-card-dark.png" />
</Frame>

### Filter options

Filter, search, sorting, and pagination settings are configured directly in the **Query** tab below the base query.

Select which fields users can filter on. Each selected field becomes a filter in the API response with facet data your frontend can render as checkboxes, dropdowns, or sliders.

* **Fields** — select from block fields or storage fields. Each selected field becomes a filterable dimension.
* **Facets** — enabled by default (up to 200 values per filter). Disable for high-cardinality fields like price ranges to reduce response size. See [Filter facets](#filter-facets) below for the response shape.
* **Active vs. total** — facets are returned in two sets: `result` (matching the current filters) and `total` (all items). Your UI can show both "X results with this filter" and "Y total items."

<Screenshot name="api-builder/listing-filters-card" caption="Filters — selected fields with facet and aggregation toggles" alt="Filters card listing six filterable fields with type badges and per-field facet and aggregation toggles" view="cutout" width="480px" />

<Frame caption="Filters — selected fields with facet and aggregation toggles">
  <img src="https://mintcdn.com/frontic/hS7rYTW0C-o2HHTZ/images/api-builder/listing-filters-card-light.png?fit=max&auto=format&n=hS7rYTW0C-o2HHTZ&q=85&s=1c59f48efac2b5fd557f9129a4d52c5b" className="dark:hidden block mx-auto mt-5 mb-5" style={{ maxWidth: "480px" }} alt="Filters card listing six filterable fields with type badges and per-field facet and aggregation toggles" width="1716" height="728" data-path="images/api-builder/listing-filters-card-light.png" />

  <img src="https://mintcdn.com/frontic/hS7rYTW0C-o2HHTZ/images/api-builder/listing-filters-card-dark.png?fit=max&auto=format&n=hS7rYTW0C-o2HHTZ&q=85&s=756eb155e7ef65f05ecec956cd2518d6" className="hidden dark:block mx-auto mt-5 mb-5" style={{ maxWidth: "480px" }} alt="Filters card listing six filterable fields with type badges and per-field facet and aggregation toggles" width="1716" height="728" data-path="images/api-builder/listing-filters-card-dark.png" />
</Frame>

#### Dynamic filters

When you select an [`Option` composite](/data-integration/data-storages#option-fields) as a filter, Frontic auto-generates **dynamic facets grouped by attribute**. One Option field produces separate filter groups for color, size, material, etc. — no manual setup needed. The facets are aggregated across variants, so a product-level listing shows all available options.

### Searchable fields

Select which fields support full-text search. Often used for product names, aliases, or descriptions.

* **Fields** — select from block fields or storage fields. Multiple fields can be searchable at once.
* **Fuzzy matching** — enabled by default to counteract typos. Disable for exact matches only.

<Screenshot name="api-builder/listing-search-card" caption="Search — selected fields support full-text search" alt="Search card showing the list of searchable fields with their types" view="cutout" width="480px" />

<Frame caption="Search — selected fields support full-text search">
  <img src="https://mintcdn.com/frontic/hS7rYTW0C-o2HHTZ/images/api-builder/listing-search-card-light.png?fit=max&auto=format&n=hS7rYTW0C-o2HHTZ&q=85&s=d6c01f4295116f8671a1010bde623c23" className="dark:hidden block mx-auto mt-5 mb-5" style={{ maxWidth: "480px" }} alt="Search card showing the list of searchable fields with their types" width="1716" height="640" data-path="images/api-builder/listing-search-card-light.png" />

  <img src="https://mintcdn.com/frontic/hS7rYTW0C-o2HHTZ/images/api-builder/listing-search-card-dark.png?fit=max&auto=format&n=hS7rYTW0C-o2HHTZ&q=85&s=efb3d8d229bed55d21c3b1e81f7730dc" className="hidden dark:block mx-auto mt-5 mb-5" style={{ maxWidth: "480px" }} alt="Search card showing the list of searchable fields with their types" width="1716" height="640" data-path="images/api-builder/listing-search-card-dark.png" />
</Frame>

### Sorting

Define which fields users can sort by.

* **Sort fields** — select from block fields or storage fields
* **Default sort** — which field and direction (ascending/descending) to use when no sort is specified
* **Multiple options** — users can choose between up to 3 sort options

<Screenshot name="api-builder/listing-sorting-card" caption="Sort — fields, default selection, direction" alt="Sort card showing available sort fields with default selection and ascending/descending direction" view="cutout" width="480px" />

<Frame caption="Sort — fields, default selection, direction">
  <img src="https://mintcdn.com/frontic/hS7rYTW0C-o2HHTZ/images/api-builder/listing-sorting-card-light.png?fit=max&auto=format&n=hS7rYTW0C-o2HHTZ&q=85&s=c69a76cd1ea4855dbc5f860c1fb6ce26" className="dark:hidden block mx-auto mt-5 mb-5" style={{ maxWidth: "480px" }} alt="Sort card showing available sort fields with default selection and ascending/descending direction" width="1716" height="380" data-path="images/api-builder/listing-sorting-card-light.png" />

  <img src="https://mintcdn.com/frontic/hS7rYTW0C-o2HHTZ/images/api-builder/listing-sorting-card-dark.png?fit=max&auto=format&n=hS7rYTW0C-o2HHTZ&q=85&s=7a92e44b15fea689c5d7a93c1286681a" className="hidden dark:block mx-auto mt-5 mb-5" style={{ maxWidth: "480px" }} alt="Sort card showing available sort fields with default selection and ascending/descending direction" width="1716" height="380" data-path="images/api-builder/listing-sorting-card-dark.png" />
</Frame>

#### Dynamic sortings

For category-specific product positioning or other parameterized sort orders, use the built-in "Sorting" data type in your storage. When you add it as a sort option, Frontic asks you to select a parameter whose value matches the key inside your sorting structure. Missing keys are handled gracefully.

Sorting keys (and the parameter) must be strings.

### Pagination

* **Default page size** — how many items per page when no limit is specified
* **Maximum page size** — the upper bound for the `limit` parameter

<Screenshot name="api-builder/listing-pagination-card" caption="Pagination — default and maximum page size" alt="Pagination card showing default and maximum page size inputs" view="cutout" width="480px" />

<Frame caption="Pagination — default and maximum page size">
  <img src="https://mintcdn.com/frontic/hS7rYTW0C-o2HHTZ/images/api-builder/listing-pagination-card-light.png?fit=max&auto=format&n=hS7rYTW0C-o2HHTZ&q=85&s=92275accee1f109928ada0c1d397f0bd" className="dark:hidden block mx-auto mt-5 mb-5" style={{ maxWidth: "480px" }} alt="Pagination card showing default and maximum page size inputs" width="1716" height="296" data-path="images/api-builder/listing-pagination-card-light.png" />

  <img src="https://mintcdn.com/frontic/hS7rYTW0C-o2HHTZ/images/api-builder/listing-pagination-card-dark.png?fit=max&auto=format&n=hS7rYTW0C-o2HHTZ&q=85&s=5c95d9d98238ef21f29bba57af6dbdf0" className="hidden dark:block mx-auto mt-5 mb-5" style={{ maxWidth: "480px" }} alt="Pagination card showing default and maximum page size inputs" width="1716" height="296" data-path="images/api-builder/listing-pagination-card-dark.png" />
</Frame>

## Fetch a listing

The minimal call takes the listing name and its parameters:

<Tabs>
  <Tab title="Client SDK">
    ```ts theme={"theme":"css-variables"}
    const { items } = await client.listing("ProductListing", {
      categoryId: "shoes",
    });
    ```
  </Tab>

  <Tab title="Nuxt Module">
    ```vue theme={"theme":"css-variables"}
    <script setup lang="ts">
    const { listing } = useFronticListing('ProductListing', {
      categoryId: 'shoes',
    })
    </script>
    ```
  </Tab>
</Tabs>

Add a `query` object to filter, sort, search, and paginate. Filters support `equals`, `range`, `contains`, and `and` / `or` / `not` for chaining — by default they're AND-combined. Passing an array of values to `equals` or `contains` is treated as an OR group.

<Tabs>
  <Tab title="Client SDK">
    ```ts theme={"theme":"css-variables"}
    const { items } = await client.listing(
      "ProductListing",
      { categoryId: "shoes" },
      {
        query: {
          filter: [
            { field: "price.amount", type: "range", from: 3000, to: 10000 },
            {
              type: "or",
              filter: [
                { field: "properties.activity", type: "equals", value: "Running" },
                { field: "properties.activity", type: "equals", value: "Cycling" },
              ],
            },
          ],
          sort: { field: "publishedAt", order: "desc" },
          search: "trail",
          page: 1,
          limit: 24,
        },
      },
    );
    ```
  </Tab>

  <Tab title="Nuxt Module">
    ```vue theme={"theme":"css-variables"}
    <script setup lang="ts">
    const { listing } = useFronticListing(
      'ProductListing',
      { categoryId: 'shoes' },
      {
        query: {
          filter: [
            { field: 'price.amount', type: 'range', from: 3000, to: 10000 },
            {
              type: 'or',
              filter: [
                { field: 'properties.activity', type: 'equals', value: 'Running' },
                { field: 'properties.activity', type: 'equals', value: 'Cycling' },
              ],
            },
          ],
          sort: { field: 'publishedAt', order: 'desc' },
          search: 'trail',
          page: 1,
          limit: 24,
        },
      },
    )
    </script>
    ```
  </Tab>
</Tabs>

For interactive search UIs, [`useFronticSearch`](/reference/nuxt-module#usefronticsearch) wraps `useFronticListing` with reactive state and ready-to-use methods for adding/removing filters, sorting, paginating, searching, and resetting state.

See the [Client SDK reference](/reference/client-sdk#client-listing) and [Nuxt module reference](/reference/nuxt-module#usefronticlisting) for the full API surface, including all filter operators and per-request overrides.

## Response

The response contains items and metadata for building your UI.

```json theme={"theme":"css-variables"}
{
  "items": [],
  "total": 998,
  "page": {
    "last": 42,
    "limit": 24,
    "current": 1,
    "next": null,
    "prev": null
  },
  "filter": {},
  "aggregation": {},
  "sort": []
}
```

<ResponseField name="items" type="array">
  The resulting items, each shaped like the connected Detail Block.
</ResponseField>

<ResponseField name="total" type="number">
  Total number of items matching the query.
</ResponseField>

<ResponseField name="page" type="object">
  Current page information: `current`, `last`, `limit`, `next`, `prev`.
</ResponseField>

<ResponseField name="filter" type="object">
  Facet data for each configured filter field.
</ResponseField>

<ResponseField name="aggregation" type="object">
  Aggregation results (min, max, avg, sum, total) for configured filter fields.
</ResponseField>

<ResponseField name="sort" type="array">
  Configured sorting options (up to 3).
</ResponseField>

### Filter facets

Each entry under `filter` describes one filter's available options under the current query. Every option carries `option`, `value`, `count`, `selected`, and `disabled` — enough for your UI to render checkboxes, dropdowns, or sliders without extra requests.

```json theme={"theme":"css-variables"}
{
  "filter": {
    "activity": [
      { "option": "Running", "value": "Running", "selected": true,  "count": 42,  "disabled": false },
      { "option": "Cycling", "value": "Cycling", "selected": false, "count": null, "disabled": false }
    ]
  }
}
```

By default, filters are AND-combined and `count` / `disabled` reflect that assumption. When a filter is applied as an OR group, only selected options get a real count — non-selected options return `count: null` so your UI can keep them selectable without showing a misleading number.

### Aggregations

For each filter field, `aggregation` returns `result` (matching the current query) and `total` (across all items). Numeric fields include `min`, `max`, `avg`, `sum`, `total`; string fields include only `total`. Disable aggregations on individual filter fields to reduce response size.

## API Playground

<Note>Preview — the API Playground is in early access. It runs against your live backend today, but the UI and feature set are still settling before general availability. [Reach out](mailto:support@frontic.com) if you want to try it.</Note>

Open the playground from any listing's detail page to test queries against real data without writing code. The listing playground gives you a full visual interface for the query layer.

<Screenshot name="api-builder/playground-listing" caption="API Playground for a Search Listing — parameters, filters, sorting, pagination, and response" alt="API Playground dialog for a Search Listing showing parameter inputs, visual filter builder with AND/OR groups, sort and pagination controls on the left, and JSON response with status, timing, and size badges on the right" view="modal" />

<Frame caption="API Playground for a Search Listing — parameters, filters, sorting, pagination, and response">
  <img src="https://mintcdn.com/frontic/YiN8HmiGFMy2ycGP/images/api-builder/playground-listing-light.png?fit=max&auto=format&n=YiN8HmiGFMy2ycGP&q=85&s=0469727e1012fa3d0d1c7a0176d51c14" className="dark:hidden block mx-auto mt-5 mb-5" style={{ maxWidth: "480px" }} alt="API Playground dialog for a Search Listing showing parameter inputs, visual filter builder with AND/OR groups, sort and pagination controls on the left, and JSON response with status, timing, and size badges on the right" width="2304" height="1532" data-path="images/api-builder/playground-listing-light.png" />

  <img src="https://mintcdn.com/frontic/YiN8HmiGFMy2ycGP/images/api-builder/playground-listing-dark.png?fit=max&auto=format&n=YiN8HmiGFMy2ycGP&q=85&s=611165ee98b0faee329a0c7f039597c2" className="hidden dark:block mx-auto mt-5 mb-5" style={{ maxWidth: "480px" }} alt="API Playground dialog for a Search Listing showing parameter inputs, visual filter builder with AND/OR groups, sort and pagination controls on the left, and JSON response with status, timing, and size badges on the right" width="2304" height="1532" data-path="images/api-builder/playground-listing-dark.png" />
</Frame>

**What you can do:**

* **Fill parameters** — each listing parameter gets its own typed input field, pre-filled with defaults where available
* **Pick a release stage** — run the request against `develop`, `preview`, or `public`. Preview and public only appear when those environments exist on the project
* **Paginate** — page and limit steppers that sync with the response. If you exceed the last page, the playground auto-clamps
* **Search** — type a search query and see how your searchable fields respond
* **Sort** — pick a sort field and direction from the configured options
* **Build filters visually** — a filter builder that supports AND/OR groups matching your configured filter options. After the first request, facet values from the response are loaded into the filter inputs so you can pick from real data
* **Switch context** — pick **Domain** to send a `contextDomain` and let Frontic resolve the matching context, or **Key** to send an explicit `contextKey`
* **Inspect the response** — status, response time, and payload size are shown alongside the body so you can spot performance issues. The full JSON response is browseable and copyable
* **Copy code snippets** — auto-generated from your current configuration, ready to paste into your project
* **Edit raw JSON** — switch to the raw tab to craft custom request payloads by hand
