---
title: Personal data handling - Web
description: Understand how Contentsquare handles Personal Data
lastUpdated: 10 June 2026
source_url:
  html: https://docs.contentsquare.com/en/web/personal-data-handling/
  md: https://docs.contentsquare.com/en/web/personal-data-handling/index.md
---

> Documentation index: https://docs.contentsquare.com/llms.txt
> Use this file to discover all available pages before exploring further.

The Contentsquare tag masks Personal Data before it leaves the browser and offers configurable commands, HTML attributes, and encrypted-collection modes to control what is sent and stored.

## At a glance

Personal Data handling on the Contentsquare tag relies on three layers:

1. **Automatic Personal Data Redaction** — the tag detects common patterns (emails, JWTs, OAuth tokens, credit card numbers) and redacts them before any data leaves the browser. See [Automatic Personal Data Redaction](#automatic-personal-data-redaction).
2. **Masking features** you configure — commands and HTML attributes to mask or strip Personal Data from URLs, API error URLs, DOM content, and clicked element text. See [Masking features](#masking-features).
3. **Controlled Exposure** — collect and encrypt selected values client-side so Contentsquare cannot see them, and decrypt only with your private key when reviewing replays. See [Controlled Exposure](#controlled-exposure).

Some data is **sent as-is** and is not automatically masked — most notably identity strings (`identify`), user properties, event names, event/pageview properties, and ecommerce item data. You are responsible for ensuring these do not contain Personal Data. See [Data sent as-is](#data-sent-as-is-not-automatically-masked).

## Automatic Personal Data Redaction

The Contentsquare tag automatically detects and replaces certain types of personal data **before** any information leaves the browser. This happens without any configuration.

The types of personal data that are detected depend on the data channel.

### What is detected

| Personal data type | Replacement token | How it is detected |
| - | - | - |
| Email addresses | `CS_ANONYMIZED_EMAIL` | Pattern matching of email addresses, including URL-encoded forms (`%40`, `%2540`) |
| JWT tokens | `CS_ANONYMIZED_JWT` | Structural match on the standard JWT format (`eyXxx.eyXxx.Xxx` — three base64-encoded segments) |
| OAuth token values | `CS_ANONYMIZED_TOKEN` | Query parameters named `id_token`, `access_token`, `refresh_token`, or `auth_token`, regardless of the token format |
| Credit card numbers | `CS_ANONYMIZED_PII` | 16-digit Visa/Mastercard number patterns, validated with a Luhn checksum |

### Where each type is masked

Not every detection applies everywhere. The table below shows exactly which personal data types are masked in each data channel.

| Data channel | Emails | JWT tokens | OAuth tokens | Credit cards |
| - | - | - | - | - |
| [**URLs**](https://docs.contentsquare.com/en/web/sending-pageviews/) (page URL, referrer) | ✅ | ✅ | ✅ | — |
| [**HTML / DOM content**](#personal-data-handling-in-the-html-in-session-replay) (Session Replay) | ✅ | — | — | ✅ |
| [**JavaScript error**](https://docs.contentsquare.com/en/web/error-analysis/) messages | ✅ | — | — | — |
| [**JavaScript error**](https://docs.contentsquare.com/en/web/error-analysis/) filenames | ✅ | ✅ | ✅ | — |
| [**API error**](https://docs.contentsquare.com/en/web/error-analysis/) URLs | ✅ | ✅ | ✅ | — |
| [**Custom error**](https://docs.contentsquare.com/en/web/error-analysis/) messages | ✅ | — | — | — |
| [**Custom error**](https://docs.contentsquare.com/en/web/error-analysis/) messages (embedded URLs) | ✅ | ✅ | ✅ | — |
| [**Custom Variables**](https://docs.contentsquare.com/en/web/sending-custom-vars/) (name and value) | ✅ | — | — | — |
| [**Dynamic Variables**](https://docs.contentsquare.com/en/web/sending-dynamic-vars/) (name and string value) | ✅ | — | — | — |
| [**Ecommerce transactions**](https://docs.contentsquare.com/en/web/sending-ecommerce-commands/) (transaction id) | ✅ | — | — | — |

Also, the following data-specific protections are always applied:

* [**JavaScript errors**](https://docs.contentsquare.com/en/web/error-analysis/): form field values (patterns like `value="..."`) are redacted in error messages.
* [**Custom errors**](https://docs.contentsquare.com/en/web/error-analysis/): phone numbers and name patterns (for example `firstName=`, `lastName=`, `userName:"..."`) are also redacted in error messages.
* [**API errors**](https://docs.contentsquare.com/en/web/error-analysis/): the query string is stripped entirely from the collected URL, in addition to the masking listed above.
* **Clicked element text**: if the text of a clicked button or link contains an email address or a credit card number, the entire text is dropped and not collected.

Note

Form field values (`<input>`, `<textarea>`) and editable content (`<div contenteditable="true|false">`) are never collected — they are replaced by dots before the HTML is sent.

### Data sent as-is (not automatically masked)

The following data is transmitted without any Automatic Personal Data Redaction. If these channels may contain personal data, you are responsible for ensuring it is removed before sending it to Contentsquare.

| Data channel | Details |
| - | - |
| [**`identify` identity string**](https://docs.contentsquare.com/en/web/track-users/) | The identity string is sent as-is. Use the [`{ hash: true }` option](https://docs.contentsquare.com/en/web/track-users/#best-practices) to hash it client-side before sending. |
| [**User properties**](https://docs.contentsquare.com/en/web/command-reference/#adduserproperties) (`addUserProperties`) | Keys and values are sent as-is (only truncated to 255 characters) |
| [**Visit properties**](https://docs.contentsquare.com/en/web/command-reference/#custompropertiesvisitadd) (`customProperties:visit:add`) | Keys and values are sent as-is |
| [**Pageview properties**](https://docs.contentsquare.com/en/web/command-reference/#custompropertiespageadd) (`customProperties:page:add`) | Keys and values are sent as-is |
| [**Page events**](https://docs.contentsquare.com/en/web/custom-page-events/) (`trackPageEvent`) | The event name string is sent verbatim |
| [**Custom events**](https://docs.contentsquare.com/en/web/command-reference/#trackevent) (`trackEvent`) | The event name string is sent verbatim |
| **External events** | The event name string is sent verbatim |
| [**Custom errors**](https://docs.contentsquare.com/en/web/error-analysis/) — name and attributes (`trackError`) | Only the error *message* is filtered; the error name and attributes are sent as-is |
| [**Ecommerce item data**](https://docs.contentsquare.com/en/web/sending-ecommerce-commands/) (`ec:transaction:items:add`) | Item names, SKUs, categories, and other attributes are sent as-is |
| **Dynamic Variable integer values** | Integer values are not processed for anonymization |
| **Non-email PII in Custom/Dynamic Variable strings** | Credit card numbers, phone numbers, JWT tokens, and other sensitive data (other than emails) are not detected in Custom or Dynamic Variable values |

## Masking features

Beyond [Automatic Personal Data Redaction](#automatic-personal-data-redaction), Contentsquare provides several commands and HTML attributes to mask or strip Personal Data from specific channels. This section lists every available feature and explains how and where to use them.

### Command cheatsheet

The following commands and attributes are available to control Personal Data collection. Each is detailed in the corresponding section below or in the [Command Reference](https://docs.contentsquare.com/en/web/command-reference/).

| Scope | Command / attribute | Purpose |
| - | - | - |
| URL path | [`setPath`](https://docs.contentsquare.com/en/web/command-reference/#setpath) | Rewrite the URL path before it is collected |
| URL query string | [`setQuery`](https://docs.contentsquare.com/en/web/command-reference/#setquery) | Rewrite the URL query string before it is collected |
| Referrer | [`referrer:maskUrl`](https://docs.contentsquare.com/en/web/command-reference/#referrermaskurl) | Mask Personal Data in the referrer path |
| Referrer | [`referrer:removeQueryString`](https://docs.contentsquare.com/en/web/command-reference/#referrerremovequerystring) | Drop the referrer query string |
| API error URLs | [`networkRequest:maskUrls`](https://docs.contentsquare.com/en/web/command-reference/#networkrequestmaskurls) | Mask Personal Data in collected API error URLs |
| Session Replay (DOM) | [`setPIISelectors`](https://docs.contentsquare.com/en/web/command-reference/#setpiiselectors) | Mask DOM elements matching CSS selectors |
| Session Replay (DOM) | `data-cs-mask` attribute | Mask the content of a specific HTML element |
| Session Replay (DOM, Page Masking on) | [`setCapturedElementsSelector`](https://docs.contentsquare.com/en/web/command-reference/#setcapturedelementsselector) | Expose specific elements on a masked page via CSS selectors |
| Session Replay (DOM, Page Masking on) | `data-cs-capture` attribute | Expose a specific element on a masked page |
| Session Replay (page-level) | [`excludeURLforReplay`](https://docs.contentsquare.com/en/web/command-reference/#excludeurlforreplay) | Disable Session Replay collection for matching pages |
| Controlled Exposure | [`setEncryptionSelectors`](https://docs.contentsquare.com/en/web/command-reference/#setencryptionselectors) | Collect the content of matching elements in encrypted form |
| Controlled Exposure | `data-cs-encrypt` attribute | Collect the content of a specific element in encrypted form |
| Identity | [`identify` with `{ hash: true }`](https://docs.contentsquare.com/en/web/track-users/#best-practices) | Hash the identity string client-side before sending it |
| Identity | [`resetIdentity`](https://docs.contentsquare.com/en/web/command-reference/#resetidentity) | Clear the identity string (for example, on logout) |

### In identity and user attributes

The tag exposes several commands to attach identity or attributes to a user. **None of these values are automatically masked** — what you pass is what is sent and stored.

* [`identify`](https://docs.contentsquare.com/en/web/track-users/): associates an identity string with the current user. The value is sent as-is unless you use the `{ hash: true }` option, which hashes it client-side. Prefer non-directly-identifying values (UUIDs, account numbers) over emails or phone numbers. See [Track Users → Best practices](https://docs.contentsquare.com/en/web/track-users/#best-practices) for the trade-offs of client-side hashing.
* [`resetIdentity`](https://docs.contentsquare.com/en/web/command-reference/#resetidentity): clears the identity associated with the current user. Use it on logout so a subsequent user on the same device does not inherit the previous identity.
* [`addUserProperties`](https://docs.contentsquare.com/en/web/command-reference/#adduserproperties), [`customProperties:visit:add`](https://docs.contentsquare.com/en/web/command-reference/#custompropertiesvisitadd), [`customProperties:page:add`](https://docs.contentsquare.com/en/web/command-reference/#custompropertiespageadd): attach custom properties to the user, visit, or pageview. Keys and values are sent verbatim — do not pass Personal Data in either.

For the full API, see [Track Users](https://docs.contentsquare.com/en/web/track-users/).

### Personal Data handling in the HTML (in Session Replay)

Sessions will be collected for Session Replay if:

* The `Session Replay` feature has been enabled for your account
* The threshold set by the `Session Replay Collection Rate` is not exceeded

For the HTML content to be sent, all these conditions must be true:

* The user hasn't opted out
* The session is being tracked
* The browser is [compatible](https://docs.contentsquare.com/en/web/compatibility/)
* The session has been flagged as "Collected for Session Replay", using the [`_cs_s`](https://docs.contentsquare.com/en/web/cookies/#_cs_s) cookie

Warning

If Session Replay is turned off, the HTML text/content of the page **is not** collected during the session. You must ensure that your URLs do not contain Personal Data or that they are masked by [modifying the sent URL](https://docs.contentsquare.com/en/web/sending-pageviews/#modifying-the-sent-url).

#### Session Replay data collection options

If Session Replay is turned on and data collection is active for the session, the HTML content of the page is sent **after every pageview** (both natural and artificial) and **every DOM change** (only the updated elements are sent).

Note

If you have a Success Manager, ask them to check your approach to masking.

The Page Masking setting controls how much of the page content is collected.

Page Masking (Automasking)

Depending on whether Page Masking is activated, the resulting replay will differ and you will have to carry out additional masking tasks.

##### With Page Masking off

The following protections apply regardless of Page Masking state: Contentsquare never collects the actual text typed into any `<input>` or `<textarea>` field.

* The content of `<input>` elements with type `text`, `email`, `password`, `search`, `tel`, `url` or `<input>` elements without a `type` attribute are replaced with bullets before the HTML is sent
* Every figure of `<input>` elements with type `number` are replaced by 0
* The `value` attribute is stripped from every `<input>` element, regardless of its type (including `checkbox`, `radio`, `hidden`, `range`, and others)
* The content `<textarea>` elements is replaced with bullets before the HTML is sent
* The content inside any element with a defined `contenteditable` property is replaced with bullets before the HTML is sent
* The content of `<script>` elements is emptied
* Except for the items listed previously, all the HTML content is sent, including `<head>`
* The content of every element marked with the data attribute `data-cs-mask` is removed (see the [Tagging DOM elements](#tagging-dom-elements) section)

CSS rules that depend on input values

Because the `value` attribute is stripped from every `<input>` element, CSS selectors that target a specific value — for example `[name="filter"][value="12"]:checked ~ article` — will not produce the expected result in Session Replay. Content shown or hidden by such rules may appear incorrectly in the replay.

Note

Dropdowns are usually coded with the `<select>` element, which is collected by default by Contentsquare. If you show any Personal Data in these elements, apply the `data-cs-mask` data attribute.

##### With Page Masking on

The following protections apply regardless of Page Masking state: Contentsquare never collects the actual text typed into any `<input>` or `<textarea>` field.

* The content of `<input>` elements with type `text`, `email`, `password`, `search`, `tel`, `url` or `<input>` elements without a type are replaced with bullets before the HTML is sent
* Every figure of `<input>` elements with type `number` are replaced by 0
* The `value` attribute is stripped from every `<input>` element, regardless of its type (including `checkbox`, `radio`, `hidden`, `range`, and others)
* The content `<textarea>` elements is replaced with bullets before the HTML is sent
* The content inside any element with a defined `contenteditable` property is replaced with bullets before the HTML is sent
* The content of `<script>` elements is emptied
* The content of every element marked with the data attribute `data-cs-mask` is removed (see the [Tagging DOM elements](#tagging-dom-elements) section)
* The content of every element marked with the data attribute `data-cs-capture` is collected and shown unless it falls under the excluded elements listed above (`<input>`, `<textarea>`)
* **Every character of the text content included in the elements sent is replaced by "A"**
* Attributes unrelated to layout are removed. Only `id`, `class`, `style`, `src`, `srcset`, `href`, `rel`, and `type` are kept

##### Selectively mask pages by URL

In case your site displays Personal Data only on a specific set of pages, **you can decide to run the Page Masking process only on a pre-defined set of pages**, so that you won't have to apply the masking across the whole site. These can only be configured by your dedicated Success Manager.

There are two available options:

* **Mask all pages except**: All pages will be masked except the ones defined by a Regex Pattern agreed with your Success Manager.
* **Unmask all pages except**: All pages will be collected with clear content except from the ones defined by a Regex pattern agreed with your Success Manager

#### Block data collection for specific pages (Session Replay)

Use the `excludeURLforReplay` command to block data collection on pages based on their URL. Use cases include:

* Personal data has been exposed
* Exclude whole parts of your website from being collected for Session Replay
* Some page replays for Session Replay cause performance issues (when the page contains many images or videos, for instance) — you can block these pages until the problem is fixed

```javascript
window._uxa = window._uxa || [];
window._uxa.push(["excludeURLforReplay", "URL_REGEX"]);
```

This command is scoped to the current pageview and must be rerun every time the tag loads.

Using this command does not block pageviews for the given pages — it only blocks data collection for Session Replay.

#### Remove content/Personal Data from the collected HTML

There are two methods to remove content from the collected HTML:

1. Using the Contentsquare Personal Data Selector
2. Tagging DOM Elements

##### Personal Data Selector

Each DOM element to be masked is identified by its CSS selector, and those selectors are pushed to the API via a JavaScript object. The content of the identified element is removed from the replay.

[Tag Configurator Template: Element Masking ](https://support.contentsquare.com/hc/en-us/articles/37271896933521-CSTC-Template-Element-Masking)Use the Tag Configurator to implement Element Masking through a visual interface.

Note

In case of CSS selectors being changed or removed, the masking will be removed as well.

Push the following object containing CSS selectors for text and attributes to the API, **before firing the main tag**:

```javascript
window._uxa = window._uxa || [];
window._uxa.push(['setPIISelectors', PIIObject]);
```

The structure of the `PII` Object is as follows:

* `PIISelectors`: Comma-separated list of CSS selectors which allow the **matching DOM elements to be masked by the tag.**

* `Attributes`: Using this key, you can **remove the defined attributes of the DOM elements from the elements matching the CSS selectors.** You can use an array of attribute names as shown in the example above.

Keep in mind that using both `PII Selectors` and `Attributes` is optional, meaning you can use either full element selectors, specific attribute selectors or both in the same object:

```javascript
{
  PIISelectors: [".css-selector, selector"], // DOM elements to be masked
  Attributes: [
      {
          selector: "select#month option, select#year option", // CSS selector(s)
          attrName: 'id' // Attribute name you want to mask
      },
      {
          selector: ".link-page-7", // CSS selector(s)
          attrName: ['href','name'] // Array attribute names you want to mask
      }
  ]
};
```

##### Tagging DOM elements

To exclude content from being collected, use the `data-cs-mask` attribute on selected elements:

```html
Content before
<p data-cs-mask>emailaddress@sentitivedata.com</p>
Content after
```

Their content is removed in the browser before it is sent to Contentsquare:

```html
Content before
<p data-cs-mask>emailaddress@sentitivedata.com</p>
Content after
```

You can also add the `data-cs-mask` attribute with JavaScript provided you do it before any pageview is sent.

**Events on removed HTML** — [Events](https://docs.contentsquare.com/en/web/events-handling/) (click, hover, etc.) will still be collected and sent to our servers even if they are targeting removed HTML elements. They will be visible in the application using Live Resources (as named in the platform).

Warning

Using comments within the HTML is not supported (`<!-- MousetestSensitiveStart -->...<!-- MousetestSensitiveEnd -->`).

#### Display content in a fully masked HTML page

There are two methods to display content in a masked HTML page:

1. Using the Contentsquare Personal Data Selector
2. Tagging DOM Elements

##### Personal Data Selector

Each DOM element to be displayed is identified by its CSS selector, and those selectors are pushed to the API via a JavaScript object. The content of the identified element is displayed in Session Replay.

[Tag Configurator Template: Element Unmasking ](https://support.contentsquare.com/hc/en-us/articles/37271866118033-CSTC-Template-Element-Unmasking)Use the Tag Configurator to implement Element Unmasking through a visual interface.

Note

In case of CSS selectors being changed or removed, the element will be masked by default.

The string which contains comma-separated CSS selectors for text and for attributes must be pushed to the Contentsquare API, **before firing the main tag**, as follows:

```javascript
window._uxa = window._uxa || [];
window._uxa.push(["setCapturedElementsSelector", "#capture-me, .show-me"]);
```

##### Tagging DOM elements

To display an HTML element in a masked page, add the `data-cs-capture` attribute to the HTML elements:

```html
Sensitive Content before
<p data-cs-capture>some piece of text that is not sensitive</p>
Sensitive Content after
```

Content that is part of the tagged element is captured as is:

```html
AAAA AAAA AA
<p data-cs-capture>some piece of text that is not sensitive</p>
AAA AAA AA
```

It can also be added with JavaScript, but attributes must be added before any pageview is sent.

#### Session Replay Testing

##### Prerequisites

* Have Google Chrome installed
* Download the [Contentsquare Tracking Setup Assistant ↗](https://chrome.google.com/webstore/detail/contentsquare-tracking-se/pfldcnnaiaiaogmpfdjjpdkpnigplfca) Chrome Extension
* Mask elements from the replay using [CSS selectors](https://docs.contentsquare.com/en/web/personal-data-handling/#personal-data-selector) or the [`data-cs-mask` attribute](https://docs.contentsquare.com/en/web/personal-data-handling/#tagging-dom-elements) — `<input>` elements are not captured by default, except dropdowns which still need masking
* Activate full session masking
* If you have already provided us with a list of your internal/office IPs for us to add to our exclusion list, inform your Contentsquare Success Manager to temporarily pause that exclusion list. Otherwise, sessions run from such an IP will not be collected by Contentsquare

##### Testing

1. Start a journey on your website, featuring the elements to be masked.

2. In the Contentsquare Tracking Setup Assistant extension, select `Turn off automasking` to prevent 'AAA' masking from affecting your local session.

   ![](https://docs.contentsquare.com/_astro/ctsa-sr-turn-off-anon.DZfUMwEP_2dkgG.webp)

3. Select `Collected for Session Replay` to enable Session Replay data collection for your session.

   ![](https://docs.contentsquare.com/_astro/ctsa-sr-1.BytcVmTZ_KLae6.webp)

   Direct link to replay

   A **Play** button appears next to the page URL. Click the icon and leave the tab open. The resulting replay will be available at this link 30 minutes after the end of your tests.

4. Select `Trigger testing pageEvent` to create the `SR Testing` page event which identifies your current session.

   ![](https://docs.contentsquare.com/_astro/ctsa-trigger-testing-page-event.B3xTUH2J_2tG0Vj.webp)

5. Make sure that the elements to be masked are visible as you progress along your testing journey. If required, fill out any test personal information. You will be able to check this information has been masked in the resulting replay.

6. Once you are done testing, close your session by either closing the session's tab or deleting your cookies.

   ![](https://docs.contentsquare.com/_astro/ctsa-delete-cookies.BdVTxncg_1Nlo3E.webp)

   Replay availability

   The replay is available 30 minutes later:

   * At the link generated above accessible via the **Play** button. ![](https://docs.contentsquare.com/_astro/ctsa-sr-2.DURDj521_Z2dzuSM.webp)

   * On the [Contentsquare platform ↗](https://app.contentsquare.com/), by filtering replays containing the `SR Testing` page event.

     ![](https://docs.contentsquare.com/_astro/find-testing-page-event.B_hhxnuU_Z1UJewh.webp)

7. Watch the replay and look for all the areas where Personal Data could appear:

* ❌ If Personal Data is visible, update your masking and test again.
* ✅ If there were no Personal Data, you are covered in terms of Privacy compliance.

##### What's next?

If you are currently in the initial implementation phase of your project, inform your Success Manager about the results so they can double-check and then turn Page Masking off for you to use full Session Replay.

If you are not in implementation and your tests are successful, you can update the Page Masking rules directly from the Console in Contentsquare if you are an Admin, by going to the **Page Masking** tab.

For instructions, see the [Help Center article ↗](https://support.contentsquare.com/hc/en-us/articles/360017105259#01H7ZAF8S5FZ70HGHV036TXF18).

##### Following Session Replay requests

HTML content is sent via requests to one of the endpoints listed below, based on where data is stored for your project:

* `https://k.aeu1.contentsquare.net/{apiVersion}/recording`
* `https://k.aus1.contentsquare.net/{apiVersion}/recording`
* `https://k.eu1.az.contentsquare.net/{apiVersion}/recording`
* `https://k.us1.az.contentsquare.net/{apiVersion}/recording`
* `https://k.ba.contentsquare.net/{apiVersion}/recording`
* `https://k.bf.contentsquare.net/{apiVersion}/recording`
* `https://k.aa.contentsquare.net/{apiVersion}/recording`
* `https://k.af.contentsquare.net/{apiVersion}/recording`

The request is sent when the 2nd value of the [`_cs_s`](https://docs.contentsquare.com/en/web/cookies/#_cs_s) cookie (Session Replay data collection state) is `3` (collected) or `5` (collected after a specific trigger) or when ETR is enabled on the project. The request contains all the DOM.

Note

The tag serializes image elements containing base64 data. To mask such images in replays, use the [`setPIISelectors` command](https://docs.contentsquare.com/en/web/command-reference/#setpiiselectors):

```javascript
const PIIobject = {
  PIISelectors: ["[src^='data:image']"]
};


window._uxa.push(['setPIISelectors', PIIobject]);
```

Inspect data sent for Session Replay

Use the [`_cs_debug`](https://docs.contentsquare.com/en/web/cookies/#_cs_debug) cookie inspect the decoded data:

Sessions collected with the `compressionDisabled` flag on are filtered out from the Session Replay pipeline.

1. From the browser console, run this command to create the cookie:

   ```plaintext
   document.cookie = "_cs_debug=compressionDisabled"
   ```

2. Reload the page.

3. In the Network tab, search for `https://k-*.contentsquare`, select the request, and check the payload.

### Blocking Personal Data in URLs

Personal data appears in more places than just the HTML content.

For a given page, you also need to mask Personal Data found in:

* [The path of the current page](#masking-personal-data-in-the-url-path)
* [The query string parameters of the current page](#masking-personal-data-in-url-query-string-parameters)
* [The referrer of the next visited page](#masking-personal-data-in-the-referrer)

Unmasked data could be exposed in the Error Analysis module.

#### Masking Personal Data in the URL path

To remove Personal Data in the URL of the current page, rewrite the URL of the pageview before the tag collects it, using the `setPath` command.

The `setPath` command takes as a parameter the exact new path to collect as a URL.

```javascript
window._uxa = window._uxa || [];
window._uxa.push([
  'setPath', <NEW_PATH_TO_COLLECT>
]);
```

Call this command on **every page where the URL contains Personal Data, before the main Tracking tag is loaded**. Only the path is to be configured, not the whole URL.

##### Example

```javascript
window._uxa = window._uxa || [];
window._uxa.push(["setPath", "/users/CS_ANONYMIZED_USER_ID"]);
```

| URL before masking | URL after masking |
| - | - |
| `https://www.contentsquare.com/users/jon.snow` | `https://www.contentsquare.com/users/CS_ANONYMIZED_USER_ID` |
| `https://www.contentsquare.com/cartpage/users/jon.snow` | `https://www.contentsquare.com/users/CS_ANONYMIZED_USER_ID` |

#### Masking Personal Data in URL query string parameters

When Personal Data can be found in the query parameters of an URL, use the `setQuery` command to replace the query string within the URL with a new masked one.

```javascript
window._uxa = window._uxa || [];
window._uxa.push([
  'setQuery',
  <ANONIMYZED_QUERY_STRING>
]);
```

The `setQuery` command takes as a parameter the exact new query string to display within the URL. This command instructs the tag to replace the part of the URL after the `?` with masked values.

Call this command on **all pages where the URL contains Personal Data, and before the main tag is loaded**. Only the query string is to be configured, not the whole URL.

##### Example

```javascript
window._uxa = window._uxa || [];
window._uxa.push(["setQuery", "?user_id=CS_ANONYMIZED_USER_NAME&address=CS_ANONYMIZED_ADDRESS"]);
```

| URL before masking | URL after masking |
| - | - |
| `https://www.mysite.com/us/makeup/valentines-day/?user_id=jon.snow&address=castle.black` | `https://www.mysite.com/us/makeup/valentines-day/?user_id=CS_ANONYMIZED_USER_NAME&address=CS_ANONYMIZED_ADDRESS` |
| `https://www.mysite.com/us/makeup/valentines-day/?campaign=valentinesday_feb_2021&user_id=jon.snow&address=castle.black` | `https://www.mysite.com/us/makeup/valentines-day/?user_id=CS_ANONYMIZED_USER_NAME&address=CS_ANONYMIZED_ADDRESS` |

Customize the masked term according to the type of the parameter to replace, so that the result is explicit:

* `CS_ANONYMIZED_USER_ID`
* `CS_ANONYMIZED_EMAIL`
* `CS_ANONYMIZED_ADDRESS`

...and more.

Note

The `setPath` and `setQuery` commands are already often used during the initial implementation phase, for other purposes than removing Personal Data in the Error Analysis module. If this is the case, amend the initial command with the new parameters to avoid collision.

#### Masking Personal Data in the referrer

Even when you have masked Personal Data in URLs and query parameters on a page, they propagate to the next visited page through the [`referrer` ↗](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer). To handle this use case, use the `referrer:` commands below.

##### In the URL

Consider this journey:

1. Users navigate from `https://www.example.com/users/123456/products/ABCDEF` to `https://www.example.com/`.
2. A pageview is sent on `https://www.example.com/`.
3. The referrer value in both the browser and in the pageview request is `https://www.example.com/users/123456/products/ABCDEF`.

To mask Personal data in the URL within the referrer, use the `referrer:maskUrl` command:

```javascript
var referrers = [
  "https://www.example.com/users/:USER_ID/products/:PRODUCT_ID",
  "https://www.example.com/account/cancelOrder/:ORDER_ID",
  "https://www.example.com/order/:ORDER_ID/merge/:ORDER_ID",
];
window._uxa = window._uxa || [];
for (var i = 0; i < referrers.length; i++) {
  window._uxa.push(["referrer:maskUrl", referrers[i]]);
}
```

The referrer value in the pageview request for `https://www.example.com/` will be:

* `https://www.example.com/users/CS_ANONYMIZED_USER_ID/products/CS_ANONYMIZED_PRODUCT_ID`
* `https://www.example.com/account/cancelOrder/CS_ANONYMIZED_ORDER_ID`
* `https://www.example.com/order/CS_ANONYMIZED_ORDER_ID/merge/CS_ANONYMIZED_ORDER_ID`

Note

Use the `referrer:maskUrl` command as many times as needed, for example to deal with all URL patterns on your site at once.

##### Within query parameters

Consider this journey:

1. Users navigate from `https://www.example.com/confirmation?firstname=jon&lastname=snow` to `https://www.example.com/`.
2. A pageview is sent on `https://www.example.com/`.
3. The referrer value in both the browser and in the pageview request is `https://www.example.com/confirmation?firstname=jon&lastname=snow`.

To mask Personal data in the query string part of the referrer, use the `referrer:removeQueryString` command:

```javascript
window._uxa = window._uxa || [];
window._uxa.push(["referrer:removeQueryString"]);
```

The referrer value in the pageview request for `https://www.example.com/` will be:

`https://www.example.com/?`

Note

To revert the behavior of the `referrer:removeQueryString` command, use `referrer:keepQueryString`. Use this command in the context of a multi-step funnel for a single page, where you run `referrer:removeQueryString` before the natural pageview and then need to pass query string parameters to subsequent artificial pageviews.

### Removing Personal Data in API errors

Use the `networkRequest:maskUrls` command to rewrite the URL before the tag collects the API error URL.

[Tag Configurator Template: Network requests mask URLs ](https://support.contentsquare.com/hc/en-us/articles/37271815661841-CSTC-Template-Network-requests-mask-URLs)Use the Tag Configurator to implement network request URL masking through a visual interface.

The command takes as parameter one or several masking patterns to apply to URLs containing Personal Data. Patterns can match the full URL of the page or only a part of it.

```javascript
window._uxa = window._uxa || [];
window._uxa.push([
  'networkRequest:maskUrls',
  <PATTERN>
]);
```

Patterns include the URL fragments to mask as variables prefixed by a colon. Such variables are replaced by `CS_ANONYMIZED_{FRAGMENT}`:

* `:user_id` becomes `CS_ANONYMIZED_USER_ID`
* `:address` becomes `CS_ANONYMIZED_ADDRESS`
* `:email` becomes `CS_ANONYMIZED_EMAIL`

Call this command **on all pages containing Personal Data which call the Contentsquare API, and before the main tag is loaded**.

#### Example

```javascript
window._uxa.push([
  "networkRequest:maskUrls",
  ["order/:order_id/merge/:order_id", "order/:order_id/item", "cancelOrder/:order_id"]
]);
```

| URL before masking | URL after masking |
| - | - |
| `https://api.net/order/:order_id/merge/:order_id` | `https://api.net/order/CS_ANONYMIZED_ORDER_ID/merge/CS_ANONYMIZED_ORDER_ID` |
| `https://api.net/order/:order_id/item` | `https://api.net/order/CS_ANONYMIZED_ORDER_ID/item` |
| `https://www.api.nl/nl/ajax/nfs/account/cancelOrder/:order_id` | `https://www.api.nl/nl/ajax/nfs/account/cancelOrder/CS_ANONYMIZED_ORDER_ID` |

### Removing Personal Data in Clicked Element

When clicked element collection is turned on and data collection is active for the session, the tag collects the text payload of the buttons and links being clicked as part of other analytics payloads (see `/events` [request](https://docs.contentsquare.com/en/web/requests/#events)).

#### With Page Masking off

The clicked element will be collected except if it is masked by `data-cs-mask`.

#### With Page Masking on

The clicked element will not be collected except if `data-cs-capture` is present on the clicked button or link.

Note

You can enable Page Masking on [specific URLs](https://docs.contentsquare.com/en/web/personal-data-handling/#selectively-mask-pages-by-url).

You can also mask specific elements on the webpage. This masking takes priority over Page Masking configuration. For more information, see [personal data selector section](#personal-data-selector-1).

## Controlled Exposure

Note

This feature is only available to Experience Monitoring customers.

Contact your Success Manager to inform them about your implementation of controlled exposure as they'll need to activate that feature for your project.

The Contentsquare Tracking Tag does not collect any text typed into `input` or `textarea` fields.

If you need to display the personal data of a user, such as shipping/delivery addresses, names, phone numbers, email addresses, or text inputs in a form field, use the collect and encrypt mode.

With the collect and encrypt mode, you can collect, store, and display text in `input`, `textarea` fields, or any other element within a page that is usually masked by the tag, before it is sent to Contentsquare's servers.

Encryption vs Masking

Encrypting data is incompatible with element level masking such as tagging DOM elements with the [`data-cs-mask`](#tagging-dom-elements) attribute or through the [Personal Data Selector](#personal-data-selector) using the `setPIISelectors` API.

This means that:

* Both attributes `data-cs-mask` and `data-cs-encrypt` should never be used on the same HTML element
* The `data-cs-mask` attribute should not be used on a container element that would target indirectly another element to be encrypted
* If you already have a personal data masking method implemented on your project, check that no element with a `data-cs-encrypt` attribute is targeted by these methods, taking the DOM nesting rules into account
* If you wish to mask an element by default but be able to encrypt it and expose it in Session Replays, you should **only** have the `data-cs-encrypt` attribute on this element at the most granular level rather than `data-cs-mask`

### Collect and encrypt personal data from the collected HTML

There are two methods to collect and encrypt personal data from the collected HTML:

* Using the Contentsquare Encryption Selector
* Tagging DOM Elements

#### Encryption Selector

Each DOM element to be collected and encrypted is identified via its CSS selector. These selectors are pushed to the API via a JavaScript object. The content of the identified element is then encrypted and collected for Session Replays.

Note

In case of CSS selectors being changed or removed, the encryption and collection will be removed as well.

The following object that contains CSS selectors for text should be pushed to the API as follows, before firing the main tag:

```javascript
window._uxa = window._uxa || [];
window._uxa.push(["setEncryptionSelectors", "#cart, .total-items"]);
```

#### Tagging DOM elements

The `data-cs-encrypt` attribute can be added on an input field, `textarea` field, or any other element. Instead of being masked, the text in the tagged element is encrypted, stored, and made available for exposing under specific conditions.

The encryption process happens on the `innerText` property of the tagged element. It does not apply on nested elements: the text of the nested element won't be masked nor encrypted. Make sure to add the `data-cs-encrypt` attribute on the most granular elements that must be collected.

```html
<h2 class="welcoming">
  Welcome back
  <span class="user_name" data-cs-encrypt>John Doe</span>
</h2>
```

You can also add the `data-cs-encrypt` attribute with JavaScript provided you do it before any pageview is sent.

Warning

During the encryption process, the value of the text is truncated after 90 characters. Choose carefully the HTML elements to expose: try to avoid `textarea` or long text inputs.

### Data Encryption

To use Controlled Exposure, obtain a combination of encryption keys:

* Public key: used by the Tracking Tag to encrypt the data
* Private key: used by the app for decryption

Note

You must generate the pair of keys, Contentsquare will never have access nor store the private key.

### How to generate the key pair

#### Option 1: With a Google chrome script

1. Copy the following script:

   ```javascript
   function arrayBufferToString(buffer) {
     const byteArray = new Uint8Array(buffer);
     let byteString = "";
     for (let i = 0; i < byteArray.byteLength; i += 1) {
       byteString += String.fromCodePoint(byteArray[i]);
     }
     return byteString;
   }


   crypto.subtle
     .generateKey(
       {
         name: "RSA-OAEP",
         hash: "SHA-256",
         modulusLength: 4096,
         publicExponent: new Uint8Array([1, 0, 1]),
       },
       true,
       ["encrypt", "decrypt"],
     )
     .then((keysObject) => {
       crypto.subtle.exportKey("pkcs8", keysObject.privateKey).then((result) => {
         const privateKey = btoa(arrayBufferToString(result));
         console.log(`Private key: `, privateKey);
       });
       crypto.subtle.exportKey("spki", keysObject.publicKey).then((result) => {
         const publicKey = btoa(arrayBufferToString(result));
         console.log(`Public key: `, publicKey);
       });
     });
   ```

2. Paste the script in the Chrome console.

3. Press enter on the keyboard.

#### Option 2: With OpenSSL or OpenSSH

On linux/Mac, you can use OpenSSL:

```plaintext
openssl genpkey -out mykey.pem -algorithm RSA -pkeyopt rsa_keygen_bits:4096
openssl rsa -in mykey.pem -pubout > mykey.pub
```

On Windows you will need to [install WSL ↗](https://docs.microsoft.com/en-us/windows/wsl/install).

#### How to add a public key

1. Go to the Contentsquare Console > Choose the account > Choose the project > "Encryption management" tab.
2. Select "Store public key".
3. Paste your preferred public key.
4. Select "Store key".

Note

It can take up to 30 minutes before the key is activated.

### Unmask on-screen text in Contentsquare

1. Select the key icon and select Unmask on-screen text
2. Enter in the private key and select decrypt (all replays will be exposed)

## User identifier

Note

This feature is only available to Experience Analytics customers on Pro and Enterprise plans, with a 50% Global Replay Sampling rate. 100% is highly recommended: the higher the sampling rate, the more likely you are to find the related replays.

Always contact your Success Manager to inform them about your implementation of user identifier: this feature must be activated for your project.

With the **User Identifier** feature, you can search for replays belonging to specific users using a unique identifier. You can search and access all sessions associated with a specific user, for example `john@gmail.com`, within the selected date range. Use this feature in the case of user feedback or complaints.

The user identifier can be any value which uniquely identifies a user such as a username, an account number, email address, phone number, CRM ID, or loyalty system ID. It is immediately hashed and encoded in a one-way format before it is sent to Contentsquare.

When filtering Session Replays with a user identifier in Contentsquare, the same hashing algorithm is used and both hashes are compared to match the user identifier with its associated replays.

### User identifier implementation

1. **Choosing the right User Identifier**: Opt for a unique identifier like the email address, username, or account number that is available on the front-end.

2. **Collecting User Identifiers**: To collect the user identifier, you need to send a page event using the [`trackPageEvent`](https://docs.contentsquare.com/en/web/custom-page-events/#defining-page-event) command, with the prefix `@user-identifier@`:

   ```javascript
   window._uxa = window._uxa || [];
   window._uxa.push(["trackPageEvent", "@user-identifier@user_email"]);
   ```

   Or if you pull the identifier from the data layer:

   ```javascript
   window._uxa = window._uxa || [];
   window._uxa.push(["trackPageEvent", "@user-identifier@" + dataLayer.Name]);
   ```

   The user identifier value is limited to 100 characters.
