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

# Session management

> How Elevate sessions and visitor identification work, covering the session lifecycle, customer keys, consent handling, and secure key storage options.

## Sessions

A session is a group of interactions within a defined time frame and forms the basis for tracking visitor behavior and enabling personalization in Elevate. Sessions are central to ensuring consistent user experiences, allowing Elevate to maintain context, preferences, and personalization as visitors navigate a site.

### Session lifecycle

The session lifecycle outlines how Elevate internally defines and manages sessions for reporting, behavioral analysis, and more. This process is handled automatically and is intended for informational purposes only, requiring no explicit action from the integrator.

An Elevate session begins when a visitor [triggers a request](#implementing-visitor-identification) and ends either through an [end notification](/elevate/docs/api/storefront/v3/notifications/end) or automatically when one of the following criteria is met:

* 15 minutes if there are no notifications for either [click](/elevate/docs/api/storefront/v3/notifications/click), [add to cart](/elevate/docs/api/storefront/v3/notifications/add-to-cart), [payment](/elevate/docs/api/admin/v3/notifications/payment), [add favorite](/elevate/docs/api/storefront/v3/notifications/add-favorite), [remove favorite](/elevate/docs/api/storefront/v3/notifications/remove-favorite), [remove recent searches](/elevate/docs/api/storefront/v3/notifications/remove-recent-searches), or [remove recently viewed](/elevate/docs/api/storefront/v3/notifications/remove-recently-viewed)
* 1 hour of inactivity, counted from the start of each hour
* 00:00 UTC, regardless of activity

Bounce sessions are not counted in session volume calculations. A session is classified as a bounce session if both of the following conditions are met:

* The session lasts for less than 1 second.
* The session contains no interactive notifications.

#### Examples

* A session starts at 13:00 with a [Landing Page](/elevate/docs/api/storefront/v3/queries/landing-page) request. This session ends at 13:15 due to 15 minutes of inactivity. This session is considered a bounce session.
* A session starts at 13:00 with a [Landing Page](/elevate/docs/api/storefront/v3/queries/landing-page) request, followed by a new query at 13:05. This session ends at 13:20 due to 15 minutes of inactivity. This session is not considered a bounce session.
* A session starts at 12:55 with a [Landing Page](/elevate/docs/api/storefront/v3/queries/landing-page) request, followed by a [click](/elevate/docs/api/storefront/v3/notifications/click) request at 12:58 and a new query at 13:05. This session ends at 15:00 due to inactivity between 14:00 and 15:00. This session is not considered a bounce session.
* A session starts at 23:55 with a [Landing Page](/elevate/docs/api/storefront/v3/queries/landing-page) request, followed by a [click](/elevate/docs/api/storefront/v3/notifications/click) request at 23:58. This session ends at 00:00. This session is not considered a bounce session.

### Session handling requirements

The following practices must be followed in all production environments:

* Each session must be tied to a unique Elevate visitor; session keys must **not** be reused.
* Elevate requests must be made even when using caching.
* For identified sessions, event notifications must be sent with the visitor’s session key.
* In production, `notify = false` must not be used with the intent of limiting session volume.

## Visitor identification

To connect behavior and events to individual users across and within [sessions](#sessions), Elevate uses visitor identifiers where the customer’s applicable configuration permits. Identification can happen at two levels:

* **Device-based** — using a randomized customerKey, assigned to visitors where permitted, for basic personalization.
* **Visitor-based** — using a persistent, secret [identifier](#selecting-visitor-identifier) tied to a known visitor (for example, a signed-in user), which enables cross-device and off-site personalization such as [Email recommendations](/elevate/docs/addons/email-recommendations/email-recommendations).

### Selecting visitor identifier

When a visitor is known to the site, typically by signing in, the retailer can use a persistent identifier to enable cross-device and off-site personalization. This identifier represents the visitor internally and must be chosen with care to support technical compatibility while allowing the retailer to assess applicable privacy obligations.

The following requirements apply when selecting such an identifier:

* Must uniquely and consistently identify the visitor across devices, access points, and systems.
* Must not be directly identifying or an externally known property (for example, an email address, username, or social security number), as this may increase privacy risk and conflict with best practices under applicable privacy legislation.
* Must be possible to access wherever personalization is applied (for example, in email platforms for personalized sends).

Retailers can typically generate persistent identifiers using internal systems, such as ID tables or hashed visitor data, to enable personalization for signed-in members.

### Implementing visitor identification

The following steps outline how to manage visitor identifiers through the Elevate API:

<Steps>
  <Step title="Assign a key to an unknown visitor">
    When an unknown visitor triggers a request, assign the visitor a random customer key and set the assigned customer key on the request.

    * Use [UUID v4](https://en.wikipedia.org/wiki/Universally_unique_identifier) <Icon icon="external-link" size={12} /> as initial randomized customer keys.
    * Persist the randomized customer key for the visitor, for example in a cookie or local storage.
  </Step>

  <Step title="Reuse the key on later requests">
    When a visitor with an already assigned customer key triggers a new request, set the assigned customer key on the request.
  </Step>

  <Step title="Replace the key when the visitor is identified">
    When a visitor signs in to the site or is otherwise identified, replace the current key with a [secret visitor identifier](#selecting-visitor-identifier) for all future requests.
  </Step>

  <Step title="Retain the key on sign out">
    When a visitor signs out, retain the current customer key to maximize the level of personalization.
  </Step>
</Steps>

For implementation options on storing and transmitting keys securely, see [Key storage and transport](#key-storage-and-transport).

### Linked keys

If multiple `customerKey` values are used during a single session, Elevate automatically links them. This typically happens when a visitor starts unauthenticated and then signs in, triggering a transition from a random key to a known identifier.

<Warning>
  A single `customerKey` must never represent more than one visitor. While a visitor can have multiple keys over time, each key must belong to one visitor only. Reusing a key across individuals can corrupt personalization data and lead to privacy and data integrity issues.
</Warning>

## Consent and privacy

This section provides implementation guidance for handling visitor identifiers where consent or another legal basis affects tracking. Customers and retailers remain responsible for determining the applicable consent or legal basis, notices, retention, cookie and browser storage rules, and Elevate configuration under applicable law. For non-consenting visitors, this documentation describes two technical approaches: [omitting keys](#consent-omit-keys) (recommended technical model) or [randomizing keys](#consent-randomized-keys) (legacy technical handling).

The Omit keys model applies to:

* All new customers with agreements entered into on or after **2026-06-04**.
* Existing customers that integrate, migrate to, or otherwise enable the Omit keys session model, which is recommended.

The Randomized keys model is legacy technical handling and applies only to existing customers that have not integrated or migrated to the new session model.

The applicable model determines how sessions are counted for reporting and billing purposes.

### Limitations

Both options break tracking continuity and limit or disable personalized features, such as:

* `PERSONAL` recommendations
* `FAVORITES` based recommendations
* Evolve functionality (for example, integration with [Voyado Engage](/elevate/docs/integration/voyado-engage-integration))

Always provide both keys whenever possible to maximize the benefits of personalization and behavioral insights, while respecting user consent.

<h3 id="consent-omit-keys">
  Omit keys (recommended)
</h3>

If a visitor does not consent, and the customer’s applicable configuration requires identifiers to be omitted, send requests and notifications without `customerKey` and `sessionKey`. This means Elevate receives the request without those keys; it is not a legal conclusion that the request is anonymous under GDPR or other privacy law.

For such requests, additionally provide the parameter `userContext=anonymous`. See [Query parameters](/elevate/docs/integration/site-integration/query-integration/query-parameters#user-context) for additional supported `userContext` values and integration details.

<h4 id="anonymous-session-count">
  Anonymous session count
</h4>

When integrating with [omitted keys](#consent-omit-keys), requests without a session key do not create sessions as defined by the [session lifecycle](#session-lifecycle). Instead, anonymous sessions are estimated based on the average number of queries per session observed for identified sessions.

**Definitions**

```bash icon="terminal" theme={null}
avgQueriesPerSession = identifiedQueries / identifiedSessions
anonymousSessions    = anonymousQueries / avgQueriesPerSession
```

Where:

* `identifiedQueries` — total number of queries that include a session key.
* `identifiedSessions` — total number of sessions as defined by the [session lifecycle](#session-lifecycle).
* `anonymousQueries` — total number of queries that do not include a session key.

**Total session count**

```bash icon="terminal" theme={null}
totalSessions = identifiedSessions + anonymousSessions
```

If no requests without a session key are sent, the total session count equals the number of identified sessions.

```bash title="Example calculation" icon="terminal" theme={null}
identifiedQueries    = 1200
identifiedSessions   = 300
anonymousQueries     = 600

avgQueriesPerSession = 1200 / 300 = 4
anonymousSessions    = 600 / 4    = 150

totalSessions        = 300 + 150 = 450
```

<h3 id="consent-randomized-keys">
  Randomized keys (legacy)
</h3>

Note that this is legacy technical handling. New integrations should use the [Omit keys](#consent-omit-keys) technical model for non-consenting visitors under this documentation, subject to the customer’s applicable consent or legal basis and configuration.

If a visitor does not consent to behavioral tracking and the legacy randomized keys model applies:

* Generate new random `customerKey` and `sessionKey` values per request or notification.
* Include `notify=false` in all queries to limit behavioral tracking under this legacy model.

## Key storage and transport

The following are implementation options for keeping key handling stable and secure. Select storage and transport methods according to the customer’s security requirements, consent or legal basis, retention rules, and cookie or browser storage obligations.

### Server-side storage

#### Store keys server-side

Store session and customer keys server-side (for example, Redis or Cloudflare KV). When a session is initiated (either anonymously or through login), store the keys under a session-scoped identifier:

```jsonc icon="code" theme={null}
session/{SESSION_ID} => {
   "elevateSessionKey": "...",
   "elevateCustomerKey": "..."
}
```

This enables fast access without requiring a database query and ensures session integrity across requests.

#### Verify identity through a session cookie

Use a secure cookie (for example, `SID`) to look up the session data on each request. This ensures that the session keys have not been manually injected or tampered with on the client side.

### Cookie vs client-side storage

You may choose to store session data in cookies (sent automatically with requests) or in browser storage (like `localStorage`). Below are two recommended patterns, depending on context.

#### Option A: Full key names (for client-side storage)

Use full names when storing data in a structured client context — for example, when using localStorage for personalization, feature toggling, or debugging purposes:

```javascript title="Client-side storage example" icon="js" theme={null}
localStorage.setItem('voyado_elevate.session', JSON.stringify({
 elevateSessionKey: '1234-5678-session-uuid',
 elevateCustomerKey: 'abcd-efgh-customer-uuid'
}));
```

* Recommended storage key — `voyado_elevate.session`
* Recommended field names — `elevateSessionKey`, `elevateCustomerKey`
* Easy to read and aligns with Elevate APIs, logs, and debugging tools
* Not automatically sent with HTTP requests

#### Option B: Short cookie names (for performance-critical headers)

Use shortened names when storing keys as cookies, to minimize HTTP header size and avoid collisions:

```bash icon="terminal" theme={null}
Set-Cookie: ve_sk=1234-5678-session-uuid; Path=/; Secure; HttpOnly
Set-Cookie: ve_ck=abcd-efgh-customer-uuid; Path=/; Secure; HttpOnly
```

* `ve_sk` = Elevate Session Key
* `ve_ck` = Elevate Customer Key
* Short names reduce payload size
* Prefix `ve_` avoids naming conflicts
* Values should be validated against server-side storage before use

Client-side integrations can use the [JavaScript library](/elevate/docs/api/javascript-library), `esales-api`, which provides built-in support for managing customerKey and sessionKey.

### Browser privacy and key persistence

Browser privacy controls such as Apple’s Intelligent Tracking Prevention (ITP) may shorten the lifetime of `localStorage` and JavaScript-set cookies. For more durable visitor identification, prefer a server-side integration where the server reads and writes a first-party cookie on each request and resolves `elevateSessionKey` and `elevateCustomerKey` from server-side storage (see [Implementing visitor identification](#implementing-visitor-identification)). In a client-side integration, keys are managed through cookies or `localStorage` (see [Cookie vs client-side storage](#cookie-vs-client-side-storage)).

If using cookies, set `HttpOnly` for server-only access, or omit it if JavaScript also needs to read the value. Prefer `Secure` and `SameSite=Lax` for general robustness.
