Documentation · OF1 Product

The page your visitor sees
isn't the page you published.

OF1 Product turns a static site into a surface that adapts per visitor. This page explains how a page is generated, what signals drive it, what data is (and isn't) stored, and how to integrate the service into your own site. It describes the of1-gen-web-service — the runtime that produces personalized pages.

Audience: product & web teams Runtime on Cloudflare Workers

What of1 is

of1 is an AI service that assembles a web page in real time for the individual visitor in front of it. Instead of serving one page authored once by hand, it reads the visitor's context, works out what they're trying to do, retrieves the most relevant content from your own corpus, and composes a page that fits that intent — every time, with no rules to write and no segments to maintain.

The critical design decision is that the LLM never writes HTML. It decides what to show and in what order; your design system decides how it renders. That keeps output on-brand, accessible, and impossible to break — while still being fully personalized.

of1 runs on Adobe Edge Delivery Services — Adobe's edge-native web platform. Edge Delivery Services is a hard requirement: of1 assembles pages from the block-based content model that EDS provides and delivers them at the edge.

Adapts

Per visitor, per intent

Every element is reconsidered for the person viewing it — not a segment they were bucketed into.

On-brand

Blocks, not markup

The model selects from 30+ pre-built, CSS-styled blocks. It never invents new markup.

Grounded

Your content, via RAG

Copy is filled from your products, features and FAQs — retrieved by vector search, not hallucinated.

Private

Signals stay client-side

Behavioural context is gathered in the browser and sent per request. of1 stores no visitor profile.

The core idea

For decades, marketing meant shouting at categories and cohorts. Your visitors now spend all day with tools that respond to their intent — then land on your one static page.

Segments are a confession that you don't know your customer well enough.

of1 removes the segment. There are no rules to write, no content matrix to maintain, no A/B variants to fork. The page is generated for the one person viewing it — and it should feel authored, not targeted. As the deck puts it: most AI wants you to know it's there; ours wants you to forget.

Request lifecycle

A single call to POST /api/generate runs an ordered pipeline at the edge. Results stream back as newline-delimited JSON (NDJSON) so the page renders block-by-block as it's produced.

1
Capture context at the edge, from the browser
The request carries the visitor's query, plus optional signals: browsing[] (URL, dwell time, scroll depth), interests[], a pre-classified intent, segment (device, region) and acquisition (UTM, referrer). A tenant id identifies the brand.
2
Analyze behaviour
Classifies the traffic source (shopping / social / search / email from the referrer) and derives a journey stage — awareness → consideration → decision — from session depth and dwell time. This frames the tone and depth of the page.
3
Classify intent
The query is sorted into one of comparison, recommendation, deep-dive, budget or discovery — by LLM (default) or keyword fallback. Personas and use-cases configured for the tenant are matched in parallel.
4
Retrieve content RAG
The query is embedded and used to search a per-tenant vector index over your products, features and FAQs. Up to ten ranked, relevance-scored results are returned — this is the grounded content the page is built from.
5
Build the prompt
Brand voice, optional brand-governance rules, the block/template guide, the retrieved content, and the analyzed intent are compiled into a system + user prompt for the model.
6
Generate & stream
The model emits structured JSON describing the page. The worker streams it as NDJSON events — section (one per block), suggestions (follow-up prompts), debug (timings, model, token usage) and done — so the client renders progressively.

The two-phase LLM

When template routing is enabled for a tenant, the model runs twice: first it picks a layout that fits the intent, then it fills that layout with retrieved, on-brand content.

From visitor to page · one request, two phases
Visitor context
Collected at the edge
  • Referrer & query
  • Device & time of day
  • Scroll & click history
  • In-session intent
Never leaves the browser
→
LLM reasoning engine
model-agnostic · GPT · Claude · Llama · Mistral
Phase 1 · Select a template
A template is a block order that fits the visitor's intent.
LLM output
first-full-recommendation
Block order
heroproductcompareverdict
→
Phase 2 · Fill the blocks
Inputs
RAG retrievalvector search over pages, images, docs
Brand layervoice, compliance, design system
LLM output
every block filled, on-brand
→
Personalized page
Rendered from blocks
Feels authored —
not generated.
No HTML invented · no CSS touched — the LLM only decides which blocks, in what order, and what fills them.

In Phase 1 the model classifies intent and picks one template from the tenant library (e.g. first-full-recommendation) — a template is just a fixed order of blocks, and the model never reorders it. In Phase 2 it fills each block's slots from RAG-retrieved content, shaped by the brand layer (voice, compliance, design tokens); image URLs are validated against an allow-list before render.

The output is a complete page — assembled from pre-styled blocks — that feels authored rather than generated. The default flow works the same way without a template step: the model composes hero / columns / cards sections directly.

Why two phases
Separating structure (which blocks, in which order) from content (what goes in them) keeps each model call small and verifiable, and means the layout is always one of a known, tested set.

Blocks & templates

Why the LLM picks blocks instead of writing HTML — and how templates map intent to a layout.

A typical web page is 10,000–50,000 tokens of HTML. Asking an LLM to emit that raw is slow, brittle, and unsafe: it hallucinates class names, breaks CSS and drops accessibility attributes, and every page would need validating. of1 sidesteps this by reusing the separation of concerns every CMS already has:

Separation of concerns · the LLM decides what, not how
Never touched by the LLM

Styling

Design tokens + CSS. Owned by developers.

The LLM chooses

Structure

Blocks — which ones, and in what order.

The LLM fills

Content

Copy, images and data, from your corpus.

In AEM Edge Delivery Services a block is simply a named table in a document — authors write them in Google Docs or Word, developers style them with CSS. of1 selects from 30+ of these pre-built blocks; it never invents markup. A template is a block order that fits a visitor's intent, grouped into families:

FamilyWhen it's usedExample templates
First recsVisitor lands cold — surface a confident top pickfirst-full-recommendation, first-discovery-broad, first-budget-focused
Follow-upThey're comparing — narrow the field, go head-to-headfollowup-head-to-head, followup-narrow-field, followup-deep-compare
Quick answersOne specific question — answer it, nudge a next stepquick-yes-no, quick-with-recommendation, quick-feature-explain
Inside one template · a fixed block order
Template
first-full-recommendation
01 hero
02 product-recommendation
03 comparison-table
04 verdict-card
05 recipe-cards
The LLM fills each block — it never reorders them.

Signals captured

Context is gathered client-side and passed on the request. It describes the current session — not a stored identity.

SignalFieldWhat it tells of1
Referrer & queryacquisition, queryWhere the visitor came from and what they asked
Device & regionsegmentForm factor and locale for framing
Scroll & click historybrowsing[]URL, dwellTimeMs, scrollDepth per page — journey depth
Interestsinterests[]Pre-computed topic scores that bias retrieval
In-session intentintentA pre-classified goal, if the client has one
Prior queriesconversationHistory[]Earlier turns, for de-duplication
Privacy — never leaves the browser
These signals are assembled client-side and sent only as part of the generation request. of1 does not set tracking cookies or build a cross-session visitor profile. The visitor's IP (from cf-connecting-ip) is used for rate-limiting only and is not written to storage.

Beyond the browser. The context model is open-ended — anything that helps describe who the visitor is and what they need can be passed on the request. The client-side signals above are the zero-setup default, but an integrator can enrich them with consented, first-party data:

Adobe profile

AEP & Real-Time CDP

The Real-Time Customer Profile from Adobe Experience Platform — audiences, computed attributes and edge-resolved identity.

Known customer

CRM & account

Lifecycle stage, tier, entitlements and purchase history for a signed-in visitor.

Loyalty

Membership & rewards

Points balance, status and benefits that change what's worth surfacing.

Commerce

Catalog & cart

Live stock, pricing, active promotions and the current cart or basket state.

Environment

Place & time

Geo, locale, weather or nearest-store inventory for context-aware framing.

Identity

Consented identity

A first-party identity graph that ties sessions together — with the visitor's consent.

A natural fit with Adobe Experience Platform
Because of1 is Adobe technology, connecting it to the Real-Time Customer Profile in Adobe Experience Platform / Real-Time CDP is a natural extension. An edge or server integration can resolve the visitor's profile — audiences, computed attributes and propensity scores — and pass it into the generation request, so the page reasons over the same unified profile the rest of your Adobe stack already uses. No built-in connector is required: any profile data that describes intent can be handed in on the request.
Still your data, still stateless
These richer sources are opt-in and first-party — supplied by you, with consent, as part of the request. of1 itself stays stateless: it reasons over whatever context it is handed for that one request and keeps nothing afterward. Any signal that helps describe intent can be plugged in.

What is stored

The service is stateless per request. It persists your content configuration — not visitor data.

StoreHoldsNotes
R2 object storageTenant configs (products, personas, features, FAQs, templates, brand voice)Static, brand-level — not request-specific
Vectorize indexEmbeddings of your products / features / FAQsContent only, scoped per tenant; no request metadata
KV cacheLoaded configs (300s), suggestions (300s), governance rules (3600s)Short-lived caches, keyed by tenant
Stateless by design
/api/generate does not log individual requests or responses to persistent storage. Behavioural analysis is computed per request and discarded. Multi-turn personalization works because the caller tracks and re-sends the behaviour profile — of1 keeps nothing between calls. Each tenant's configs, vectors and cache keys are fully isolated.

API endpoints

Public endpoints are CORS-enabled (Access-Control-Allow-Origin: *) and need no auth. Generation is rate-limited to 30 requests / 60s per IP. Admin endpoints require a token.

POST/api/generateGenerate a page — streams NDJSON
POST/api/suggestFollow-up exploration prompts
POST/api/personalizeRewrite existing page elements per behaviour
POST/api/tenants/:id/syncPull & index tenant config from EDS (admin)

A minimal generation request:

# POST /api/generate { "id": "frescopa--of1-demo--aem-growth-adoption", "query": "recommend a coffee machine for me", "browsing": [{ "url": "/espresso", "dwellTimeMs": 8200, "scrollDepth": 0.7 }], "segment": { "device": "mobile", "region": "ch" } }

The response is a stream of NDJSON lines — section, suggestions, debug, done (default flow) or a single page event with full HTML + stylesheet (template-routing flow) — which the client consumes as it arrives. Per-request overrides such as ?device=mobile&region=fr&provider=bedrock&model=claude-opus are supported.

Embed the SDK

The client SDK handles streaming, DOM injection and the debug widget so you don't have to.

<!-- 1. Load the SDK --> <link rel="stylesheet" href="https://of1-gen-web-service.franklin-prod.workers.dev/sdk/of1-client.css"> <script src="https://of1-gen-web-service.franklin-prod.workers.dev/sdk/of1-client.js"></script> // 2. Initialise against a container OF1.init(document.querySelector('#of1'), { id: 'frescopa--of1-demo--aem-growth-adoption', query: userQuery, });
Debug mode
Append ?debug=1 to any page using the SDK to reveal a widget showing the model used, timings, intent classification, RAG match counts and token usage — plus a runtime model-override control (stored in sessionStorage).

Tenant configuration

A tenant is your brand. Its content and behaviour are defined by JSON files authored in AEM / EDS and pulled into of1 via sync.

FileDefines
brand-voice.jsonPersonality, tone, vocabulary, words to avoid
products.jsonProducts — id, name, category, price, keywords, highlights, images
personas.jsonPersonas and their keywords / preferences
use-cases.jsonUse-cases matched against the query
features.json, faqs.jsonFeature descriptions and Q&A used in RAG
templates.json / block-guide.jsonTemplate routing definitions, or block layout rules
suggestions.json, cta-template.jsonUI strings and the CTA mustache template

Publish these at https://<id>.aem.page/of1/config/<file>.json, then call POST /api/tenants/<id>/sync (with the admin token) to pull them into R2 and rebuild the vector index. Configs are cached in KV for 300 seconds.

Models & infrastructure

ConcernWhat runs it
Page generation & intent classificationCerebras gpt-oss-120b (default; model-agnostic — GPT, Claude, Llama, Mistral, Bedrock)
Template selection & suggestionsCloudflare Workers AI @cf/meta/llama-3.1-8b-instruct
Embeddings for RAGCloudflare AI @cf/baai/bge-base-en-v1.5
ComputeCloudflare Workers at the edge
StorageR2 (configs), Vectorize (embeddings), KV (cache)
Brand governanceAdobe Brand Governance agent (optional; colours, tone, guardrails per domain / segment)
Model-agnostic
The reasoning engine is not tied to one provider. Providers are adapters — Cerebras, Workers AI and Bedrock ship today — and the model can be overridden per request for testing.
of1 · generative websites for an audience of one. This page documents OF1 Product — the runtime that produces personalized pages (of1-gen-web-service). © 2026 Adobe — early-stage technology by the Adobe Experience Manager team.