Skip to main content

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
Use the search parameter for full-text search across product fields:
const { data: products } = await client.products.list({
  search: 'tote bag',
  limit: 12,
})

Filtering Products

By Price Range

const { data: products } = await client.products.list({
  price_gte: 20,
  price_lte: 100,
})

By Availability

const { data: products } = await client.products.list({
  in_stock: true,
})

By Category

// 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'],
})

By Tags

const { data: products } = await client.products.list({
  tags_cont: 'sale',
})

Sorting

// 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
Get available filter options for building a faceted search UI. Returns option values, price ranges, and categories with counts:
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',
})

Filtering Other Resources

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

Equality Predicates

PredicateDescriptionExample
eqEqualsq[status_eq]=active
not_eqNot equalsq[status_not_eq]=archived
inIn arrayq[id_in][]=1&q[id_in][]=2

String Predicates

PredicateDescriptionExample
contContainsq[name_cont]=shirt
startStarts withq[name_start]=spree
endEnds withq[email_end]=@example.com
i_contCase-insensitive containsq[name_i_cont]=SHIRT

Comparison Predicates

PredicateDescriptionExample
gtGreater thanq[price_gt]=50
gteqGreater than or equalq[quantity_gteq]=10
ltLess thanq[price_lt]=100
lteqLess than or equalq[created_at_lteq]=2025-12-31

NULL Predicates

PredicateDescriptionExample
nullIs NULLq[deleted_at_null]=true
not_nullIs not NULLq[published_at_not_null]=true
presentIs not NULL and not emptyq[image_present]=true
Only attributes explicitly allowed by each resource can be used for filtering. Attempting to filter on unsupported fields will be silently ignored.

Pagination

All list endpoints support pagination:
const { data: products, meta } = await client.products.list({
  page: 1,
  limit: 24,
})
// meta.total_count => 150
// meta.total_pages => 7
See Querying for the full list of filtering, sorting, and pagination options.

Search Providers

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 for typo tolerance, relevance ranking, and faster faceted search.
# 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 for architecture details and how to build custom providers.