# Sitemap Implementation

The Marketing Cloud Personalization Sitemap system is a configuration-driven integration layer that executes within and is deployed by the Personalization module of the Salesforce Interactions SDK. A Sitemap is developed using the SDK to integrate with a specific site and map key business objects into the Personalization system through event capture. A Sitemap includes page type information, which can additionally include catalog items such as products, articles, content, and categories that support the ability to gauge user interest against the catalog.

:::note
For more information on the Personalization Sitemap, see [Sitemap Overview](/docs/marketing/personalization/guide/personalization-sitemap.md). For more information on the Personalization data model, see [Data Model](/docs/marketing/personalization/guide/data-modeling.md).
:::

***

**In This Article**

This article details the following topics related to the implementation of a Personalization Sitemap.

- [Sitemap Configuration Type Definitions](#sitemap-configuration-type-definitions)
  - [SiteMapConfig Type Processing](#sitemapconfig-type-processing)
  - [Global Config](#global-config)
  - [Page Types](#page-types)
    - [PageConfig](#pageconfig)
    - [CatalogConfig](#catalogconfig)
    - [CartConfig](#cartconfig)
  - [OrderConfig](#orderconfig)
  - [LineItem](#lineitem)
  - [Interaction](#interaction)
  - [CatalogObjectInteraction](#catalogobjectinteraction)
  - [CartInteraction](#cartinteraction)
  - [OrderInteraction](#orderinteraction)
    - [CatalogConfig Utility Functions](#catalogconfig-utility-functions)
  - [Default Page Config](#default-page-config)
- [Sitemap API](#sitemap-api)
  - [Resolvers](#resolvers)
  - [Utility Functions](#utility-functions)
- [Single Page App Handling](#single-page-app-handling)
- [Sitemap Localization Implementation](#sitemap-localization-implementation)
  - [Example: Setting Locale in the Global Configuration](#example-setting-locale-in-the-global-configuration)
  - [Catalog Configurations in Different Locales](#catalog-configurations-in-different-locales)
  - [Order Configuration in Different Locales](#order-configuration-in-different-locales)

***

**Example Sitemaps**

The following is a list of example Sitemaps we've created for different types of business websites that depict how you could approach designing a Sitemap for your Personalization implementation. While the JavaScript and HTML code in these example Sitemaps are only for reference purposes, they can give you a head start in developing the Sitemap for your implementation.

- [Financial services](/docs/marketing/personalization/guide/financial-services.md)
- [ecommerce](/docs/marketing/personalization/guide/ecommerce.md)
- [B2B](/docs/marketing/personalization/guide/b2b.md)

***

## Sitemap Configuration Type Definitions

A `SiteMapConfig` consists of the following three, separate configurations.

- `global`: The `global` configuration contains objects to be monitored by Personalization on all page type configuration objects, and the default page configuration (if defined) of your site.
- `pageTypes`: The `pageTypes` configuration contains objects used to detect/match each different page type to be monitored on your site.
- `pageTypeDefault`: If defined, the objects configured in `pageTypeDefault` are matched when all `PageConfig` objects in the `pageTypes` array resolve to `false`. Do remember that the `pageTypeDefault` matches this way only when the sitemap contains *at least one* validly constructed `PageConfig` object. When using the `SalesforceInteractions` namespace, an interaction must be provided for `pageTypeDefault`.

The following sections describe how the preceding Sitemap configuration types are processed and provide additional information about each configuration type.

### SiteMapConfig Type Processing

When the configuration for either a `PageConfig` object inside the `pageTypes` array or the `pageTypeDefault` matches a page on the site, the matched configuration merges with anything defined within `GlobalConfig`. Individual attributes are merged in the following manner.

- `locale` : the matched `PageConfig` or `DefaultPageConfig` takes precedence
- `contentZones`: concatenate
- `listeners`: concatenate
- `onActionEvent`: the function for the matched `PageConfig` or `DefaultPageConfig` executes first, followed by the function for the `GlobalConfig`

The result of this merge is then evaluated as expected.

```typescript
{
  global: GlobalConfig,
  pageTypeDefault: DefaultPageConfig,
  pageTypes: PageConfig[]
}
```

***

### Global Config

`GlobalConfig` defines the additional data to be tracked if a `PageConfig` or `DefaultPageConfig` matches a specific page.

```typescript
{
  locale?: string | () => string,
  contentZones?: ContentZone[],
  listeners?: Listener[],
  onActionEvent?: (event: ActionEvent) => ActionEvent
}
```

***

### Page Types

Page type configurations use a `pageTypes` array to declare how to detect that a given URL or loaded page is one of the known page types. Each page type configuration must contain properties for `name`, `action`, and `isMatch`, which declares the function used to detect that page type. Additionally, individual page type configurations can declare [Content Zones](/docs/marketing/personalization/guide/content-zones.md) representing key parts of a page designed for personalization adjustments. The configurations can also declare other event listeners for a given page type, such as an "add to cart" listener. Page types can map to more than a single page; for example, while the **Home** page is an example of a page type with only a single instance of a page, the product display page (PDP) type would have separate URLs for every product on the site, but only a single page type.

For more information on page types, refer to the [Page Types](/docs/marketing/personalization/guide/page-types.md) documentation.

#### PageConfig

`PageConfig` defines the data to be tracked for a specific page. The `PageConfig` object accepts the following fields.

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
{
  name: string, // required
  isMatch: () => boolean | () => Promise<boolean>, // required
  locale?: string | () => string,
  interaction?: Interaction,
  contentZones?: ContentZone[],
  listeners?: Listener[],
  onActionEvent?: (event: ActionEvent) => ActionEvent
}
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
{
    name: string, // required
    isMatch: () => boolean | () => Promise<boolean>, // required
    locale?: string | () => string,
    action?: string,
    itemAction?: string,
    catalog?: CatalogConfig,
    cart?: CartConfig,
    order?: OrderConfig,
    contentZones?: ContentZone[],
    listeners?: Listener[],
    onActionEvent?: (event: ActionEvent) => ActionEvent
}
```

The following table describes the fields that a `PageConfig` accepts.

| Field           | Expected Value Type                                                                 | Required? | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               | Namespace                |
| --------------- | ----------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
| `name`          | String                                                                              | **Yes**   | The page type that gets sent in the event when this configuration is evaluated. Example: Homepage, Product Detail                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | Both                     |
| `isMatch`       | `() => boolean \| Promise<boolean>`                                                 | **Yes**   | The function provided here is evaluated when the sitemap is deciding which `PageConfig` to evaluate. The sitemap only evaluates the first `PageConfig` whose `isMatch` resolves to `true`. If no `isMatch` resolves to `true`, then the `pageTypeDefault` configuration runs.                                                                                                                                                                                                                                                                                                                                                                                                             | Both                     |
| `locale`        | String                                                                              | No        | The locale of the page (for example, `en_US`). Use `locale` only if you have catalog localization enabled.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | Both                     |
| `action`        | String                                                                              | No        | The name of the action dispatched in the event when this configuration is evaluated. **Important**: Capture actions only if they’re necessary for personalization and targeting. Actions must have names that can be reused across users and sessions. If you dynamically populate action names, ensure that these names stay consistent across sessions for any user performing the action. Dynamic user information in action names can cause issues and should be avoided whenever possible. For more information and best practices on using actions, see [Best Practices For Using Actions](/docs/marketing/personalization/guide/item-actions.md#best-practices-for-using-actions). | `Evergage`               |
| `itemAction`    | String                                                                              | No        | The name of the itemAction dispatched in the event when this configuration is evaluated.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | `Evergage`               |
| `interaction`   | `Interaction`, `CatalogObjectInteraction`, `CartInteraction`, or `OrderInteraction` | No        | An object describing the interaction on the page. For more information, refer to the [Interaction](#interaction) section of this article. For more information and best practices on using actions, see [Best Practices For Using Interactions](/docs/marketing/personalization/guide/interaction-definitions.md#best-practices-for-using-interactions).                                                                                                                                                                                                                                                                                                                                  | `SalesforceInteractions` |
| `catalog`       | `CatalogConfig`                                                                     | No        | The catalog data to be captured. For more information, refer to the [CatalogConfig](#catalogconfig) section of this article.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | `Evergage`               |
| `cart`          | `CartConfig`                                                                        | No        | The cart data to be captured. For more information, refer to the [CartConfig](#cartconfig) section of this article.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | `Evergage`               |
| `order`         | `OrderConfig`                                                                       | No        | The order data to be captured. For more information, refer to the [OrderConfig](#orderconfig) section of this article.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | `Evergage`               |
| `contentZones`  | `ContentZone[]`                                                                     | No        | The content zones defined in the sitemap determine where Personalization campaigns are rendered throughout a website. Personalization templates reference these content zones for targeting within campaigns. For more information on content zones, refer to the [Content Zones](/docs/marketing/personalization/guide/content-zones.md) documentation.                                                                                                                                                                                                                                                                                                                                  | Both                     |
| `listeners`     | `Listener[]`                                                                        | No        | The event listeners to be bound when this configuration is evaluated. For more information, refer to the [Listeners](#listeners) section of this article.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | Both                     |
| `onActionEvent` | `(event: ActionEvent) => ActionEvent`                                               | No        | The `onActionEvent` function modifies the outgoing `ActionEvent`. This function runs whenever the sitemap builds an `ActionEvent` before sending it to Personalization. The sitemap builds the `ActionEvent` as a result of calling the `sendEvent` function or building a `PageConfig` array. If the GlobalConfig and a matched PageConfig array contain the `onActionEvent` function, then both functions are executed. The function in `PageConfig` is executed before executing the function in the `GlobalConfig` array.                                                                                                                                                             | Both                     |

***

#### Default Page Config

`DefaultPageConfig` defines the default page configuration to use if no other page types are matched. When using `DefaultPageConfig` with the `SalesforceInteractions` namespace, an interaction must be provided.

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
{
  name: string,
  interaction: Interaction
}
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
{
  name: string;
}
```

#### CatalogConfig

`CatalogConfig` defines the catalog data to be captured and accepts the following fields. A `catalog` object accepts the following fields.

:::important
Only available in the `SalesforceInteractions` namespace.
:::

```javascript
catalog: {
    <ItemType>: {
        _id: string | () => string | () => Promise<string | () => string> // required
        categories?: string[] | () => string[] | () => Promise<string[] | () => string[]>
        <attributes>?: value | () => value,
        relatedCatalogObjects?: { // In case you're using 'dimensions' instead of 'relatedCatalogObjects', you can continue to do so as they both function the same way.
            <relatedCatalogObject>?: string[] | () => string[] | () => Promise<string[] | () => string[]>
        },
        attributes?: {
            <attribute>?: value | () => value
        }
    }
}
```

The `ItemType` in a `CatalogConfig` is defined in the **Catalog and Profile Objects** section of the Personalization UI. An `ItemType` can refer to items such as products, content, blogs, or any other catalog object, whether built in or user-defined. The following table describes the fields that an `ItemType` array accepts.

| Field                  | Expected Value Type                                                       | Required? | Description                                                                                                                                                                                                                                                                                                                  |
| ---------------------- | ------------------------------------------------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `_id`                  | `string \| () => string \| () => Promise<string \| () => string>`         | **Yes**   | The ID of the catalog item. This field is required for an item to be tracked. **Important:** When capturing catalog items IDs, avoid capturing line break characters (`\n`). This character isn't supported in IDs of catalog items, interactions, and actions. Including line breaks in the IDs can cause issues in the UI. |
| `categories`           | `string[] \| () => string[] \| () => Promise<string[] \| () => string[]>` | No        | The categories the catalog item belongs to.                                                                                                                                                                                                                                                                                  |
| `<attributes>`         | `value \| () => value`                                                    | No        | Use this field to define standard, built-in item attributes. Examples of attributes include `_id`, `name`, `price`, and so on.                                                                                                                                                                                               |
| `relatedCatalogObject` | `string[] \| () => string[] \| () => Promise<string[] \| () => string[]>` | No        | Catalog objects can be assigned to other catalog objects to describe them in more detail. When so assigned, it is considered a related catalog object.                                                                                                                                                                       |
| `attributes`           | `value \| () => value`                                                    | No        | Custom attributes on an item, as defined in the **Catalog Setup** section of the Personalization UI.                                                                                                                                                                                                                         |

For more details on catalog items and item attributes, see [Create a Custom Catalog Object](https://help.salesforce.com/s/articleView?id=sf.mc_pers_catalog_object_custom.htm).

#### CartConfig

`CartConfig` defines the cart data to be captured. The `cart` object accepts the following fields.

:::important
Only available in the `SalesforceInteractions` namespace.
:::

```javascript
cart: {
    complete: {
        <ItemType>: LineItem[]
    }
}
```

When including a `CartConfig` in a `pageType`, ensure that it follows the following structure.

:::important
Only available in the `SalesforceInteractions` namespace.
:::

```javascript
cart: {
    complete: {
        <ItemType>: {
            lineItem: {
                _id: string[],
                price: double[],
                quantity: integer[]
            }
        }
    }
}
```

Additionally, a user's cart can be emptied by sending an event with an empty array of `LineItems`.

```javascript
{
  cart: {
    complete: {
      Product: [];
    }
  }
}
```

### OrderConfig

`OrderConfig` defines the order data to be captured. An `order` object accepts the following fields.

:::important
Only available in the `Evergage` namespace.
:::

```javascript
order: {
    <ItemType>: {
        orderId: string | () => string | Promise<string | () => string>,
        totalValue?: double | () => double | Promise<double | () => double>,
        currency?: string | () => string | Promise<string | () => string>,
        lineItems: LineItem[]
    }
}
```

### LineItem

`LineItem` represents a single item in a cart/transaction. A `LineItem` object accepts the following fields.

:::important
Only available in the `Evergage` namespace.
:::

```javascript
{
    _id: string | () => string | Promise<string | () => string>
    price: double | () => double | Promise<value | ()=> double>
    quantity: integer | () => integer | Promise<value | ()=> integer>
}
```

### Interaction

`Interaction` represents the interaction the user is taking on the page. An `Interaction` object accepts the following fields.

:::important
Only available in the `SalesforceInteractions` namespace.
:::

```javascript
{
  name: string; // required
}
```

### CatalogObjectInteraction

`CatalogObjectInteraction` is an extension of `Interaction` that accepts a `catalogObject`. A `CatalogObjectInteraction` object accepts the following fields.

:::important
Only available in the `SalesforceInteractions` namespace.
:::

```javascript
{
    name: CatalogObjectInteractionName,
    catalogObject: {
        type: string,
        id: string,
        attributes?: { [key: string]: any },
        relatedCatalogObjects?: { [catalogObjectType: string]: string[] }
    }
}
```

For all `CatalogObjectInteractions`, refer to the [CatalogObjectInteraction](/docs/marketing/personalization/guide/interaction-definitions.md#catalogobjectinteraction) documentation.

### CartInteraction

`CartInteraction` is an extension of `Interaction` that accepts information about a cart. A `CartInteraction` object accepts the following fields.

:::important
Only available in the `SalesforceInteractions` namespace.
:::

```javascript
{
    name: CartInteractionName,
    lineItem?: LineItem,
    lineItems?: LineItem[]
}
```

In a `CartInteraction`, `LineItem` accepts the following fields.

```javascript
{
    catalogObjectType: string,
    catalogObjectId: string,
    quantity: number,
    price?: number,
    currency?: string,
    attributes?: { [key: string]: any }
}
```

For all `CartInteractions`, refer to the [CartInteraction](/docs/marketing/personalization/guide/interaction-definitions.md#cartinteraction) documentation.

### OrderInteraction

`OrderInteraction` is an extension of `Interaction` that accepts information about an order. An `OrderInteraction` object accepts the following fields.

:::important
Only available in the `SalesforceInteractions` namespace.
:::

```javascript
{
    name: OrderInteractionName,
    order: {
        id: string;
        lineItems?: LineItem[];
        totalValue?: number;
        currency?: string;
        attributes?: { [key: string]: any };
    }
}
```

In an `OrderInteraction`, `LineItem` accepts the following fields.

```javascript
{
    catalogObjectType: string,
    catalogObjectId: string,
    quantity: number,
    price?: number,
    currency?: string,
    attributes?: { [key: string]: any }
}
```

For all `OrderInteractions`, refer to the [OrderInteraction](/docs/marketing/personalization/guide/interaction-definitions.md#orderinteraction) documentation.

#### CatalogConfig Utility Functions

The Personalization module of the Salesforce Interactions SDK includes the following utility function that is especially helpful for building LineItems.

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
  SalesforceInteractions.mcis.buildLineItemFromPageState(quantitySelector) => LineItem
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
  Evergage.util.buildLineItemFromPageState(quantitySelector) => LineItem
```

The preceding utility function returns a `LineItem` constructed from the data already captured on the page using the given `quantitySelector` to determine the number of items in the line item.

***

### Default Page Config

The `DefaultPageConfig` defines what data is tracked *only if* all other `PageConfig`s resolve to `false`.

The `DefaultPageConfig` accepts the following fields.

```typescript
{
    name: string, // required
    locale?: string | () => string,
    contentZones?: ContentZone[],
    listeners?: Listener[],
    onActionEvent?: (event: ActionEvent) => ActionEvent
}
```

:::note
The `DefaultPageConfig` works only when the sitemap contains *at least one* validly constructed `PageConfig` object.
:::

***

## Sitemap API

The Sitemap API is scoped on the `window` under `Evergage`.

### initSitemap

Initialize the sitemap process using the provided configuration. Events are not sent to Personalization unless this function is called.

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.initSitemap(siteMapConfig: *SiteMapConfig*) => void
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.initSitemap(siteMapConfig: *SiteMapConfig*) => void
```

### cashDom

A small library for modern browsers that provides jQuery-style syntax to wrap modern Vanilla JS features and select elements from the DOM. For more information on `Cash`, refer to the [Cash documentation](https://kenwheeler.github.io/cash/#docs).

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.cashDom(selector: *String*, context) => Cash
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.cashDom(selector: *String*, context) => Cash
```

### sendEvent

Send a custom event to Personalization.

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.sendEvent(event: *ActionEvent*)
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.sendEvent(event: *ActionEvent*)
```

### getSitemapResult

Get the current page state, including values in the configuration that have already been resolved.

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.mcis.getSitemapResult();
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.getSitemapResult()
```

***

### Listeners

Create a listener.

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.listener(bind: keyof WindowEventMap, selector: string, callback: Function): Listener;
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.listener(bind: keyof WindowEventMap, selector: string, callback: Function): Listener;
```

You can use a listener to "listen" for user actions on a page, capture information from that action, and initiate a function or action based on the captured information. Listeners are structurally similar to jQuery's event listeners.

The following are examples of simple listeners that bind a click to the banner of a website and dispatch an event to Personalization.

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.listener("click", ".header-banner", () => {
  SalesforceInteractions.sendEvent({ interaction: { name: "Banner Click" } });
});
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.listener("click", ".header-banner", () => {
  Evergage.sendEvent({ action: "Banner Click" });
});
```

The following are namespace-specific examples of listeners that capture email addresses using a custom callback function.

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.listener("submit", "form#subscribe", (e) => {
  const userEmail = SalesforceInteractions.cashDom(e.target).find("#email").val();
  if (typeof userEmail === "string" && /^.+@.+\..+$/.test(userEmail)) {
    SalesforceInteractions.sendEvent({
      interaction: {
        name: "Email Capture",
      },
      user: {
        identities: { emailAddress: userEmail },
      },
    });
  }
});
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.listener("submit", "form#subscribe", (e) => {
  const userEmail = Evergage.cashDom(e.target).find("#email").val();
  if (typeof userEmail === "string" && /^.+@.+\..+$/.test(userEmail)) {
    Evergage.sendEvent({
      action: "Email Capture",
      user: {
        attributes: { emailAddress: userEmail },
      },
    });
  }
});
```

***

### Resolvers

Resolvers return functions so that they can be invoked *after* a page has been matched. When used in a `PageConfig`, the returned functions do not need to be invoked to get the final value - the underlying sitemap code handles that logic.

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.resolvers.<resolver>
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.resolvers.<resolver>
```

`transform` functions are callbacks designed to evaluate or modify the resolved value.

```typescript
fromSelector(selector: string, transform?: (string) => string) => () => string
```

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.cashDom(selector).text();
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.cashDom(selector).text();
```

Returns the text of the first instance of the selector in the DOM.

```typescript
fromSelectorMultiple(selector: string, transform?: (string[]) => string[]) => () => string[]
```

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
[SalesforceInteractions.cashDom(selector).eq(0).text(), SalesforceInteractions.cashDom(selector).eq(1).text(), ...]
```

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
[Evergage.cashDom(selector).eq(0).text(), Evergage.cashDom(selector).eq(1).text(), ...]
```

Returns the text of all instances of the selector in the DOM in an array.

```typescript
fromSelectorAttribute(selector: string, attribute: string, transform?: (string) => string) => () => string
```

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.cashDom(selector).attr(attribute);
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.cashDom(selector).attr(attribute);
```

Returns the attribute of the first instance of the selector in the DOM.

```typescript
fromSelectorAttributeMultiple(selector: string, attribute: string, transform?: (string[]) => string[]) => () => string[]
```

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
[SalesforceInteractions.cashDom(selector).eq(0).attr(attribute), SalesforceInteractions.cashDom(selector).eq(1).attr(attribute), ...]
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
[Evergage.cashDom(selector).eq(0).attr(attribute), Evergage.cashDom(selector).eq(1).attr(attribute), ...]
```

Returns the attributes of all instances of the selector in the DOM as an array.

```typescript
fromMeta(metaName: string, transform?: (string) => string) => () => string
```

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.cashDom("meta[name='" + metaName + "']")
  .first()
  .attr("content");
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.cashDom("meta[name='" + metaName + "']")
  .first()
  .attr("content");
```

Returns the content of the first meta tag with the given meta tag name.

```typescript
fromItemProp(itemProp: string, transform?: (string) => string) => () => string
```

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.cashDom("[itemprop='" + itemProp + "']")
  .first()
  .attr("content");
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.cashDom("[itemprop='" + itemProp + "']")
  .first()
  .attr("content");
```

Returns the content of the first `itemProp` with the given `itemProp`.

```typescript
fromWindow(windowVar: string, transform?: (string) => string) => () => string
```

Returns the value from a nested object. Returns `null` if the nested object, or some object in the path, does not exist.

```typescript
fromJsonLd(path: string, transform?: any) => () => any
```

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.cashDom("script[type='application/ld+json']").first().text();
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.cashDom("script[type='application/ld+json']").first().text();
```

If the path is `null`, the first JSON-LD script is returned after being parsed into a JavaScript object. If a path is provided, then the value of the path from the parsed JavaScript object is returned.

```typescript
buildCategoryId(selector: string, startFrom?: integer, ignoreLast?: boolean, transform?: (string) => string) => () => string
```

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.cashDom(selector).eq(startFrom).text()|SalesforceInteractions.cashDom(selector).eq(startFrom+1).text()|...
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.cashDom(selector).eq(startFrom).text()|Evergage.cashDom(selector).eq(startFrom+1).text()|...
```

Returns a pipe-delimited string using the text of all instances of the selector.

```typescript
buildCategoryIdAttribute(selector: string, attribute: string, startFrom?: integer, ignoreLast?: boolean, transform?: (string) =>  string) => () => string
```

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.cashDom(selector).eq(startFrom).attr(attribute)|SalesforceInteractions.cashDom(selector).eq(startFrom+1).attr(attribute)|...
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.cashDom(selector).eq(startFrom).attr(attribute)|Evergage.cashDom(selector).eq(startFrom+1).attr(attribute)|...
```

Returns a pipe-delimited string using the given attribute of all instances of the selector.

```typescript
fromCanonical(transform?: (string) => string) => () => string
```

Returns a canonical URL, if one exists on the page.

```typescript
fromHref(transform?: (string) => string) => () => string
```

Returns the value stored in `window.location.href`

***

### Utility Functions

The Personalization module of the Salesforce Interactions SDK provides several utility functions that you can use to help parse data.

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.mcis.<util>
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.util.<util>
```

The following table describes these utility functions in detail.

| Utility Function                                                                                                       | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | Namespace  |
| ---------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| `buildLineItemFromPageState(quantitySelector: string) => LineItem`                                                     | Returns a `LineItem` constructed from the data already captured on the page, using the given `quantitySelector` to determine how many of the items are in the `lineItem`.                                                                                                                                                                                                                                                                                                                | Both       |
| `extractFirstGroup(regex: RegExp, str: string) => string`                                                              | Returns a string of the first group extracted from the provided regex.                                                                                                                                                                                                                                                                                                                                                                                                                   | Both       |
| `getFloatValue(text: string) => number`                                                                                | Returns a floating point number parsed from the provided string.                                                                                                                                                                                                                                                                                                                                                                                                                         | `Evergage` |
| `getIntegerValue(text: string) => number`                                                                              | Returns an integer number parsed from the provided string.                                                                                                                                                                                                                                                                                                                                                                                                                               | `Evergage` |
| `getLastPathComponent(url: string) => string`                                                                          | Returns the last path component for the provided URL. For example, `SalesforceInteractions.util.getLastPathComponent("https://example.example/myExamplePath.html")` returns `myExamplePath.html`.                                                                                                                                                                                                                                                                                        | `Evergage` |
| `getLastPathComponentWithoutExtension(url: string) => string`                                                          | Returns the last path component without an extension for the provided URL. For example, `SalesforceInteractions.util.getLastPathComponent("https://example.example/myExamplePath.html")` returns `myExamplePath`.                                                                                                                                                                                                                                                                        | Both       |
| `getParameterByName(name: string, url?: string) => string`                                                             | Returns the value of the provided parameter name from the provided URL. If no URL is provided, the current `location.search` of the page is used.                                                                                                                                                                                                                                                                                                                                        | Both       |
| `getPathname(url: string) => string`                                                                                   | Returns the `Pathname` of the provided URL.                                                                                                                                                                                                                                                                                                                                                                                                                                              | `Evergage` |
| `getUtagFirstForField(fieldName: string) => any`                                                                       | Returns the first value for the provided field in a `window.utag_data` object.                                                                                                                                                                                                                                                                                                                                                                                                           | `Evergage` |
| `getValueFromNestedObject(path: string, obj?: object) => any`                                                          | Returns the value from a nested object. If an object is not provided, `window` is used. Returns `null` if the nested object, or some object in the path, does not exist.                                                                                                                                                                                                                                                                                                                 | Both       |
| `qualifyUrl(unqualified: string) => string`                                                                            | Returns a qualified URL href from an unqualified relative URL path. If unqualified is null or unprovided, returns null.                                                                                                                                                                                                                                                                                                                                                                  | `Evergage` |
| `removeQueryString(url: string) => string`                                                                             | Returns a URL without query strings from the provided URL.                                                                                                                                                                                                                                                                                                                                                                                                                               | `Evergage` |
| `resolveWhenTrue.bind(trueFunc: () => any, bindId?: string, timeout?: number, checkInterval?: number) => Promise<any>` | Returns a Promise that resolves when the provided `trueFunc` evaluates to `true`.DONE If `timeout` is not provided, a 2000-ms default timeout is used. If `checkInterval` is not provided, a 100-ms default interval is used to check the trueFunc. If the timeout is reached, the check is unbound. An `unbind` function is provided under `resolveWhenTrue.getBindings()`. If a `bindId` is provided, the `unbind` function is mapped to that key, otherwise a new random key is used. | Both       |
| `resolveWhenTrue.unbind(bindId: string) => void`                                                                       | When given a `bindId` unbinds that bound `resolveWhenTrue` function.                                                                                                                                                                                                                                                                                                                                                                                                                     | Both       |
| `resolveWhenTrue.getBindings() => [key: string]: unbindFunction: ()`                                                   | Returns a map of currently bound `resolveWhenTrue` functions.                                                                                                                                                                                                                                                                                                                                                                                                                            | Both       |
| `resolveWhenTrue.clearBindings() => void`                                                                              | Clears all currently bound `resolveWhenTrue` functions.                                                                                                                                                                                                                                                                                                                                                                                                                                  | Both       |

***

## Single Page App Handling

Depending on the SDK namespace you're using, use either of the following code snippets to reinitialize the beacon and the Sitemap when using Personalization on a single-page application (SPA).

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.reinit();
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.reinit();
```

Executing the preceding code results in the following.

1. Depending on the SDK namespace you're using, dispatch a `SalesforceInteractions.CustomEvents.OnInit` or an `Evergage.CustomEvents.OnInit` event.
2. Reinitialize the beacon with the same settings as the initial page load (for example, `cookieDomain`).
3. Rerun the sitemap using the same configuration as the initial page load.
4. Send activity timing for the previous page.
5. Start activity timers for the current page.

Ensure that you wrap the reinitialization function in logic to determine when to reinitialize the beacon and sitemap. The following is a sample sitemap code that includes logic to reinitialize the beacon and sitemap when the URL changes without a full page load.

:::note
The following sitemap code examples are for illustrative purposes only. We recommend considering other ways of using the reinitialization function that better suits your specific use case, and the way your site functions.
:::

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.init().then(() => {

    const config = {
        global: {},
        pageTypes: [
            {
                name: "home",
                interaction: {
                    name: "Homepage"
                },
                isMatch: () => /home/.test(window.location.href);
            }
        ]
    };

    /*
        Check for URL change every 2 seconds. If URL has changed, reinitialize beacon and sitemap.
    */
    const handleSPAPageChange = () => {
        let url = window.location.href;
        const urlChangeInterval = setInterval(() => {
            if (url !== window.location.href) {
                url = window.location.href;
                SalesforceInteractions.reinit();
            }
        }, 2000);
    }

    handleSPAPageChange();

    SalesforceInteractions.initSitemap(config);
})
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.init().then(() => {

    const config = {
        global: {},
        pageTypes: [
            {
                name: "home",
                isMatch: () => /home/.test(window.location.href);
            }
        ]
    };

    /*
        Check for URL change every 2 seconds. If URL has changed, reinitialize beacon and sitemap.
    */
    const handleSPAPageChange = () => {
        let url = window.location.href;
        const urlChangeInterval = setInterval(() => {
            if (url !== window.location.href) {
                url = window.location.href;
                Evergage.reinit();
            }
        }, 2000);
    }

    handleSPAPageChange();

    Evergage.initSitemap(config);
})
```

***

## Sitemap Localization Implementation

The localization setting enables a single dataset to cater to a site with multiple languages and locales while leveraging the same catalog and sitemap across those languages and locales. The use of localization requires sending the locale attribute in an event.

:::important
To use catalog localizations, you must check the **Enable Localization of Catalog Metadata Based on Page Locale** setting in a catalog's settings via the Personalization UI by navigating to **Settings** > **Catalog and Profile Objects**.
:::

Locales must be set in a specific format of an [ISO 639 alpha-2](https://en.wikipedia.org/wiki/ISO\_639-1) language code, followed by an underscore, followed by an [ISO 3166 alpha-2](http://en.wikipedia.org/wiki/ISO\_3166-1\_alpha-2) country code. The following list contains examples of valid locales.

- `en_US`
- `en_AU`
- `en_CA`
- `zh_CN`
- `en_GB`
- `pt_PT`
- `en_HK`
- `zh_HK`

### Example: Setting Locale in the Global Configuration

The following is an example of a View Item event that depicts how to send an event with a locale. You can set the locale on the `global`, `pageTypeDefault`, and individual `pageTypes` configurations in the `SiteMapConfig`. You can set the locale manually in events tracked through `sendEvent` functions.

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
SalesforceInteractions.init().then(() => {
  const buildLocale = () => {
    let locale = SalesforceInteractions.CashDom("meta[type='locale']").attr("content");
    return locale;
  };

  const config = {
    global: {
      locale: buildLocale(),
    },
    pageTypeDefault: {
      name: "default",
    },
    pageTypes: [
      {
        name: "home",
        interaction: {
          name: "Homepage",
        },
        isMatch: () => {
          return window.location.pathname === "/";
        },
      },
    ],
  };

  SalesforceInteractions.initSitemap(config);
});
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
Evergage.init().then(() => {
  const buildLocale = () => {
    let locale = Evergage.CashDom("meta[type='locale']").attr("content");
    return locale;
  };

  const config = {
    global: {
      locale: buildLocale(),
    },
    pageTypeDefault: {
      name: "default",
    },
    pageTypes: [
      {
        name: "home",
        action: "Homepage",
        isMatch: () => {
          return window.location.pathname === "/";
        },
      },
    ],
  };

  Evergage.initSitemap(config);
});
```

### Catalog Configurations in Different Locales

When building catalog configurations in a sitemap, different locales can all use the same configuration. Localized attributes are all on the same item in Personalization. Therefore, when selecting which `_id` to use for a Catalog Item, or a Catalog Item's related catalog objects, ensure that you select an `_id` that does not change depending on the page's locale. Failing to do so creates extra Catalog Items and related catalog objects in the catalog and split attribution for users between different site locales. All item types can be localized.

For products, ensure that `currency`, if available, is captured in the catalog along with `price`. The `currency` attribute takes an [ISO 4217](https://en.wikipedia.org/wiki/ISO\_4217) 3-character string currency code as its value and can change based on locale.

The following are example `catalog` objects with a `currency` attribute specified.

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
catalogObject: {
    type: "Product",
    id: getProductId(),
    attributes: {
        name: getProductName(),
        price: getProductPrice(),
        currency: "AUD"
    }
}
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
catalog: {
    Product: {
        _id: getProductId(),
        name: getProductName(),
        price: getProductPrice(),
        currency: "AUD"
    }
}
```

The following list contains examples of valid currencies.

- `USD`
- `AUD`
- `THB`
- `EUR`
- `BRL`
- `DKK`

### Order Configuration in Different Locales

When creating an order configuration on a dataset that includes locales, an additional field in the order configuration is required to calculate total revenue correctly. The `currency` attribute takes an [ISO 4217](https://en.wikipedia.org/wiki/ISO\_4217) 3-character string currency code as its value. If no currency is provided, the default currency on the dataset is applied as the currency for items in the `order` object.

The following are example `order` objects with a `currency` attribute specified.

```sfdocs-code {"lang":"javascript", "title": "SalesforceInteractions Namespace"}
{
  ...
  order: {
    id: "testOrder123",
    totalValue: 120.25,
    currency: "AUD",
    lineItems: LineItem[]
  }
  ...
}
```

```sfdocs-code {"lang":"javascript", "title": "Evergage Namespace"}
{
    ...
      order: {
          Product: {
              orderId: "testOrder123",
              totalValue: 120.25,
              currency: "AUD",
              lineItems: {
                  _id: string[],
                  price: double[],
                  quantity: integer[]
                }
            }
        }
    ...
}
```

## See Also

- [*Salesforce Help*: Create a Custom Catalog Object](https://help.salesforce.com/s/articleView?id=sf.mc_pers_catalog_object_custom.htm)
- [*External Link*: Cash Documentation](https://github.com/fabiospampinato/cash#documentation)
