Treating event payloads, decisioning context, and request-scoped Handlebars as formal integration contracts rather than simple templates.
In Adobe Journey Optimizer (AJO), context.scope is a request-scoped Data Transfer Object (DTO) that holds the transient data of a single ExperienceEvent. Effective architecture requires differentiating between Persistent Profile Data and Transient Event Payloads. We recommend using Simulation Data Payloads to validate array iteration and using context-scoped Handlebars for mission-critical variables like SKU and Price to bypass the 15-minute Unified Profile ingestion delay.
Most teams approach AJO as if it has a single data surface: “the profile.” In reality, context.scope is closer to a request-scoped DTO that exists only for the lifetime of one journey evaluation.
When an event, API call, or edge decision hits AJO, its payload is hydrated into context.scopecontext.scope and made available to Handlebars, decisioning rules, and ranking formulas in that single execution. There is no guarantee you will ever see that same payload again.
In AJO, context.scopecontext.scope represents the event-side of the ExperienceEvent class: a timestamped snapshot of “what just happened.”
Typical fragments under the context scope include:
context.commerce.ordercontext.commerce.order for purchases, carts, and adjustments.context.web.webPageDetailscontext.web.webPageDetails for URL, referrer, and page name.After the action renders, the data in the context scope is destroyed; only whatever you choose to map into AEP as an ExperienceEvent persists in the long-term profile history.
The most distinctive feature of context.scopecontext.scope is its ability to handle JSON Arrays: product lists, cart items, and recommendation slots.
// Accessing the SKU of the first item in a purchase array
{{context.commerce.order.purchaseItems[0].SKU}}
{{context.commerce.order.purchaseItems[0].priceTotal}}
Adobe now supports contextual iteration helpers. Use the .first().first() function to safely extract a single matching item from an event array without hard-coded index logic.
{{! Find the first line item where quantity > 0 }}
{{@event{PurchaseEvent}.first(context.commerce.order.purchaseItems.quantity > 0).SKU}}ExperienceEvent schemas often define optional fragments. Referencing them blindly leads to null values and blank personalization blocks.
{{! Dangerous: assumes billing exists for every event }}\n{{context.commerce.order.billing.address.country}}
Web-specific fields like context.web.webPageDetails.URLcontext.web.webPageDetails.URL do not exist on Mobile App or Server-Side events. Reusing templates across channels without Conditional Guards guarantees breakage.
{{#if context.web.webPageDetails.URL}}\n Source: {{context.web.webPageDetails.URL}}\n{{/if}}As an architect, your core decision is: does this value only matter for this one interaction, or should it become part of the customer’s long-term state?
Use context.scopecontext.scope for anything that is inherently episodic: the specific cart SKU, the weather at send time, or a one-time API response.
Promote data to profile.scopeprofile.scope when the event expresses a durable truth: the last purchase date, most frequent device class, or long-term preferences.