Personalization / Advanced Personalization / Implement personalization / Guides

Personalizing search facets

Facets let your users narrow down search results by using specific categories or filters. Using Advanced Personalization, you can personalize search facets to suit each user’s preferences. This approach allows users to refine their search, focusing on results that align closely with their interests.

This guide shows how to use Advanced Personalization and InstantSearch to personalize search facets.

Before you begin

This guide assumes that you’re familiar with React InstantSearch and fetching a user profile.

It also assumes that you’ve configured Advanced Personalization.

Retrieve facet values matching the user profile

Start by creating the usePersonalizedItems() function. This function helps extract a list of facets from the search response that are most relevant to the user.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { usePersonalizationProfile } from "./PersonalizationProfileContext";

function usePersonalizedItems(attribute) {
  const { affinities } = usePersonalizationProfile();
  const affinitiesMatchingAttribute = affinities.filter(
    (affinity) => affinity.name === attribute
  );
  const affinityScoreByValue = affinitiesMatchingAttribute.reduce(
    (acc, affinity) => {
      acc[affinity.value] = affinity.score;
      return acc;
    },
    {}
  );

  return {
    getPersonalizedItems: (items) => {
      return items
        .filter((item) => Boolean(affinityScoreByValue[item.value]))
        .map((item) => ({
          ...item,
          affinityScore: affinityScoreByValue[item.value],
        }))
        .sort((a, b) => b.affinityScore - a.affinityScore);
    },
  };
}

Here’s how this works:

  • Retrieve the user’s affinities. The function gets the user’s affinities from the personalization context.

  • Filter affinities. It keeps only affinities that match the specified attribute.

  • Create affinity scores. It builds a mapping of the scores for the filtered affinities.

  • Personalize facets. It exposes a function which filters, scores and sorts facets by their affinity scores in descending order.

Then, you can use the usePersonalizedItems() function in your application.

Choose a display approach

When personalizing search facets, you can either subtly guide users by prioritizing relevant facets or create a focused experience by showing only the most relevant facets. The choice depends on your user experience goals and the complexity of your facet structure.

Option 1: Sort refinement list items

The most flexible approach is to sort refinement list items based on user preferences while maintaining access to all search facets. This method subtly guides users towards relevant facets while preserving the complete capability of your search interface.

Use this approach when:

  • You want to maintain access to all facet values
  • You need to preserve existing refinement list capability
  • You want to subtly guide users while keeping all facet values available

Preview

Storefront displaying personalized search facets through sorting

Storefront displaying personalized search facets through sorting

In this example, Sony appears first despite having fewer results than other brands, reflecting the user’s affinity for this brand.

Implementation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { RefinementList } from 'react-instantsearch';

function PersonalizedSortingRefinementList(props) {
  const { getPersonalizedItems } = usePersonalizedItems(props.attribute);
  const transformItems = props.transformItems || ((items) => items);

  return (
    <RefinementList
      {...props}
      transformItems={(items, ...args) => {
        const itemsInUserAffinity = getPersonalizedItems(items);
        const affinityScores = new Map(
          itemsInUserAffinity.map((item) => [
            item.value,
            item.affinityScore || 0,
          ])
        );
        const transformedItems = [...items].sort(
          (a, b) =>
            (affinityScores.get(b.value) || 0) -
            (affinityScores.get(a.value) || 0)
        );

        return transformItems(transformedItems, ...args);
      }}
    />
  );
}

This implementation:

  • Preserves all existing functionalities of a refinement list
  • Sorts items based on user affinity scores while keeping all facet values accessible
  • Combines personalization with any custom transformations

Option 2: Create a dedicated refinement list

For a more focused approach, you can create a dedicated refinement list that displays only the facets most relevant to the user. This creates a streamlined experience by filtering out less relevant facets. You can combine this with a regular non-personalized refinement list.

Use this approach when:

  • Your facet list is long and needs significant filtering
  • User experience benefits from a focused, shorter list of options
  • You want to reduce cognitive load for users

Preview

Storefront displaying personalized search facets through filtering

Storefront displaying personalized search facets through filtering

Implementation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { RefinementList } from "react-instantsearch";

function PersonalizedRefinementList({ attribute }) {
  const { getPersonalizedItems } = usePersonalizedItems(attribute);

  return (
    <RefinementList
      limit={500}
      transformItems={(items) => {
        return getPersonalizedItems(items);
      }}
    />
  );
}

This implementation:

  • Over-fetches items to ensure a good pool of potential matches
  • Filters and sorts items based on user affinities
  • Creates a focused list of the most relevant facet values

Next steps

You can also use these strategies to personalize search facets with the <Menu> widget.

Did you find this page helpful?