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

# Search & Filtering

> Search, filter, and sort products and other resources via the Store API

export const Since = ({version, from}) => {
  const knownPrevious = {
    '5.0': '4.10',
    '6.0': '5.4'
  };
  const previous = (from ?? knownPrevious[version]) ?? (() => {
    const [major, minor] = version.split('.').map(Number);
    if (Number.isNaN(major) || Number.isNaN(minor) || minor < 1) {
      throw new Error(`<Since version="${version}" />: cannot derive previous version automatically. ` + `Pass an explicit "from" prop, e.g. <Since version="${version}" from="X.Y" />.`);
    }
    return `${major}.${minor - 1}`;
  })();
  return <Tooltip tip={`Available since Spree ${version}+.`} cta="Upgrade instructions" href={`/developer/upgrades/${previous}-to-${version}`}>
      <Badge icon="lock">Spree {version}+</Badge>
    </Tooltip>;
};

## Overview

Spree provides powerful search, filtering, and sorting capabilities for products and other resources. The Store API supports:

* Full-text search across product names, descriptions, and SKUs
* Attribute-based filtering (price range, availability, stock status)
* Category and taxon filtering
* Faceted search with filter counts
* Flexible sorting options

## Product Search

Use the `search` parameter for full-text search across product fields:

<CodeGroup>
  ```typescript SDK theme={"theme":"night-owl"}
  const { data: products } = await client.products.list({
    search: 'tote bag',
    limit: 12,
  })
  ```

  ```bash cURL theme={"theme":"night-owl"}
  curl 'https://api.mystore.com/api/v3/store/products?q[search]=tote+bag&limit=12' \
    -H 'Authorization: Bearer pk_xxx'
  ```
</CodeGroup>

## Filtering Products

### By Price Range

<CodeGroup>
  ```typescript SDK theme={"theme":"night-owl"}
  const { data: products } = await client.products.list({
    price_gte: 20,
    price_lte: 100,
  })
  ```

  ```bash cURL theme={"theme":"night-owl"}
  curl 'https://api.mystore.com/api/v3/store/products?q[price_gte]=20&q[price_lte]=100' \
    -H 'Authorization: Bearer pk_xxx'
  ```
</CodeGroup>

### By Availability

<CodeGroup>
  ```typescript SDK theme={"theme":"night-owl"}
  const { data: products } = await client.products.list({
    in_stock: true,
  })
  ```

  ```bash cURL theme={"theme":"night-owl"}
  curl 'https://api.mystore.com/api/v3/store/products?q[in_stock]=true' \
    -H 'Authorization: Bearer pk_xxx'
  ```
</CodeGroup>

### By Category

<CodeGroup>
  ```typescript SDK theme={"theme":"night-owl"}
  // Products in a specific category
  const { data: products } = await client.categories.products.list('clothing/shirts', {
    limit: 12,
  })

  // Or filter by category ID (includes descendants)
  const { data: products } = await client.products.list({
    in_category: 'ctg_xxx',
  })

  // Multiple categories (OR logic, checkbox filters)
  const { data: products } = await client.products.list({
    in_categories: ['ctg_shirts', 'ctg_pants'],
  })
  ```

  ```bash cURL theme={"theme":"night-owl"}
  # Products in a category
  curl 'https://api.mystore.com/api/v3/store/categories/clothing/shirts/products?limit=12' \
    -H 'Authorization: Bearer pk_xxx'

  # Filter by category ID (includes descendants)
  curl 'https://api.mystore.com/api/v3/store/products?q[in_category]=ctg_xxx' \
    -H 'Authorization: Bearer pk_xxx'

  # Multiple categories (OR logic)
  curl 'https://api.mystore.com/api/v3/store/products?q[in_categories][]=ctg_shirts&q[in_categories][]=ctg_pants' \
    -H 'Authorization: Bearer pk_xxx'
  ```
</CodeGroup>

### By Tags

<CodeGroup>
  ```typescript SDK theme={"theme":"night-owl"}
  const { data: products } = await client.products.list({
    tags_cont: 'sale',
  })
  ```

  ```bash cURL theme={"theme":"night-owl"}
  curl 'https://api.mystore.com/api/v3/store/products?q[tags_cont]=sale' \
    -H 'Authorization: Bearer pk_xxx'
  ```
</CodeGroup>

## Sorting

<CodeGroup>
  ```typescript SDK theme={"theme":"night-owl"}
  // Sort by price (low to high)
  const sorted = await client.products.list({
    sort: 'price_low_to_high',
  })

  // Available sort options:
  // price_low_to_high, price_high_to_low, newest, name_a_z, name_z_a
  ```

  ```bash cURL theme={"theme":"night-owl"}
  curl 'https://api.mystore.com/api/v3/store/products?sort=price_low_to_high' \
    -H 'Authorization: Bearer pk_xxx'
  ```
