Integrating AEM Headless with a React SPA for Scalable Web Platforms

Adobe Experience Manager has long powered enterprise websites for banks, insurers, and government departments across Australia. As digital teams in Sydney, Melbourne, and Brisbane rebuild legacy experiences around component-driven JavaScript frameworks, the conversation has shifted from "can AEM serve modern apps?" to "what is the cleanest way to combine AEM's content tooling with a React single-page application?"

The headless mode of AEM, exposed through Content Fragments and a GraphQL endpoint, gives content authors a familiar authoring surface while liberating front-end engineers from JSP and Sightly. A React SPA can then consume structured content over HTTP, render pages on the client, and still inherit the workflow, permissions, and translation governance that AEM was built for.

For Australian organisations bound by the Privacy Act 1988 and the Notifiable Data Breaches scheme, keeping content in a governed repository rather than scattered across front-end repos also reduces compliance friction. The pattern described below reflects what delivery teams at the official conference website discussed during the 2016 sessions in Chicago, and it remains a baseline for many local projects today.

Why AEM Headless Pairs Naturally with React

React's component model lines up well with the way Content Fragment Models are designed in AEM. Each fragment exposes a typed schema covering text, date, reference, and JSON objects, and a React component can mirror that schema almost one-to-one. Teams that previously translated Sightly templates into React props can reuse the same mental model, which lowers the cost of retraining.

Another benefit is author control. Editors in Adelaide or Perth who work on marketing pages don't need a developer's help to publish a new product launch. They edit a fragment, hit publish, and the GraphQL layer serves the update to the SPA on the next request. This decoupling matches how Australian retailers like Kmart and Woolworths separate their merchandising teams from their engineering squads.

Finally, AEM's dispatcher and CDN integration can still front the SPA. The SPA's static bundle is delivered from Apache or a CDN, while dynamic content comes from the /content/cq:graphql/global/endpoint.json endpoint, all behind a single domain. That single-domain pattern keeps cookies clean and avoids the cross-origin headaches that plagued earlier headless experiments.

Designing Content Fragment Models

Before any code is written, the content model deserves a whiteboard. A typical Australian financial-services site might define fragment models for product cards, rate tables, disclosure footnotes, and PDF links. Each field needs a label, a type, and a default — properties that appear directly in the authoring dialog.

References between fragments matter too. A "campaign" fragment might reference a list of "offer" fragments, allowing editors to assemble landing pages without touching code. In AEM 6.5 and AEMaaCS, the schema editor exposes single-, multi-, and string-reference types, and the React side uses GraphQL fragments to pull the full tree in a single query.

Localisation is the next decision. Australian sites often need English-only at launch, with Mandarin or Vietnamese added for community-facing portals in Sydney's inner west or Melbourne's south-east. AEM's language copy feature lets authors translate fragments within the same model, and the React layer can resolve the active locale from the URL prefix or a cookie.

Choosing how the front-end reaches those fragments is the next fork in the road. The patterns below have all appeared in Australian projects over the last five years.

Approach Content delivery Front-end rendering Best fit Trade-offs
GraphQL via /content/cq:graphql Typed, queryable, low over-fetch Client-side hydration Large content models, multi-channel reuse Requires GraphQL client and schema governance
REST using Sling Model Exporter JSON via .model.json selectors SSR or static build Small sites, simple schemas More endpoints, harder to evolve
Assets API for media only Binary references in fragment Client-side render Media-heavy microsites Manual linking in code
SPA Editor SDK + Remote SPA Component-manifest driven Client-side with hydration Marketing teams that need in-context editing Tighter coupling to AEM runtime

A deeper look at how one team ran similar integration patterns under heavy load is preserved in the session persistence at scale recording, which is still a useful reference for anyone sizing dispatcher caches today.

Building the React Layer

The React side usually starts with Next.js or a custom Webpack/Vite setup. Either way, the data-fetching layer should abstract AEM behind a small client interface so unit tests can mock the endpoint without hitting the dispatcher. A typical project uses Apollo Client for GraphQL queries, with persisted queries enabled to shrink the payload and protect the endpoint from arbitrary queries.

Routing is where teams often trip up. A React SPA serving /personal-banking/home-loans/ must map to the right AEM path, fetch the right fragment, and fall back gracefully if the path doesn't exist. Using a route resolver JSON document stored as a fragment lets editors add new pages without redeploying the front-end, a useful capability when product launches run on quarterly cycles aligned with the Australian financial calendar.

State management stays simple: Redux Toolkit or Zustand for cross-page state, React Query for server cache. The AEM endpoint is treated as a slow, cacheable source, which fits well with HTTP caching headers set on the dispatcher.

Authentication, Compliance, and Local Legislation

When the SPA renders authenticated content, for example a customer's insurance policy summary, the integration must respect AEM's authentication model. Token-based authentication using a short-lived bearer token issued by an upstream identity provider (Okta, Azure AD B2C, or an in-house system) works cleanly with AEMaaCS and avoids exposing long-lived credentials to the browser.

Australian privacy law adds further constraints. Under the Notifiable Data Breaches scheme, any breach that is likely to result in serious harm must be reported to the Office of the Australian Information Commissioner within 72 hours. Logging access to personal data, including who viewed which fragment, becomes a first-class requirement. AEM's audit logs, piped into a SIEM, give compliance teams a defensible trail.

Government projects may also need to satisfy the Australian Signals Directorate's Essential Eight maturity model. While that framework targets operating systems and patching, the principle of only standardising on supported applications applies to the React build too. Teams should pin dependency versions, scan with tools like Snyk or Sonatype, and document the supply chain before go-live.

Performance, Caching, and Geographic Latency

Distance matters. A round trip from Sydney to a us-east-1 origin can add 200 milliseconds, and end users notice. Local teams typically deploy the AEM publish tier in ap-southeast-2 (Sydney) or replicate to ap-southeast-4 (Melbourne) when Azure is used, then front the SPA with a CDN that has Australian PoPs — Cloudflare, Akamai, or Fastly all qualify.

Caching should sit at three layers: the CDN for static bundles, the dispatcher for HTML and GraphQL responses with Cache-Control: max-age=300, and the React side using React Query's staleTime to avoid refetching on every navigation. Cache keys include locale and device class so mobile and desktop variants don't pollute each other.

Image delivery deserves special attention. AEM's built-in adaptive image servlet can resize on the fly, but for a high-traffic campaign it pays to pre-generate renditions at build time and serve them from object storage. The React component then picks the closest rendition based on srcset and the actual rendered size.

Practical Recommendations Before Go-Live

A few patterns have proven reliable across the Australian projects surveyed:

  • Define fragment models in a dedicated repo, not in AEM itself, and promote them through environments like code.
  • Version the GraphQL schema with every content model change, and publish a changelog authors can read.
  • Set up a staging dispatcher that mirrors production's cache headers, so performance tests are not skewed by cache misses.
  • Wire AEM's audit log into your SIEM on day one; retrofitting it later is painful.
  • Run a load test from a Sydney-based k6 or Gatling agent to catch latency issues before the campaign lands.

Applying these recommendations early avoids the rework that comes when accessibility, compliance, or caching gaps are discovered late in delivery.

Teams that want to see the patterns in action can register for the conference and join the hands-on labs in Chicago. Recordings from earlier years remain a useful reference for anyone maintaining an AEM-plus-React stack across Australian time zones.