> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Personalized catalogs

> Let each B2B buyer access only the part of the catalog they can search and browse.

export const Records = () => <Tooltip tip="A record is a searchable object in an Algolia index. Each record consists of named attributes." cta="Algolia records" href="/doc/guides/sending-and-managing-data/prepare-your-data#algolia-records">
    records
  </Tooltip>;

Business-to-business (B2B) catalogs often need to control access to products, prices, or terms.
Different users should only see the data they're allowed to access,
typically based on their company account or role.

With Algolia, you can add an entitlement attribute to your <Records />,
for example `visible_by`, and use it in filters to restrict search results.
For example, the filter `visible_by:group_1` returns only records accessible to that group.
Generate secured API keys on your backend with these filters embedded so users can't modify or remove them in search requests.

## Common entitlement patterns

Sellers often create a public catalog for users who aren't signed in.
They can also create a custom catalog for each buyer account.
In B2B, a buyer account usually represents a company and can include multiple users with different roles and permissions.

Your search and browse strategy should support:

* **Per-account entitlement policies.**
  Each signed-in user can only search and browse the catalog available to their company account,
  including the products, pricing, and order quantities defined for that buyer.

* **User-level entitlement policies.**
  Each signed-in user can only search, browse, and interact with the catalog according to the roles and permissions defined by the buyer account administrator.

## Restrict catalog access with secured API keys

Use secured API keys to restrict each user's searches to the records their buyer account or role can access.
Store entitlement values in your records, for example in a `visible_by` attribute,
and generate the secured API key on your backend with filters that match the authenticated user's entitlements.

```mermaid actions={false} theme={"system"}
flowchart TD
    buyer["B2B buyer"]

    subgraph app["Your app"]
        direction TB
        auth["Authenticate the user"]
        rules["Determine allowed visible_by values"]
        key["Generate secured API key with filters"]
    end

    subgraph algolia["Algolia"]
        direction TB
        index["Product catalog index"]
        results["Only matching records returned"]
    end

    buyer -->|"Sign in"| auth
    auth --> rules
    rules --> key
    key -->|"Search with secured API key"| index
    index --> results
    results --> buyer
```

### Set up secured API keys

<Steps>
  <Step title="Prepare your records and index">
    Add an entitlement attribute to each record, such as `visible_by`,
    and add it to the index's [`attributesForFaceting`](/doc/api-reference/api-parameters/attributesForFaceting) so you can filter results by buyer account or access group.

    ```jsonc JSON icon=braces theme={"system"}
    {
      "objectID": "product-123",
      "visible_by": ["company-1", "company-3"],
      // Other attributes
    }
    ```
  </Step>

  <Step title="Generate and return a secured API key on your backend">
    Authenticate the user in your app and determine their buyer account or other entitlement group.
    Then generate a secured API key with filters that match that user's entitlements and return it from a backend endpoint.
    For example, using [`express`](https://expressjs.com/):

    ```js JavaScript icon=code theme={"system"}
    const express = require("express");
    const app = express();

    app.get("/api-key", (_, res) => {
      const securedApiKey = client.generateSecuredApiKey({
        parentApiKey: "ALGOLIA_SEARCH_API_KEY",
        restrictions: {
          filters: "visible_by:COMPANY_ID",
        },
      });

      res.send({ apiKey: securedApiKey });
    });
    ```
  </Step>

  <Step title="Use the secured API key in the frontend">
    After the user signs in,
    your frontend requests the secured API key from your backend and uses it for search requests:

    ```js JavaScript icon=code theme={"system"}
    import algoliasearch from "algoliasearch/lite";
    // Fetch the secured API key from your backend
    async function getSecuredApiKey() {
      const response = await fetch("BACKEND_URL/api-key");
      const data = await response.json();
      return data.apiKey;
    }
    // Create a search client using the secured API key
    async function createSearchClient() {
      const apiKey = await getSecuredApiKey();
      return algoliasearch("ALGOLIA_APPLICATION_ID", apiKey);
    }
    // Usage
    const client = await createSearchClient();
    ```

    Search requests made with this key only return records that match the current user's entitlement filters.
  </Step>
</Steps>

<Note>
  If your entitlement attribute, such as `visible_by`, contains sensitive access information,
  hide it from search responses with [`unretrievableAttributes`](/doc/guides/security/api-keys/how-to/user-restricted-access-to-data#make-sensitive-attributes-inaccessible).
</Note>

## See also

* [User-restricted access to data](/doc/guides/security/api-keys/how-to/user-restricted-access-to-data)
* [Inline the API key](/doc/guides/building-search-ui/going-further/api-keys-security/js#inline-the-api-key)
