# Configure and render facets Facets let catalog configuration drive the storefront's filter controls. Admin defines which dimensions to expose. Storefront returns the values and counts for the current product result context. Your UI uses the returned `queryField` to send a selected value back as a filter. ## 1. Configure a Brand facet Use an Admin credential with facet configuration permissions. Check existing facets before creating a duplicate. Admin API ```graphql mutation CreateBrandFacet($input: FacetCreateInput!) { facetCreate(input: $input) { facet { id name association field { kind valueSelectionMode } } errors { __typename ... on UserError { message } } } } ``` Variables ```json { "input": { "name": "Brand", "association": "PRODUCT", "field": { "kind": "VENDOR", "valueSelectionMode": "AUTOMATIC", "excludedValues": [] } } } ``` `PRODUCT` associates the facet with product results. Use `PRODUCT_VARIANT` for variant results. `AUTOMATIC` discovers catalog values, with optional exclusions. `MANUAL` uses an explicit `values` list. Choose one mode deliberately and use `valueOrder` when you need a preferred presentation order. ## 2. Choose a supported field kind | Kind | Configuration or display | | --- | --- | | `VENDOR` or `TAG` | Discrete product labels | | `ATTRIBUTE` | Requires the intended `attributeId` | | `METAFIELD` | Requires a supported public definition and its namespace/key | | `AVAILABILITY` | Purchase-availability filter | | `PRICE` | Contextual minimum and maximum amounts | The owner and association must be valid for the selected kind. Price and availability facets do not use the discrete-value selection and ordering settings. Use [FacetFieldInput](/api/admin-graphql/inputs/facet-field-input) for the exact combinations. ## 3. Read with the product result Storefront API ```graphql query CatalogFacets($storeId: ID!, $currency: String!, $query: String) { products(first: 20, storeId: $storeId, priceCurrency: $currency, query: $query) { nodes { id name } facets { name field queryField values { name count } } pageInfo { hasNextPage endCursor } } } ``` Variables ```json { "storeId": "", "currency": "EUR", "query": null } ``` Add the same price channel, country, locale, and customer context your product grid requires. Render the returned label and values. Keep selected values as field/value pairs and combine them using [search syntax](/concepts/query-language). Never derive an attribute's search field from its display label. ## 4. Treat price bounds differently For a `PRICE` facet, values named `min` and `max` carry amounts in their `count` field. Those amounts use integer minor currency units. For ordinary discrete values, `count` is a matching-result count. Use the facet kind to choose the interpretation. Keep currency and other price context unchanged when applying a range. Refresh products and facets together after selection, and reset pagination. ## Verify Test a value containing spaces, an excluded value, a selected value with no matches, and a market change. Confirm the chosen filter uses the returned `queryField` and that a price bound is formatted as money rather than a product count. See [Add search and filters](/guides/storefront/search-and-filters) for URL state and overlapping-request handling.