# Personalize with Shopper Context

With Shopper Context, you can personalize shopping experiences by tailoring your promotions, pricing, product recommendations, and content delivered to your site based on shopper behavior. For example, if shoppers visit your site from a mobile device, offer them a 10% discount.

The hook named `useUpdateShopperContext` is used to set the Shopper Context in a [Progressive Web App (PWA) Kit](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/getting-started.md) site. The default implementation of Shopper Context in PWA Kit is a demonstration of personalization capabilities. In the [demo implementation](#demo-implementation-of-shopper-context) described in this guide, we use query parameters to activate a personalization scheme that changes product listing page (PLP) content and promotions. Extend our implementation with custom code to match your own personalization strategy.

This guide explains our demo implementation of Shopper Context and how to configure and extend it to power the personalization strategy for your PWA Kit site. The functionality described in this guide isn’t supported in a [hybrid storefront](/docs/commerce/b2c-commerce/guide/hybrid-implementation.md).

We recommend testing personalization in a non-production environment before deploying your changes to production. You can also preview your personalization using [Storefront Preview](/docs/commerce/b2c-commerce/guide/storefront-preview.md).

Before running the commands in this guide, replace any placeholders with actual values. Placeholders are formatted like this: `$PLACEHOLDER`.

## Sample Usage

This video shows an example of how to personalize content and promotions with the demo implementation of Shopper Context.

::video{src="tRLVE69bmVyFsNAWv4LSfo" title="Shopper Context in PWA Kit" type="vidyard"}

## Prerequisites

To use personalization with Shopper Context:

- Build your site with:
  - The [Retail React App template](https://github.com/SalesforceCommerceCloud/pwa-kit/blob/develop/packages/template-retail-react-app/README.md)
  - Retail React App version 5.0.0 or later
- Have the Account Manager role of Business Manager Administrator. If you don’t have this role, ask your Account Manager Administrator to assign it to you. See [Managing Account Manager for Salesforce B2C Commerce Users](https://help.salesforce.com/s/articleView?id=000391212\&type=1).
- If you haven’t done so already, set up [Authorization for Shopper APIs](https://developer.salesforce.com/docs/commerce/commerce-api/guide/authorization-for-shopper-apis.md).
- Set up your site based on the types of personalization that you want to use. For example, set up [customer groups](https://help.salesforce.com/s/articleView?id=cc.b2c_using_dynamic_customer_groups_for_active_merchandising.htm\&type=5) in Business Manager to apply rules for personalized pricing, products, or promotions.

## Configure Shopper Context

### 1. Create a SLAS Private Client

- In the Shopper Login and API Access (SLAS) Admin UI, create a SLAS private client. See [Create a SLAS Client](https://developer.salesforce.com/docs/commerce/commerce-api/guide/authorization-for-shopper-apis.md#create-a-slas-client).

### 2. Enable Shopper Context and Hooks

In Business Manager:

- Enable Shopper Context. See [Set and Retrieve Shopper Context](https://developer.salesforce.com/docs/commerce/commerce-api/guide/shopper-context-api.md#set-and-retrieve-shopper-context).
- Complete these [Hooks Prerequisites](https://developer.salesforce.com/docs/commerce/commerce-api/guide/extensibility_via_hooks.md?\_ga=2.255637128.1234409611.1725201953-590114715.1724343723#hooks-prerequisites).

### 3. Upload the shopper_context_hooks Cartridge

The `shopper_context_hooks` cartridge acts as an allowlist to ensure that only the context you want to use for personalization campaigns can be set from the client. In Business Manager:

- Add `shopper_context_hooks` to your site’s cartridge path. This step ensures site security by preventing unauthorized members of your site development team from setting all Shopper Context scopes.
  - Go to **Administration > Sites > Manage Sites**.
  - Select the site where you want to use this cartridge. Example site identifier: `RefArch`.
  - Click the **Settings** tab.
  - In the Cartridges field, add the new cartridge path `shopper_context_hooks`. Add the new cartridge path before the path for `app_storefront_base`.
    For example: `shopper_context_hooks:app_storefront_base`
- Install and upload the cartridge.

  - Clone the [Shopper Context hooks repository](https://github.com/SalesforceCommerceCloud/shopper_context_hooks). The name of the top-level directory is `shopper_context_hooks`.

  - To install package dependencies, from the `shopper_context_hooks` directory, run:

    `npm install`

  - Configure client IDs by updating `CLIENT_REGISTRY` in `cartridges/shopper_context_hooks/cartridge/scripts/config/clientRegistry.js`

  - Create a `dw.json` file in the `shopper_context_hooks` directory. Replace the `$` strings in this example with actual values or set the corresponding environment variables.

  ```jsx
  {
    "hostname": "$HOST.demandware.net",
    "username": "$USERNAME",
    "password": "$PASSWORD",
    "code-version": "$VERSION"
  }
  ```

  - From the `shopper_context_hooks` directory, run:

    `npm run uploadCartridge`

For more information about uploading the cartridge, see [Upload Code for Storefront Reference Architecture (SFRA)](https://developer.salesforce.com/docs/commerce/sfra/guide/b2c-build-sfra.md#upload-code-for-sfra).

### 4. Configure Custom Site Preferences

Configure the client registry by adding a custom site preference. To do so, import the `system-objecttype-extensions.xml` in Business Manager.

- Go to **Administration** > **Site Development** > **Import & Export**.
- Under **Import & Export Files**, click **Upload**.
- Click **Choose File**.
- Go to `meta/meta`.
- Select `system-objecttype-extensions.xml`.
- Click **Upload**.
- After the file is uploaded, click **Back**.
- Under **Meta Data**, click **Import**.
- Select `system-objecttype-extensions.xml` and click **Next**.
- After the file is validated, click **Import**.

### 5. Update the shopper_context_hooks Cartridge CLIENT_REGISTRY from Site Preferences

To update your configuration, in Business Manager:

- Go to **Merchant Tools** > **Site Preferences** > **Custom Preferences** > **Shopper Context Hooks Preferences**.
- Update the Client Registry field with a JSON configuration. Enter your client ID that you set up in step 1 and the Shopper Context keys that the client can set. You can enter any of the keys available in the [ShopperContext type](https://developer.salesforce.com/docs/commerce/commerce-api/references/shopper-context?meta=type%3AShopperContext). For client IDs that require permissions to set all Shopper Context keys, such as the [client ID used for Storefront Preview](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/storefront-preview.md), use the key `all`.

In this example, we set Shopper Context keys for two different client IDs.

- Requests from client ID `aaaaaaaa-8536-4a39-acbb-8e7f1759f901` can set only the 3 specified keys in Shopper Context.
- Requests from client ID `bbbbbbbb-b5e9-efbc-42f6-584f60fd54ff` can set all keys in Shopper Context.

```json
{
  "aaaaaaaa-8536-4a39-acbb-8e7f1759f901": ["sourceCode", "geoLocation", "deviceType"],
  "bbbbbbbb-b5e9-efbc-42f6-584f60fd54ff": ["all"]
}
```

### 6. Add the Shopper Context Scope

- Add this Shopper Context scope to the SLAS Private Client: `sfcc.shopper-context.rw`. See [Create a SLAS Client](https://developer.salesforce.com/docs/commerce/commerce-api/guide/authorization-for-shopper-apis.md#create-a-slas-client).

## Demo Implementation of Shopper Context

Our demo of Shopper Context uses the `sourceCode` set through a query parameter to trigger content changes on a PLP and new promotions for a specific customer group. You can see the demo in action on a PLP by adding `&sourcecode=instagram` to the URL.

In our demo we utilize the `useUpdateShopperContext` hook to trigger a personalization campaign. In your project, add or remove Shopper Context query parameters in the `SHOPPER_CONTEXT_SEARCH_PARAMS` constant in `app/constants.js` to achieve your own personalizations triggered by query parameters.

For example, if you added [custom attributes](https://help.salesforce.com/s/articleView?id=cc.b2c_using_session_custom_attributes.htm\&type=5) that you want to be set using query parameters, include them as custom query parameters in `app/constants.js`. In this example, we add these parameters: `deviceType` and `storeId`.

```jsx
export const SHOPPER_CONTEXT_SEARCH_PARAMS = {
   // These are the default query parameters.
    sourceCode: {paramName: 'sourceCode'},
    geoLocation: {
        city: {paramName: 'city'},
        country: {paramName: 'country'},
        countryCode: {paramName: 'countryCode'},
        latitude: {paramName: 'latitude', type: SHOPPER_CONTEXT_FIELD_TYPES.DOUBLE},
        longitude: {paramName: 'longitude', type: SHOPPER_CONTEXT_FIELD_TYPES.DOUBLE},
        metroCode: {paramName: 'metroCode'},
        postalCode: {paramName: 'postalCode'},
        region: {paramName: 'region'},
        regionCode: {paramName: 'regionCode'}
    },
    // These are examples of custom query parameters that you can optionally add.
    customQualifiers: {
        deviceType: {paramName: 'deviceType'}
    },
    assignmentQualifiers: {
        storeId: {paramName: 'storeId'}
    }
}, // More code here...
```

## Extend Shopper Context

Optionally, you can add personalization beyond what's in the [Demo Implementation of Shopper Context](#demo-implementation-of-shopper-context). For example, you can personalize content based on a shopper’s geolocation.

In this sample code, we get a shopper's geolocation. After you get the geolocation, you can apply your chosen personalization. For example:

- For New York, USA: 20% discount on women's tops.
- For Boston, USA: 15% discount on women's tops.

```jsx
// ... Default imports in the hook
import {useEffect, useState} from 'react'

export const useUpdateShopperContext = () => {
    // ... Default code in the hook
    const [location, setLocation] = useState({latitude: null, longitude: null})

     // Get the latitude and longitude of the shopper's geolocation using the browser's navigator.geolocation API.
    const fetchLocation = () => {
        if (typeof navigator !== 'undefined' && navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(
                (position) => {
                    setLocation({
                        latitude: position.coords.latitude,
                        longitude: position.coords.longitude
                    })
                },
                (err) => {
                    console.error(err.message) // Handle errors gracefully
                },
                {
                    enableHighAccuracy: true, // Try to get the most accurate location
                    timeout: 10000, // Time in milliseconds before timing out
                    maximumAge: 60000 // Cache the location for 1 minute
                }
            )
        } else {
            console.error('Geolocation is not supported by this browser.')
        }
    }

    fetchLocation()

    // Update the Shopper Context when the latitude and/or longitude changes.
    useEffect(() => {
        if (location.latitude && location.longitude) {
            const newShopperContext = {
                geoLocation: {
                    latitude: location.latitude,
                    longitude: location.longitude
                }
            }
            handleShopperContextUpdate(shopperContext, newShopperContext)
        }
    }, [location.latitude, location.longitude])
}
```

## Troubleshoot Shopper Context

This section provides a suggested solution for a common error that you can encounter while using Shopper Context.

### Incorrect or Missing Personalization

**Potential Cause:** Personalization in Business Manager isn’t configured correctly.

**Suggested Solution:** Ensure that the context trigger you set is assigned to a personalization campaign in Business Manager.

## See Also

- [Shopper Context API Documentation](https://developer.salesforce.com/docs/commerce/commerce-api/guide/shopper-context-api.md)
- [Personalize with Cookies](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/personalize-with-cookies.md)
- [Conditional Rendering](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/maximizing-your-cache-hit-ratio.md#conditional-rendering)
- [Integrate Page Designer with PWA Kit](/docs/commerce/b2c-commerce/guide/page-designer.md)