</CodeGroup>

## Product Filters (Faceted Search)

Get available filter options for building a faceted search UI. Returns option values, price ranges, and categories with counts:

<CodeGroup>
  ```typescript SDK theme={"theme":"night-owl"}
  const filters = await client.products.filters()
  // {
  //   option_types: [{ name: "size", option_values: [{ name: "Small", count: 12 }, ...] }],
  //   price_range: { min: 9.99, max: 199.99 },
  //   categories: [{ id: "ctg_xxx", name: "Clothing", count: 45 }],
  // }

  // Scoped to a specific category
  const categoryFilters = await client.products.filters({
    category_id: 'ctg_xxx',
  })
  ```

  ```bash cURL theme={"theme":"night-owl"}
  # All filters
  curl 'https://api.mystore.com/api/v3/store/products/filters' \
    -H 'Authorization: Bearer pk_xxx'

  # Scoped to a category
  curl 'https://api.mystore.com/api/v3/store/products/filters?category_id=ctg_xxx' \
    -H 'Authorization: Bearer pk_xxx'
  ```
</CodeGroup>

## Filtering Other Resources

The Store API uses query parameters prefixed with `q[]` for filtering any resource collection. Common filter predicates:

### Equality Predicates

| Predicate | Description | Example                     |
| --------- | ----------- | --------------------------- |
| `eq`      | Equals      | `q[status_eq]=active`       |
| `not_eq`  | Not equals  | `q[status_not_eq]=archived` |
| `in`      | In array    | `q[id_in][]=1&q[id_in][]=2` |

### String Predicates

| Predicate | Description               | Example                     |
| --------- | ------------------------- | --------------------------- |
| `cont`    | Contains                  | `q[name_cont]=shirt`        |
| `start`   | Starts with               | `q[name_start]=spree`       |
| `end`     | Ends with                 | `q[email_end]=@example.com` |
| `i_cont`  | Case-insensitive contains | `q[name_i_cont]=SHIRT`      |

### Comparison Predicates

| Predicate | Description           | Example                         |
| --------- | --------------------- | ------------------------------- |
| `gt`      | Greater than          | `q[price_gt]=50`                |
| `gteq`    | Greater than or equal | `q[quantity_gteq]=10`           |
| `lt`      | Less than             | `q[price_lt]=100`               |
| `lteq`    | Less than or equal    | `q[created_at_lteq]=2025-12-31` |

### NULL Predicates

| Predicate  | Description               | Example                         |
| ---------- | ------------------------- | ------------------------------- |
| `null`     | Is NULL                   | `q[deleted_at_null]=true`       |
| `not_null` | Is not NULL               | `q[published_at_not_null]=true` |
| `present`  | Is not NULL and not empty | `q[image_present]=true`         |

<Info>
  Only attributes explicitly allowed by each resource can be used for filtering. Attempting to filter on unsupported fields will be silently ignored.
</Info>

## Pagination

All list endpoints support pagination:

<CodeGroup>
  ```typescript SDK theme={"theme":"night-owl"}
  const { data: products, meta } = await client.products.list({
    page: 1,
    limit: 24,
  })
  // meta.total_count => 150
  // meta.total_pages => 7
  ```

  ```bash cURL theme={"theme":"night-owl"}
  curl 'https://api.mystore.com/api/v3/store/products?page=1&limit=24' \
    -H 'Authorization: Bearer pk_xxx'
  ```
</CodeGroup>

See [Querying](/api-reference/store-api/querying) for the full list of filtering, sorting, and pagination options.

## Search Providers <Since version="5.4" />

Spree uses a pluggable search provider architecture. The default provider uses SQL (ILIKE + Ransack). For production catalogs with 1,000+ products, we recommend switching to [Meilisearch](/integrations/search/meilisearch) for typo tolerance, relevance ranking, and faster faceted search.

```ruby theme={"theme":"night-owl"}
# config/initializers/spree.rb
Spree.search_provider = 'Spree::SearchProvider::Meilisearch'
```

No client-side or API changes are needed — the same `q[search]`, filter params, and sort options work with any provider.

See [Build a Custom Search Provider](/developer/how-to/custom-search-provider) for architecture details and how to build custom providers.

## Related Documentation

* [Products](/developer/core-concepts/products) — Product catalog and listing
* [Querying](/api-reference/store-api/querying) — API filtering, sorting, and pagination reference
* [Build a Custom Search Provider](/developer/how-to/custom-search-provider) — Step-by-step guide
* [Meilisearch Integration](/integrations/search/meilisearch) — Setup guide
