---
title: Context System
slug: experience/context-system
docTags: 
createdAt: 2026-05-13T15:23:30.127Z
---



The **context** is the runtime data store that every component and data source in a Purple Experience view can read from.

It is a key-value object updated by the Experience as the user navigates, interacts, and as data sources finish loading.

Components reference context values in their config using $context.\<key> — Experience replaces these at runtime with the actual values.

## When to Use $context

Use $context.\* in views.json whenever a component or data source needs to read runtime data, including:

- Current publication
- User attributes
- Device type
- Search query
- Data source results

This is the primary mechanism for dynamic configuration without writing custom code.

# Basic Examples

## Example: Rendering a publication name

:::BlockQuote
\{
&#x20; "type": "html",
&#x20; "tag": "h1",
&#x20; "text": "$context.publication.name"
}
:::

The heading renders the loaded publication name from $context.publication.

## Example: Filtering content using context

:::BlockQuote
\{
&#x20; "type": "list",
&#x20; "dataSource": \{
&#x20;   "type": "content",
&#x20;   "contextKey": "articles",
&#x20;   "filter": \{
&#x20;     "publication": \{
&#x20;       "id": \{
&#x20;         "value": "$context.publication.id"
&#x20;       }
&#x20;     }
&#x20;   }
&#x20; },
&#x20; "content": \{
&#x20;   "type": "content",
&#x20;   "template": "card"
&#x20; }
}
:::

This list filters content items using the publication ID loaded into context.

# Built-in Context Keys

Experience automatically populates these keys in every view.

| Key                 | Type   | Description                       |
| ------------------- | ------ | --------------------------------- |
| platform            | string | WEB, IOS, or ANDROID              |
| today               | string | Current date in YYYY-MM-DD format |
| outlet              | string | Active Angular router outlet      |
| device\_type        | string | phone, tablet, or desktop         |
| device\_orientation | string | portrait or landscape             |
| device\_width       | number | Browser window width              |
| device\_height      | number | Browser window height             |
| connection\_state   | string | ONLINE or OFFLINE                 |
| userAttributes      | object | Persistent per-device user data   |
| accountData         | object | Logged-in user account data       |
| initialUrl          | string | Initial app URL                   |
| pathUrl             | string | Current path URL                  |
| entitlement\_token  | string | Active entitlement token          |
| preview             | string | ?preview= query param (web only)  |
| preview\_app        | string | Preview metadata for in-app usage |

# Data Source Results in Context

When a data source defines a contextKey, the loaded results are published into $context.

## Example

:::BlockQuote
\{
&#x20; "type": "content",
&#x20; "contextKey": "articles",
&#x20; "batchSize": 10
}
:::

After loading:

- $context.articles contains the loaded array
- $context.articles.totalCount contains total matching items
- $context.articles.hasNextPage indicates whether more items exist

# List and Swiper Item Injection

When a list or swiper renders child components, the current item is injected into the child context.

## Default injected keys

| Data source type | Injected key         |
| ---------------- | -------------------- |
| content          | $context.content     |
| publication      | $context.publication |

Additional injected values:

- $context.entryIndex
- $context.groupIndex

## Example: Custom entryId

:::BlockQuote
\{
&#x20; "type": "list",
&#x20; "entryId": "article",
&#x20; "dataSource": \{
&#x20;   "type": "content",
&#x20;   "contextKey": "articles"
&#x20; },
&#x20; "content": \{
&#x20;   "type": "html",
&#x20;   "tag": "h2",
&#x20;   "text": "$context.article.title"
&#x20; }
}
:::

This makes the current item available as $context.article instead of $context.content.

# URL Parameters in Context

All URL query parameters are automatically added to $context as raw strings.

Example:

:::BlockQuote
?issueId=4711
:::

Results in:

:::BlockQuote
$context.issueId === "4711"
:::

## Automatically Resolved Parameters

Some query params are automatically resolved into full Catalog API objects.

| Query param        | Context key          | Type               |
| ------------------ | -------------------- | ------------------ |
| ?publication=\<id> | $context.publication | CatalogPublication |
| ?issue=\<id>       | $context.issue       | CatalogIssue       |
| ?content=\<id>     | $context.content     | CatalogContent     |
| ?taxonomy=\<id>    | $context.taxonomy    | CatalogTaxonomy    |
| ?collection=\<id>  | $context.collection  | CatalogCollection  |
| ?category=\<id>    | $context.category    | CatalogCategory    |
| ?post=\<id>        | $context.post        | CatalogPost        |

:::BlockQuote
Parameters ending in Id are not resolved automatically.
:::

# Path Parameters

Path segment values extracted by the URL resolver are available under $context.pathParams.

## Example

Path definition:

:::BlockQuote
/\:publicationSlug/\:contentSlug
:::

Available values:

:::BlockQuote
$context.pathParams.publicationSlug
$context.pathParams.contentSlug
:::

