Skip to main content
POST
/
{collection_handle}
/
facets
Facets API: Get Collection Facets
curl --request POST \
  --url https://app.uselayers.com/api/storefront/v1/{collection_handle}/facets \
  --header 'Accept: <accept>' \
  --header 'Content-Type: <content-type>' \
  --header 'X-Storefront-Access-Token: <x-storefront-access-token>' \
  --data '
{
  "facets": [
    "<string>"
  ],
  "retrieveFacetCount": true,
  "includeFacetRanges": true,
  "filter_group": {}
}
'
import requests

url = "https://app.uselayers.com/api/storefront/v1/{collection_handle}/facets"

payload = {
"facets": ["<string>"],
"retrieveFacetCount": True,
"includeFacetRanges": True,
"filter_group": {}
}
headers = {
"X-Storefront-Access-Token": "<x-storefront-access-token>",
"Content-Type": "<content-type>",
"Accept": "<accept>"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
const options = {
method: 'POST',
headers: {
'X-Storefront-Access-Token': '<x-storefront-access-token>',
'Content-Type': '<content-type>',
Accept: '<accept>'
},
body: JSON.stringify({
facets: ['<string>'],
retrieveFacetCount: true,
includeFacetRanges: true,
filter_group: {}
})
};

fetch('https://app.uselayers.com/api/storefront/v1/{collection_handle}/facets', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));
<?php

$curl = curl_init();

curl_setopt_array($curl, [
CURLOPT_URL => "https://app.uselayers.com/api/storefront/v1/{collection_handle}/facets",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'facets' => [
'<string>'
],
'retrieveFacetCount' => true,
'includeFacetRanges' => true,
'filter_group' => [

]
]),
CURLOPT_HTTPHEADER => [
"Accept: <accept>",
"Content-Type: <content-type>",
"X-Storefront-Access-Token: <x-storefront-access-token>"
],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
package main

import (
"fmt"
"strings"
"net/http"
"io"
)

func main() {

url := "https://app.uselayers.com/api/storefront/v1/{collection_handle}/facets"

payload := strings.NewReader("{\n \"facets\": [\n \"<string>\"\n ],\n \"retrieveFacetCount\": true,\n \"includeFacetRanges\": true,\n \"filter_group\": {}\n}")

req, _ := http.NewRequest("POST", url, payload)

req.Header.Add("X-Storefront-Access-Token", "<x-storefront-access-token>")
req.Header.Add("Content-Type", "<content-type>")
req.Header.Add("Accept", "<accept>")

res, _ := http.DefaultClient.Do(req)

defer res.Body.Close()
body, _ := io.ReadAll(res.Body)

fmt.Println(string(body))

}
HttpResponse<String> response = Unirest.post("https://app.uselayers.com/api/storefront/v1/{collection_handle}/facets")
.header("X-Storefront-Access-Token", "<x-storefront-access-token>")
.header("Content-Type", "<content-type>")
.header("Accept", "<accept>")
.body("{\n \"facets\": [\n \"<string>\"\n ],\n \"retrieveFacetCount\": true,\n \"includeFacetRanges\": true,\n \"filter_group\": {}\n}")
.asString();
require 'uri'
require 'net/http'

url = URI("https://app.uselayers.com/api/storefront/v1/{collection_handle}/facets")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["X-Storefront-Access-Token"] = '<x-storefront-access-token>'
request["Content-Type"] = '<content-type>'
request["Accept"] = '<accept>'
request.body = "{\n \"facets\": [\n \"<string>\"\n ],\n \"retrieveFacetCount\": true,\n \"includeFacetRanges\": true,\n \"filter_group\": {}\n}"

response = http.request(request)
puts response.read_body
POST /storefront/v1/summer-collection/facets

{
  "facets": ["vendor", "product_type", "price_range"],
  "retrieveFacetCount": true,
  "includeFacetRanges": true
}
{
  "facets": {
    "vendor": {
      "Nike": 45,
      "Adidas": 30,
      "New Balance": 25,
      "Puma": 20,
      "Reebok": 15,
      "Vans": 15
    },
    "product_type": {
      "Shoes": 80,
      "Apparel": 50,
      "Accessories": 20
    }
  },
  "facetRanges": {
    "price_range": {
      "min": 29.99,
      "max": 249.99
    }
  },
  "filters": {}
}

Authorization

X-Storefront-Access-Token
string
required
Token-based authentication header in the form of <YOUR_LAYERS_TOKEN>.

Headers

Content-Type
string
default:"application/json"
required
Accept
string
default:"application/json"
required

Path parameters

collection_handle
string
required
The handle of the collection to retrieve facets for.

Body

facets
string[]
Facets to be included. Accepts both exact facet codes (e.g., "vendor", "options.Size") and wildcard patterns (e.g., "options.*", "metafields.product.*").Wildcard patterns expand to all matching attribute codes. For example, "options.*" expands to all option facets like "options.Size" and "options.Color". Wildcards must match at least one attribute code to be valid.Examples:
// Exact facet codes
"facets": ["vendor", "options.Size", "options.Color"]

// Wildcard pattern
"facets": ["options.*"]

// Mixed exact and wildcard
"facets": ["vendor", "options.*", "metafields.product.*"]
retrieveFacetCount
boolean
If the count of each facet value should be calculated
includeFacetRanges
boolean
If you want a min/max range for numeric facets such as price.
filter_group
object
Refer to our dedicated Filter Expressions guide to learn more about filter expressions.

Response

This endpoint returns facet metadata only — it does not return product results, pagination fields, or an attributionToken. If you need products alongside facets, use the Browse API with retrieveFacetCount enabled instead.
facets
object
Object whose keys are facet attribute codes and whose values are objects mapping each facet value to its result count. Only returned when retrieveFacetCount is true.Counts are scoped to the visibility of the active shopping channel, so they always match the number of products a shopper can actually see in the collection for that channel. Products that are not published to the requester’s channel, are B2B-only, or are hidden by a combined-listing role are excluded from every bucket. When the request is a mobile app request but the store does not have an app sales channel configured, counts fall back to the web channel.
facetRanges
object
Object whose keys are facet attribute codes and whose values are objects with min and max numeric properties. Only returned when includeFacetRanges is true.Ranges are computed only over products visible on the active shopping channel. A numeric range — for example, a price slider’s min and max — cannot come from a product the shopper cannot see.
filters
object
Echo of the filter group expressions that were applied when computing the counts. Useful for verifying that the request’s filter_group was interpreted as expected.

When to use

Use this endpoint when you need facet data without fetching product results. Common scenarios include:
  • Pre-loading filter options: Fetch available filter values before the user starts browsing
  • Sidebar filters: Build filter UIs that show available options and counts independently of the product grid
  • Reducing payload size: Avoid fetching full product data when you only need facet information
For combined product results and facets in a single request, use the Browse API with retrieveFacetCount enabled instead.
POST /storefront/v1/summer-collection/facets

{
  "facets": ["vendor", "product_type", "price_range"],
  "retrieveFacetCount": true,
  "includeFacetRanges": true
}
{
  "facets": {
    "vendor": {
      "Nike": 45,
      "Adidas": 30,
      "New Balance": 25,
      "Puma": 20,
      "Reebok": 15,
      "Vans": 15
    },
    "product_type": {
      "Shoes": 80,
      "Apparel": 50,
      "Accessories": 20
    }
  },
  "facetRanges": {
    "price_range": {
      "min": 29.99,
      "max": 249.99
    }
  },
  "filters": {}
}