Implement facets
Implement facets
A search interface often includes facets that allow the user to narrow down a query to a specific subset of result items by selecting one or more dynamic filter values. This article provides guidelines for implementing facets on your own, assuming that you can’t use the Coveo JavaScript Search Framework or the Atomic or Headless libraries in your custom search integration with the Coveo Platform.
|
|
Note
As a reference, you may want to look at the source code of the |
|
|
Prior to September 2024, these guidelines instructed users to log facet-specific |
Standard facet actions
The following table lists some actions that you may want to make available in a facet implementation.
Every action belongs to a specific Coveo Analytics event category, and each entry indicates the actionCause, eventType and eventValue values that must be logged when the action is performed.
Each entry also includes a link to the corresponding implementation guidelines.
| Facet action | Coveo Analytics event | actionCause |
eventType |
eventValue |
Implementation guidelines |
|---|---|---|---|---|---|
Select a value |
Search |
|
N/A |
N/A |
|
Un-select a value |
Search |
|
N/A |
N/A |
|
Reset selected |
Search |
|
N/A |
N/A |
|
Request more values |
Custom |
|
|
|
|
Request less values |
Custom |
|
|
|
|
Search for a value |
N/A |
N/A |
N/A |
N/A |
|
|
Note
It’s important to use the correct
|
Request and render facets
Conceptually, a facet relies on an existing field (for example, @bookauthor) to render a sorted list of facet values (for example, Ernest Hemingway, Mark Twain), each of which is accompanied by an estimated number of occurrences in the current query result set.
You can request the necessary data to render one or more facets through the facets query parameter.
Each valid object you include in the facets query parameter will populate a distinct object in the facets array of that query response body.
Most of the time, when a query is sent from a faceted search interface, you’ll want to request and render or update facets. To do so, prepare a new query. In the request body:
When the Search API returns, for each facet to render in the search interface:
Call the Usage Analytics Write API to log the corresponding search event.
In the request body, include an object containing the following key-value pairs in the facetState property for each non-idle facet value:
-
"facetType": <TYPE> -
"field": <FIELDNAME> -
"id": <ID> -
"state": <STATE> -
"value": <VALUE> -
"displayValue": <DISPLAY_VALUE>(optional) -
"facetPosition": <FACET_POSITION>(optional) -
"title": <TITLE>(optional) -
"valuePosition": <VALUE_POSITION>(optional)
where:
-
<TYPE>(string) is the facet data type (for example,specific). -
<FIELDNAME>(string) is the@-prefixed name of the field that this facet is based on (for example,@booklength). -
<ID>(string) is the unique identifier of the facet in which one or more values were toggled. Typically, this is the@-prefixed name of the field that this facet is based on (for example,@booklength). -
<STATE>(string) is the current state of the facet value (eitherauto_selectedorselected). -
<VALUE>(string) is the name of the toggled facet value (for example,Hardcover). -
<DISPLAY_VALUE>(string) is the display name of the facet value (for example,Hardcover). -
<FACET_POSITION>(integer) is the 1-based position of the facet (for example,1). -
<TITLE>(string) is the facet title (for example,Format) -
<VALUE_POSITION>(integer) is the 1-based position of the value in the facet (for example,2).
Examples of requesting and rendering facets
-
A customer accesses the Books4Fun search interface. Once loaded, the search interface retrieves and renders the Book Format and Author facets with the following request:
POST https://platform.cloud.coveo.com/rest/search/v2 HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: Bearer **********-****-****-****-************Payload (excerpt)
{ ... "q": "Doctor Sleep", "cq": "NOT @source==\"Movies4Fun\"", ... "facets": [ { "facetId": "@bookformat", "field": "bookformat", "type": "specific", "currentValues": [], ... }, { "field": "bookauthor", "facetId": "@bookauthor", "type": "specific", "currentValues": [], ... } ], ... }200 OK response body (excerpt)
{ ... "facets": [ { "facetId": "@bookformat", "field": "bookformat", "moreValuesAvailable": true, "values": [ { "value": "Hardcover", "state": "idle", "numberOfResults": 83 }, { "value": "Softcover", "state": "idle", "numberOfResults": 47 }, ... ], "indexScore": 0.435 }, { "facetId": "@bookauthor", "field": "bookauthor", "moreValuesAvailable": true, "values": [ { "value": "Charles Dickens", "state": "idle", "numberOfResults": 24 }, { "value": "Ernest Hemingway", "state": "idle", "numberOfResults": 26 }, { "value": "Mark Twain", "state": "idle", "numberOfResults": 23 }, ... ], "indexScore": 0.435 } ], ... } -
Logging a search event for this action:
POST https://myorgid.analytics.org.coveo.com/rest/ua/v15/analytics/searches?visitor=********-****-****-******** HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: Bearer **********-****-****-****-************Payload (excerpt)
[ { "actionCause": "interfaceLoad", ... "facetState": [] } ]
Toggle facet values
In a typical faceted search interface, the user can toggle (that is, select or un-select) any number of facet values to alter the facets query parameter.
When the user interacts with a facet in this way, prepare a new query.
For each facet currently displayed in the search interface, include a corresponding object in the facets query parameter:
-
Set
facetIdto the unique identifier of the facet. -
Set
typetospecific. -
If the facet is the one that was just interacted with, set
freezeCurrentValuestotrue. -
If more than the originally specified
numberOfResultsare being requested for the facet, setisFieldExpandedtotrue(see Request additional facet values). -
For each value currently displayed in the facet, include a corresponding object in the
currentValuesarray: -
Call the Search API to execute this query.
When the Search API returns, call the Usage Analytics Write API to log the corresponding search event. In the request body:
-
Set the
actionCauseproperty to: -
For each non-idle facet, include an object containing the following key-value pairs in the
facetStateproperty:-
"facetType": <TYPE> -
"field": <FIELDNAME> -
"id": <ID> -
"state": <STATE> -
"value": <VALUE> -
"displayValue": <DISPLAY_VALUE>(optional) -
"facetPosition": <FACET_POSITION>(optional) -
"title": <TITLE>(optional) -
"valuePosition": <VALUE_POSITION>(optional)
where:
-
<TYPE>(string) is the facet data type (for example,specific). -
<FIELDNAME>(string) is the@-prefixed name of the field that this facet is based on (for example,@booklength). -
<ID>(string) is the unique identifier of the facet in which one or more values were toggled. Typically, this is the@-prefixed name of the field that this facet is based on (for example,@booklength). -
<STATE>(string) is the current state of the facet value (eitherauto_selectedorselected). -
<VALUE>(string) is the name of the toggled facet value (for example,Hardcover). -
<DISPLAY_VALUE>(string) is the display name of the facet value (for example,Hardcover). -
<FACET_POSITION>(integer) is the 1-based position of the facet (for example,1). -
<TITLE>(string) is the facet title (for example,Format) -
<VALUE_POSITION>(integer) is the 1-based position of the value in the facet (for example,2).
-
-
Set other required or optional properties as needed, such as
language,originLevel1, ororiginLevel2.
When the Usage Analytics Write API returns successfully:
Interact with a facet indirectly
The Coveo JavaScript Search Framework includes components that allow users to interact with facets indirectly, such as the Breadcrumb and FieldValue components.
If you implement your own components, be sure to use the appropriate actionCause value when logging a search event after the user has indirectly toggled one or more facet values:
| Action | actionCause |
|---|---|
Select or un-select a single facet value by interacting with a query result |
|
Un-select a single facet value by interacting with breadcrumbs |
|
Clear all selected facet values by interacting with breadcrumbs |
|
Examples of toggling facet values
-
A customer is browsing products on the Books4Fun site. They select the
Hardcovervalue from the Book Format facet, which executes the following query:POST https://platform.cloud.coveo.com/rest/search/v2 HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: Bearer **********-****-****-****-************Payload (excerpt)
{ ... "q": "Doctor Sleep", "cq": "NOT @source==\"Movies4Fun\"", ... "facets": [ { "facetId": "@bookformat", "field": "bookformat", "type": "specific", "currentValues": [ { "value": "Hardcover", "state": "selected", "preventAutoSelect": false } { "value": "Softcover", "state": "idle", "preventAutoSelect": false }, ... ], "numberOfValues": 3, ... }, { "field": "bookauthor", "facetId": "@bookauthor", "type": "specific", "currentValues": [ { "value": "Ernest Hemingway", "state": "idle", "preventAutoSelect": false }, { "value": "Mark Twain", "state": "idle", "preventAutoSelect": false } ], "numberOfValues": 3, ... } ], ... "language": "en", "originLevel1": "Books4FunSearch", "originLevel2": "All", ... }200 OK response body (excerpt)
{ ... "facets": [ { "facetId": "@bookformat", "field": "bookformat", "moreValuesAvailable": true, "values": [ { "value": "Hardcover", "state": "selected", "numberOfResults": 83 }, { "value": "Softcover", "state": "idle", "numberOfResults": 47 }, ... ], "indexScore": 0.435 }, { "facetId": "@bookauthor", "field": "bookauthor", "moreValuesAvailable": true, "values": [ { "value": "Charles Dickens", "state": "idle", "numberOfResults": 24 }, { "value": "Ernest Hemingway", "state": "idle", "numberOfResults": 26 }, { "value": "Mark Twain", "state": "idle", "numberOfResults": 23 }, ... ], "indexScore": 0.435 } ], ... } -
Logging a search event for this action:
POST https://myorgid.analytics.org.coveo.com/rest/ua/v15/analytics/searches?visitor=********-****-****-******** HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: Bearer **********-****-****-****-************Payload (excerpt)
[ { "actionCause": "facetSelect", "eventType": "dynamicFacet", ... "facetState": [ { "field": "@bookformat", "id": "@bookformat", "title": "Format", "facetType": "specific", "facetPosition": 1, "value": "Hardcover", "valuePosition": 2, "displayValue": "Hardcover", "state": "selected" } ] } ]
Request additional facet values
The numberOfValues facet request parameter lets you specify the maximum number of facet values that the index may retrieve to populate the values array of a given facet object (the default value is 8).
You may also want to allow the user to autonomously request to display more values in a facet. When the user interacts with a facet in this way, prepare a new query:
-
Set the
numberOfResultsquery parameter to0. -
In the
facetsquery parameter, include thefacetobject for which the user has requested additional values. -
In the
facetobject operation, setfieldto the name of the field that the facet is based on (for example,@bookauthor). -
For each value currently displayed in the facet, include a corresponding object in the
currentValuesarray: -
Set
numberOfValuesto a higher value than the one that was specified the last time the facet was requested (for example,16). -
Set
isFieldExpandedtotrue. -
Set all of the other facet request parameters to the same values as the last time the facet was requested.
NoteAlthough this query isn’t meant to return actual result items, you should include the other search request parameters as usual. This way, it will represent the current state of the search interface, aside from
numberOfResultsbeing forcefully set to0andfacetsnot necessarily containing all of the operations required to update facets. Otherwise, the retrievedfacetsobject may not contain accurate or consistent facet values or occurrence counts. -
Call the Search API to execute this query.
When the Search API returns, call the Usage Analytics Write API to log the corresponding custom event. In the request body:
-
Set the
actionCauseproperty toshowMoreFacetResultswhen showing more results orshowLessFacetResultswhen showing less. -
Set the
eventTypeproperty todynamicFacet. -
Set the
eventValueproperty toshowMoreFacetResultswhen showing more results orshowLessFacetResultswhen showing less. -
Set other required or optional properties as needed, such as
language,originLevel1, ororiginLevel2.
When the Usage Analytics Write API returns successfully, re-render the facet as appropriate.
Examples of requesting additional facet values
-
A customer is browsing products on the Books4Fun site. They can’t find their favourite author among the currently rendered values in the Author facet, so they request to display more values. This interaction executes the following request:
POST https://platform.cloud.coveo.com/rest/search/v2 HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: Bearer **********-****-****-****-************Payload (excerpt)
{ ... "q": "Doctor Sleep", "cq": "NOT @source==\"Movies4Fun\"", "numberOfResults": 0, ... "facets": [ { "facetId": "@bookformat", "field": "bookformat", "type": "specific", "currentValues": [ { "value": "Hardcover", "state": "selected", "preventAutoSelect": false } { "value": "Softcover", "state": "idle", "preventAutoSelect": false }, ... ], "numberOfValues": 3, ... }, { "field": "bookauthor", "facetId": "@bookauthor", "type": "specific", "currentValues": [ { "value": "Ernest Hemingway", "state": "idle", "preventAutoSelect": false }, { "value": "Mark Twain", "state": "idle", "preventAutoSelect": false } ], "numberOfValues": 6, "isFieldExpanded": true, ... } ], ... "language": "en", "originLevel1": "Books4FunSearch", "originLevel2": "All", ... }200 OK response body (excerpt)
{ ... "facets": [ { "facetId": "@bookformat", "field": "bookformat", "moreValuesAvailable": true, "values": [ { "value": "Hardcover", "state": "selected", "numberOfResults": 83 }, { "value": "Softcover", "state": "idle", "numberOfResults": 47 }, ... ], "indexScore": 0.435 }, { "facetId": "@bookauthor", "field": "bookauthor", "moreValuesAvailable": true, "values": [ { "value": "Charles Dickens", "state": "idle", "numberOfResults": 24 }, { "value": "Ernest Hemingway", "state": "idle", "numberOfResults": 26 }, { "value": "Mark Twain", "state": "idle", "numberOfResults": 23 }, { "value": "Stephen King", "state": "idle", "numberOfResults": 14 }, ... ], "indexScore": 0.435 } ], ... } -
Logging a custom event for this action:
POST https://myorgid.analytics.org.coveo.com/rest/ua/v15/analytics/custom?visitor=********-****-****-******** HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: Bearer **********-****-****-****-************Payload (excerpt)
[ { "actionCause": "showMoreFacetResults", "eventType": "dynamicFacet", "eventValue": "showMoreFacetResults", ... "facetState": [ { "field": "@bookformat", "id": "@bookformat", "title": "Format", "facetType": "specific", "facetPosition": 1, "value": "Hardcover", "valuePosition": 2, "displayValue": "Hardcover", "state": "selected" } ] } ]
Perform facet search
|
|
Note
The following guidelines suggest a facet search implementation which is similar to that of the Coveo JavaScript Search Framework (that is, wildcard pattern matching as the user types). You may opt to use an entirely different approach for your own implementation. |
You may want to allow the user to look for specific facet values by typing into a dedicated search input within a facet. When the user interacts with a facet in this way, on each valid keystroke:
-
Retrieve the current value from the facet search input (for example,
a). -
Prepare a new facet search request. In the request body:
-
Set the
fieldproperty to the name of the field that the facet being searched is based on (for example,bookauthor). -
Set the
queryproperty to the-prefixed and-suffixed value that was retrieved in step 1 (for example,abecomesa). -
Set the
numberOfValuesproperty to the maximum number of matching values to retrieve through facet search (for example,4). The default value is10. -
Set other optional properties as needed, such as
ignoreValuesorcaptions.
-
-
Set all of the other facet request parameters to the same values as the last time the facet was requested.
NoteAlthough this query isn’t meant to return actual result items, you should include the other search request parameters as usual. This way, it will represent the current state of the search interface, aside from
numberOfResultsbeing forcefully set to0andfacetsnot necessarily containing all of the operations required to update facets. Otherwise, the retrievedfacetsobject may not contain accurate or consistent facet values or occurrence counts. -
Call the Search API to execute this query.
-
When the Search API returns, render the retrieved facet values using the
displayValueandcountvalues of each object in thevaluesarray in the response body.
Example of performing facet search
A customer is browsing products on the Books4Fun site. They can’t find their favourite author among the currently rendered values in the Author facet, so they begin typing the author’s name into the facet search box. This interaction executes the following request:
POST https://myorganizationid9sd8df7s.org.coveo.com/rest/search/v2/facet HTTP/1.1
Accept: application/json
Content-Type: application/json
Authorization: Bearer **********-****-****-****-************
Payload (excerpt)
{
"field": "bookauthor",
"numberOfValues": 4,
"query": "*W*"
}
200 OK response body (excerpt)
{
"values": [
{
"displayValue": "William Shakespeare",
"rawValue": "William Shakespeare",
"count": 10
},
{
"displayValue": "William Faulkner",
"rawValue": "William Faulkner",
"count": 5
},
...
],
"moreValuesAvailable": false
}