Bank data into the public cloud – and through the audit
A consumer-finance institution, part of an international banking group, replaces its email system with Adobe Journey Optimizer. Introducing the tool was the smaller part. The hard part was releasing internal customer data to a cloud the bank does not own.
An email system that sends lists
What was running before – and why it no longer held.
Lists instead of profiles. Sending based on exported recipient lists. No continuous customer profile, no reaction to events.
Data in silos. Warehouse, core systems and third parties delivered separately. Merging happened manually, shortly before the send.
One channel. Email alone. SMS and push did not exist as orchestrated channels, at best as isolated solutions.
What Adobe Journey Optimizer is – and why a bank chooses it
Adobe Journey Optimizer is the orchestration application of Adobe Experience Cloud. Not an email tool with a database attached, but an application on Adobe Experience Platform: every journey reads the same customer profile that segmentation, governance and Customer Journey Analytics use.
For the institution this meant one decision that carries everything else: which data leaves the building – and which does not. The warehouse remained the system of record. The platform received a defined slice, loaded in a batch cycle, with retention periods per dataset.
One profile instead of lists. Every send used to read an exported recipient list. In the Real-Time Customer Profile there is one record per customer, shared by segmentation, journey and reporting – whoever withdraws is withdrawn everywhere.
Events instead of send dates. Account opening, an application, an expiring deadline: the journey reacts to what happens, with wait steps and conditions in one logic instead of three tools.
New channels without new systems. SMS and push are outputs of the same journey as email. Consent, frequency and retention apply once – for all channels. That was the prerequisite for starting omnichannel at all.
The system of record stays in the building. The platform receives exactly as much as it needs to activate.
Customer data leaves the building – under what conditions?
At a bank, the question is not whether a marketing platform works technically. The question is which customer data it may see at all, how long it may keep it, and how it is proven that the data disappears again. This release was the longest and hardest part of the project – not the configuration.
The load-bearing architecture decision: the internal data warehouse remained the actual customer data platform. Journey Optimizer did not receive the full customer base, but specifically the attributes, events and flags needed for activation – in dedicated datasets, with a defined lifetime.
Concretely: a strict TTL concept per dataset, dedicated datasets instead of shared storage, deletion logic via the Data Hygiene API, and a robust connection back to the warehouse. Plus the evidence trail for the cyber-security audits: certificates, server locations, data flows, protocols, tool access.
Part of this was the preference center: timestamps and logic were agreed with Legal and Data Privacy, and unsubscribes run back to the warehouse in a 24-hour cycle with error handling – so that a withdrawal arrives where the data is held as system of record, not only in the platform.
Not the raw field into the cloud, but the derived attribute. What the platform does not need, it does not get.
From product to data requirement: the attribute catalogue
“What data do you need?” is the wrong first question. The right one is: which decision should the journey make – and what is the minimum information that carries it?
Before a single field was mapped, a catalogue was built. For every product and every use case of the institution the work ran backwards: from the message that should arrive at the customer, via the decision the journey has to make for it, to the data point that carries that decision. Only then came the technical side – event or attribute, XDM field, source system, load path.
Every row got two columns that are often missing in marketing projects and that decide the release in a bank: purpose and retention period. This table later became the basis for the conversations with Legal and Data Privacy – and the document that lay on the table in the audits.
| Use case | Decision in the journey | Data point | Type | Purpose & retention |
|---|---|---|---|---|
| Welcome track | Is the contract active – and since when? | Contract status | Attribute | Contractual communication · term + statutory period |
| Reacting to an application | Was an application submitted, and is it open? | Application received | Event | Service communication · short period after closing |
| Regional targeting | Which region – without transferring the address? | Region, derived | derived | Regional offers · tied to the contract |
| Channel choice | May we contact by push? | Consent per channel | Attribute | Proof of consent · until withdrawal + evidence period |
| Offer logic | Through which sales route did the customer arrive? | Origin flag | Attribute + validity | Offer control · duration of the programme |
Example rows, anonymised and reduced to the pattern. The real catalogue covered the institution’s product range and was approved row by row.
The third row shows the principle that separates a catalogue from a wish list: the platform does not get the address, it gets the region. For the decision “which regional offer” the derived attribute is enough – and a field that is never transferred does not have to be deleted, protected and explained in an audit. Data minimisation here is not a compliance concession; it saves work in three places at once.
Origin is a basis for decisions, not an administrative field
A customer does not reach the institution only directly. Part of the business runs through sales partners – and what a customer may be offered afterwards depends on where they came from. For orchestration this is not an edge case but a class of requirements in its own right: origin needs its own attribute, a validity period, a precedence rule for the case where several programmes apply – and it must be read at the moment the message is built, not during the nightly import.
That made it clear why a recipient list no longer holds: the same campaign has to produce two different contents for two customers because their origin differs. That is personalisation as a rule set, not as a text block.
// Entry: in the audience, not contacted for 7 daysinAudience("Active customers – credit card") and not inLastDays(#{Profile.lastContact.timestamp}, 7)// Offer logic: check origin while the programme is validnot isEmpty(#{Profile.origin.programId}) and nowWithDelta(0, "days") < toDateTime(#{Profile.origin.validUntil})// Channel: push only with consent and a device, otherwise emailisEmpty(#{Profile.pushToken}) or #{Profile.consents.push.val} != "y"Functions inAudience, inLastDays, isEmpty, nowWithDelta, toDateTime from the AJO function reference; field paths are placeholders.
From catalogue to schema: how an XDM tree is built
The attribute catalogue says which information is needed. The schema says what it looks like in the platform. Adobe puts it as an equation: Class + Schema Field Groups = XDM Schema.
A schema is “a set of rules that represent and validate the structure and format of data”. The class determines the behaviour of the data – record or time-series – and with it which field groups are eligible at all. A field group is a reusable component that defines related fields. The dataset is finally the table that data is ingested into; all data must conform to a pre-defined XDM schema.
For a marketing data model one distinction matters above all: XDM Individual Profile is record-based and describes the attributes of a person – mutable. XDM ExperienceEvent is time-series-based and captures the state of the system when something happened – immutable. Contract status is a profile attribute. “Application received” is an event. This assignment later decides whether a journey can react to an event or can only check a condition.
Which is exactly why Adobe’s best practices put one step before modelling: “Sort your data tables into profile, lookup, and event categories before constructing your schemas.” In the project this was the bridge from catalogue to schema – every row was assigned one of those three categories up front.
Schema "Customer – activation" ├─ Class XDM Individual Profile record-based ├─ Field group Demographic Details standard ├─ Field group Personal Contact Details standard └─ Field group _{TENANT_ID}.activation custom ├─ contractStatus string ├─ regionDerived string ├─ origin │ ├─ programId string │ └─ validUntil date-time └─ consents · email · sms · push object Schema "Application – event" └─ Class XDM ExperienceEvent time-series, immutable identityMap CRMID (primary) · email · ECID
TENANT_ID to avoid collisions with other field groups or fields.” Exactly one primary identity is required for the schema to be enabled for the Real-Time Customer Profile.Through the Schema Registry API the same structure looks like this – the class is referenced via allOf, custom fields live in the tenant namespace:
// Reference the class – the "base class" of the schema{ "title": "Customer – activation", "allOf": [ { "$ref": "https://ns.adobe.com/xdm/context/profile" } ]}// Custom field group: everything under the tenant namespace"_{TENANT_ID}": { "activation": { "origin": { "programId": { "type": "string" }, "validUntil": { "type": "string", "format": "date-time" } } }}// Identities – exactly one primary per schema"identityMap": { "CRMID": [ { "id": "2e33192000007456-...", "primary": true } ], "email": [ { "id": "...", "primary": false } ]}Structure and identityMap per the Adobe documentation (Schema Composition, Schema Registry API); field and tenant names are placeholders from the project pattern. Experience Platform accepts neither null nor empty values in required fields on ingestion.
Two rules from the same documentation were more than style questions in a banking context. “Keep schemas as simple as possible. Add new fields only when necessary.” And: “If you are not sure whether a particular field is necessary to include in a schema, the best practice is to leave it out.” What the catalogue could not justify did not enter the schema – and therefore did not have to be defended in the audit. That schema changes are additive and breaking changes are not supported makes this discipline a necessity: a field that is in, does not quietly disappear again.
The difference between profile and event has one more consequence for retention: according to Adobe, events carry a higher risk of automatically expiring and being purged from the profile store. Anyone building a journey on an event needs to know how long that event is readable at all – a question that sits next to the retention period in the catalogue.
Personalisation is a rule set, not a text block
A data model on its own sends nothing. Between profile and inbox lies the layer a campaign team works with every day: templates, reusable fragments, and the expressions that turn a field into a sentence.
The message designer reads the same profile fields as the journey condition. Two notations are available: Handlebars {{…}} for profile attributes and loops, and the Profile Query Language {%= … %} for functions and conditions. In a bank, one detail matters more than any design question: what happens when a field is empty? An optional attribute may be empty – the salutation may not.
// Fallback when the attribute is empty or nullHello {%= profile.person.name.firstName ?: "there" %},// Content by contract state – one template, two statements{%#if profile.contract.status = "active" %} … content for existing customers{%else%} … neutral content without product reference{%/if%}Syntax per the AJO personalisation documentation: ?: is the default fallback helper, PQL comparisons use a single =, not ==. Field paths are placeholders.
The second building block are fragments – “reusable components that can be referenced in one or more emails”. For a regulated institution this is not convenience but governance: mandatory disclosures, imprint, right-of-withdrawal notice and unsubscribe link live centrally, once. When Legal changes a wording it changes everywhere – per the documentation, changes “are automatically propagated to all contents using that fragment, including live journeys and campaigns”, as long as inheritance has not been broken.
One limit of this belongs in the operating manual, because otherwise it surfaces in production: adding new personalised attributes to a live fragment is not supported. Anyone wanting to extend a personalisation plans it in advance – or builds a new version.
On top came content templates as starting points for recurring tracks, and event tagging so that reactions flow back into the profile as events and the next journey can respond to them. Only with this layer does a data model become something a team can operate without developers – and that was precisely the goal of the handover.
Three layers that have to hold together
Data foundation
Schemas and datasets following the attribute catalogue, mapping from the warehouse via Data Prep – including transformations and calculated fields, so that derived attributes are created on ingestion and not in the source system. Plus identities and merge rules, retention per dataset, and sandboxes for development, test and production so a change is not verified in live operation.
Channels
Email replacing the legacy system, plus SMS and push as orchestrated channels of the same journey. Consent and frequency apply per customer, not per campaign. Custom actions connect systems that have no channel of their own.
Operational readiness
SSO via SAML, a role model for campaign engineering, administration and approval, tasks and dependencies in Jira, dry runs before every step, and handover to the internal team with their own accounts.
The release did not happen at the end but ran in parallel from the data foundation onwards – every new data category brought a new review round.
What an audit wants to see – and what it will not accept
The release did not happen in a single meeting. It was a series of reviews with the institution’s architects, with cyber security and with data privacy – each with its own questions and its own evidence.
What was delivered was not a presentation but a chain of evidence:
- Data flows per data category – from source through ingestion and profile to channel and deletion, as a diagram and as a description.
- Server locations and certificates of the vendor, mapped to the services actually in use.
- Deletion concept with evidence – TTL per dataset, Data Hygiene API, and the answer to how you can tell that deletion happened.
- Role and permission model – who may see which data, who may send, who may approve, connected via SSO.
- Withdrawal path – preference center, timestamps, return flow to the warehouse in a 24-hour cycle with error handling.
- The attribute catalogue – every row with purpose and retention, approved rather than asserted.
And the counter-check, because it costs the most time in projects like this: an audit does not accept “we only use what is necessary” without a field list. No deletion without evidence of how it is proven. No role that nobody owns by name. And no architecture sketch that does not show where the data sits.
Preparing these six points before the first audit shortens the release considerably. Supplying them afterwards means renegotiating every time.
What was handed over so it keeps running without me
A platform only the consultant can operate is not a result. The handover was therefore not a meeting at the end but a workstream of its own – parallel to the build.
Three workshop days took place on site, alongside remote sessions for accounts, sandbox approvals and open questions from day-to-day work. More than ten people were trained, from the campaign team up to management – not the same content for everyone: whoever builds journeys needs conditions and fragments; whoever approves needs the role model and the approval path; whoever owns the budget needs the architecture in one picture.
Blueprints and templates for the recurring tracks, so the team adapts rather than deciding from scratch for every campaign.
Documentation of the data model – the attribute catalogue with purpose and retention, the schemas, the mapping rules from the warehouse.
Role and approval model with individual accounts via SSO: campaign engineering, administration and approval separated instead of one shared login.
Backlog and dependencies in Jira, so open points do not live in an email thread after handover.
Dry runs before every step – documented, including the errors they found. That is the part that saves time at the next release.
In the end the data model, pipelines, deletion logic, SSO, roles, channels and approval processes were set up and documented. The security audits were evidenced with certificates, data flows and server locations. The internal team had their own accounts – and production was ready, the first test email delivered successfully.
How this enablement part is structured is described in detail under Enablement.
Where the road was meant to lead
The batch cycle was a deliberate decision, not a limitation: as long as the warehouse is the system of record, there is no reason to move data faster than it is needed. The planned next stage after rollout was near-real-time synchronisation via the Edge Network and Real-Time CDP – so that an event triggers a journey in seconds instead of in a daily cycle.
Email sending then becomes customer journey orchestration: SMS and push were connected, decisioning and in-app prepared. And because every journey runs on the same profile, decisions become measurable – who received which message when, what happened next, where the path breaks. For campaign engineers and architects this is exactly where the lever sits: not sending more emails, but making data-driven decisions visible across the company.
Same pattern, different auditor
The task repeats in every regulated industry: a marketing tool is introduced, but the real work lies beneath it – in the data model, the retention periods, the evidence for the auditors.
In pharma the auditor is MLR instead of cyber security, the HCP profile replaces the customer profile, and instead of account status a claim approval decides. The structure of the problem stays the same: the system of record stays in the building, the platform receives exactly as much as it needs to activate – and the attribute catalogue decides how long the release takes. How this differs by industry is described under Industries. Why an initiative like this only holds if marketing, analytics, leadership and architecture have the same discussion is covered in the fundamentals article What Omnichannel Really Means.
Adobe Experience Cloud in detailWhat decision-makers ask before a project like this
Does our data warehouse remain the system of record?
What does a security audit actually require?
How long does the data release take?
What happens with unsubscribes and objections?
Does this require real time?
Sources: Adobe Experience Platform blueprints, XDM Schema Composition, Best Practices for data modeling, Schema Registry API and the AJO personalisation and function references (Experience League, accessed 2 Sep 2026). Own illustrations. Project details anonymised; what is described is the work delivered – no customer data, no operating figures.