These values are raw strings, not resolved API objects.

# $global — App-wide Data

Data loaded through globalData in GlobalConfig becomes available globally through $global.\<contextKey>.

## Example

:::BlockQuote
"$global.experienceConfig.featureFlags.showBanner"
:::

## Important

- $global is loaded once at app startup
- It is not reactive
- It does not update on navigation

Use $global for:

- Feature flags
- Shared app configuration
- Global runtime settings

# userAttributes

userAttributes is a persistent key-value map stored per device.

Access values using:

:::BlockQuote
$context.userAttributes.\<key>
:::

Typical use cases:

- Onboarding state
- User preferences
- Consent tracking

Attributes can be updated via:

- set-user-attribute actions
- JavaScript through the Purple API

# $context vs $global vs $functions

| Scope      | Access               | Description                     |
| ---------- | -------------------- | ------------------------------- |
| $context   | $context.key         | Per-view reactive runtime data  |
| $global    | $global.key          | App-wide startup data           |
| $functions | $functions.myFn(arg) | Custom synchronous JS functions |

# Context Object Layers

The final $context object is built by merging multiple layers.

Later layers override earlier ones.

| Layer | Contents                                              |
| ----- | ----------------------------------------------------- |
| 1     | Metadata (platform, today, etc.)                      |
| 2     | URL query parameters                                  |
| 3     | View context and resolved objects                     |
| 4     | Always-present fields (initialUrl, accountData, etc.) |
| 5     | Parent list/swiper injected item                      |

Layer 5 has the highest precedence.

# Context Updates

Experience updates context reactively.

| Trigger                 | Changed keys                    | Timing                     |
| ----------------------- | ------------------------------- | -------------------------- |
| URL query param changes | Query params + resolved objects | On navigation              |
| Data source loading     | Data source contextKey          | After API response         |
| Metadata refresh        | Metadata keys                   | Login/logout refresh       |
| Entitlement changes     | Entire component tree           | Global re-evaluation       |
| User attribute updates  | userAttributes                  | On update                  |
| Account updates         | accountData                     | After refresh              |
| Network changes         | connection\_state               | Online/offline transitions |

Rapid synchronous updates are automatically coalesced into a single async re-evaluation.

# Body Tag Attributes

Exerience automatically applies runtime context values to the HTML \<body> element.

## Example

:::BlockQuote
\<body data-pxp-platform="WEB" data-pxp-app\_id="my-app">
:::

## Available Attributes

| Attribute         | Description                       |
| ----------------- | --------------------------------- |
| data-pxp-platform | Current platform                  |
| data-pxp-app\_id  | App ID in preview mode            |
| Custom attributes | Configured through bodyAttributes |

## Example Configuration

:::BlockQuote
\{
&#x20; "purple": \{
&#x20;   "bodyAttributes": \["device\_type", "locale"]
&#x20; }
}
:::

# Experience 5.0.0 Changes

Since Experience 5.0.0, only these categories are automatically added to the body tag:

1. Platform
2. App ID (preview only)
3. Explicitly configured custom attributes

If older automatic body attributes are required, add them to bodyAttributes manually.

# Advanced Features

## Checking Login State

Use $context.entitlement\_token to conditionally render content.

:::BlockQuote
\{
&#x20; "type": "section",
&#x20; "condition": \{
&#x20;   "value": "$context.entitlement\_token",
&#x20;   "operation": "SET"
&#x20; },
&#x20; "content": \[
&#x20;   \{
&#x20;     "type": "html",
&#x20;     "tag": "p",
&#x20;     "text": "You are logged in"
&#x20;   }
&#x20; ]
}
:::

# Testing Notes & Edge Cases

## $context.content vs $context.\<contextKey>

Inside a list:

:::BlockQuote
$context.content
:::

Outside a list:

:::BlockQuote
$context.articles
:::

These are different values.

## pathParams Keys

Path parameter keys match the slug name in the route definition.

Example:

:::BlockQuote
/articles/\:articleSlug
:::

Available at:

:::BlockQuote
$context.pathParams.articleSlug
:::

## $global Is Not Reactive

Changes to $global require a full application reload.

## Falsy Value Normalisation

The following values are normalized to null:

- undefined
- null
- false
- "undefined"
- "null"
- "false"

Prefer SET / NOT\_SET conditions over direct equality checks.

## Deprecated $context.issue

$context.issue comes from the deprecated issue data source.

Prefer:

- content data sources
- $context.content

## SSR Device Keys

These keys are browser-only and unavailable during SSR:

- device\_type
- device\_orientation
- device\_width
- device\_height

# Related Topics

- &#x20;[Experience Components](docId\:OsNi9cWzjYRd2-tYz4f15)&#x20;
- &#x20;[Data Sources](docId\:fuMBUaBWeON_OTO5wfevf)&#x20;
- views.json
- custom.js and $functions
- Base Component and onConfigChange
