Under the hood
From the moment a visitor lands to the moment personalised content appears: intent classification, atom assembly, brand voice, multi-tier caching, image selection, and a presentation learning system that improves with every session.
Before any of this
Everything below runs on your atom library. Write atoms directly in the admin, or import them from an existing site: Spectare reads your published pages and drafts focused atoms for you to review, so personalisation starts from real content on day one, not a blank library. Nothing publishes without your approval.
Script tag
Client-side slots
spectare.js runs in the browser after page load. It reads UTM params, referrer, and localStorage, calls qualify, then assembles and fills data-spectare-slot divs. Works on any site that runs JavaScript. Visitors see a brief shimmer while the pipeline runs.
WordPress plugin
Server-rendered zones
The PHP plugin calls /api/assemble/ssr on the server before the page is sent. Zone shortcodes or Gutenberg blocks mark where each content type renders: hero, body, proof, cta. Content is in the HTML at first paint. Page caching is bypassed automatically.
Next.js SSR
React server components
Your server component reads signals from the HTTP request before the page is sent. It calls /api/assemble/ssr and passes the result to PersonalisedSection. Content is in the HTML at first paint with no shimmer. The client confirms intent and tracks conversions.
On the client-side path, spectare.js runs on every page load. It reads the referrer, UTM parameters, landing page URL, and any page visit history stored in localStorage from earlier in the session or from previous visits. These signals are sent to /api/qualify/your-org, where Claude classifies them into an audience, funnel stage, and confidence score. The result is a signed context token: not a user profile, not a cookie, not a segment. On the Next.js SSR path, signals come from the HTTP request headers and query string instead. The SSR qualify result is also cached by signal pattern for 7 days, and flushed the moment you change your audience segments or other settings, so repeat visitors with the same page, referrer, and UTM signature skip the Claude call entirely and receive a classification in under 50ms.
spectare.js
collects signals and calls qualify
POST /api/qualify/your-org
sends context to the server
Claude: classify intent
audience · stage · confidence
Signed context token
carries audience, stage, and confidence. Valid for 1 hour.
spectare.js runs client-side on every page load
No training period
Claude is the model. Classification is accurate from visitor one without historical traffic data.
No cookies
Intent is classified fresh each session on the client-side path. On the SSR path, the classify result is cached by signal pattern, not by person. No visitor profile is ever stored.
Returning visitors
Visit history in localStorage means returning visitors are personalised even with no UTM params.
On the client-side path, the context token is passed to /api/assemble/components. On the Next.js SSR path, /api/assemble/ssr handles qualify and assemble in a single server call with no token exchange needed. Either way, the core assembly logic runs: vector search, conversion history, and image selection in parallel, then Claude selecting from a registry of 9 component types. Claude sees which atoms have converted most for this audience and stage, and which atoms have appeared together in past converting sessions. Semantic similarity finds the candidates. Past performance decides between them. The result is a component list that renders in the browser (client path) or arrives pre-rendered in the HTML (SSR path).
Context token
audience · stage · confidence
Vector search
candidates by semantic similarity
Conversion history
atoms + arrangements that converted for this audience + stage
Image selection
best overlay image for audience + stage
Claude: assemble page
picks atoms, picks component types, writes Claude-owned slots in your brand voice
HeroStatement
Claude writes
ImageCtaHero
Claude writes
AtomCard
StatGrid
FeatureList
TestimonialCard
ComparisonTable
CodeBlock
CtaStrip
Rendered page
personalised content in the browser
Runs on the server after qualify returns a token
What Claude writes
Claude generates fresh copy for two component types: HeroStatement (headline and subheading) and ImageCtaHero (headline, subheading, and CTA label). Everything else (AtomCard prose, StatGrid numbers, TestimonialCard quotes) is drawn directly from your atoms and never rewritten.
Brand voice
Set a plain-English instruction in Settings and Claude writes every headline in your voice: "Direct and confident. Short sentences. No jargon." Brand voice only applies to Claude-written components. Your atom content is never rewritten regardless of what you set.
Personalisation runs through two caches, checked in turn, so most visits never call Claude at all. The first reuses the visitor’s classification (signals to audience, stage, and intent); the second reuses the assembled page for that intent. Both are pre-warmed for common patterns and kept for seven days, so even a first visitor usually lands on a warm result and the page is served in about 200ms. The image bandit still runs on every request, even on a hit, so image optimisation never stalls.
Signals to intent
Hit: a visitor with the same signals was classified before, so the audience, stage, and intent are reused with no Claude call. Miss: Claude Haiku reads the signals once, then the result is cached.
Intent to page
Hit: that intent (type, audience, stage) was assembled recently, so the personalised layout is served in about 200ms with no Claude call. Image selection still runs every time. Miss: Claude assembles the components once for that pattern, then writes it back so the next visitor hits the cache.
Two caches, checked in turn. Both are pre-warmed for common patterns and kept for 7 days, so most visits skip Claude entirely.
Zero-flicker delivery for Next.js
Next.js customers can call /api/assemble/ssr from a server component before the page is sent to the browser. The shared Redis cache means warm intent patterns return a pre-assembled component list in under 50ms. PersonalisedSection accepts the pre-rendered assembly as a prop: if the client classify result matches the server result, no DOM update occurs and the visitor sees no content flash at any network speed.
Spectare selects a hero image for each assembled experience. It uses a multi-armed bandit: 90% of requests exploit the image with the highest observed conversion rate for the current audience and stage combination; 10% explore a random image to gather data on untested combinations. Every impression is recorded, and conversions update the conversion rate in real time. No manual A/B test setup required.
Visitor arrives
audience + stage known from qualify
Select image
exploit (90%) or explore (10%)
Record impression
image, audience, and stage recorded
Visitor converts?
Conversion recorded
linked to this image, audience, and stage
Next visitor
image with the best conversion rate for this audience + stage
10% of requests explore a random image. 90% exploit the best-converting image.
Every conversion event records which atoms appeared together in that session. A graph tracks how often every pair of atoms appears together in converting sessions. When the assembly pipeline picks a primary atom, it reads the graph to surface supporting atoms that have actually worked alongside that primary, not just ones that are semantically similar. Claude also receives the top-converting atom IDs for the visitor's specific audience and stage combination, drawn from the last 30 days of conversions. Both signals are passed directly to Claude during assembly, on every path: client-side, SSR, and script tag. The graph is rebuilt nightly from all conversion data.
Visitor converts
session contained atoms A, B, and C
Co-conversion links updated
every pair of atoms in the session gets a stronger link
Next visitor: primary = A
assembly reads the strongest co-conversion links for A
B
weight 12
C
weight 7
D
weight 2
B is chosen. Not just semantically similar. Actually converted together.
The graph is rebuilt nightly from all conversion data. Atom selection reads it directly.
Vector search finds the right atoms. The co-conversion graph finds the right supporting atoms. But which component order converts best? A StatGrid before an AtomCard, or after? Spectare tests this automatically. Set an exploration rate in Settings and a configurable share of visitors see an experimental arrangement. The arrangement is labelled with a strategy tag: data-led, outcome-led, question-led, social-proof-led, or technical-led. Every arrangement is recorded with its impressions and conversions, on every path: client-side, SSR, and script tag, on cache hits as well as fresh assemblies.
Then the loop closes. Once an arrangement clears your signal threshold, Claude is told which arrangements convert best for this visitor’s audience and stage, with the rates that earned them. It prefers a proven arrangement when the atoms support one, and ignores it when they do not: a winning shape built from the wrong content converts worse than an honest one. Exploration runs blind to this, on purpose, so it keeps finding arrangements the data has not seen yet. The atom content never changes. Only the presentation is tested.
There is a discipline to when a winner counts. Ahead is not the same as winning: a 12% rate beating a 10% rate across a hundred visits each sits well inside the noise. So Spectare holds every arrangement’s rate as a confidence interval, not a single number, and only names a winner once that interval clears the runner-up, once its worst case still beats the other’s best case. Until then the honest verdict is that it is still gathering data, and that is exactly what your analytics show, per audience and stage: a statistically real winner, or a clear not-yet, never a coin toss dressed up as a result.
Visitor arrives
intent known from qualify
Exploration check
is this visitor in the configured exploration share?
most visitors · exploit
Proven arrangement
served from Redis cache
exploration share · explore
New arrangement
bypasses cache; strategy tag assigned
Impression recorded
variantId · audience · stage · components
no conversion
Session ends
impression counted, no conversion
conversion
Conversion recorded
linked to this variant, audience, stage
What's working
variants ranked by conversion rate once signal threshold reached
Set exploration rate and signal threshold in Settings. Results appear in Analytics once a variant reaches your chosen impression threshold.
This block was assembled by the exact pipeline described above: your signals were classified into an intent, atoms were selected from the library, and the layout was composed and cached, before the page reached you. Here is what it produced for this visit.
Read visitor intent from referrer, UTM signals, and page context. Assemble personalized experiences in server-rendered HTML before any JavaScript runs.
More of your buyers research through AI, and the visitor is often an agent. The same atom library that personalises pages for people is also published as machine-readable data, so an assistant can read what you offer, accurately and current, without scraping a rendered page.
llms.txt describing what you offer and where to find it./api/content, with a stable slug per item.The demo page runs the full qualify and assemble pipeline live. Describe your site and watch intent classification and content assembly happen in real time.