SentientUI

Changelog

New features, improvements, and fixes — most recent first.

0.31.0— Audiences you have to earn

September 12, 2026

The audience grid now says where every row came from. Groups we suggest, groups you declare, groups we think we can see and groups your traffic has actually proved are four different things, and they used to look identical — which made the product appear to know your visitors before it had met one.

featureEvery audience row says why it exists

Each row in Who sees what now carries its provenance beside its observed share, because the two only mean something together. "Everyone" is live from your first visitor and is where most traffic sits. "Starter" is a suggestion we ship in the box — you did not declare it and we have not proved it, so it argues for itself with its own numbers or you delete it. "Declared" is a group your code tells us about, and we take your word for it. "Candidate" is a pattern we think is forming: it serves nobody and spends nothing. "Unlocked" is one your traffic has proved responds differently, and only then does it get its own versions.

improvementThe four groups we ship are a starting point, not a claim

The default set is no longer presented as though you declared it. It is an editable starter template — rename it, keep the parts that match your visitors, delete the rest. Nothing about it asserts those groups exist on your site.

0.30.0— You approve, it goes live

September 10, 2026

Adaptive UI grows an approval layer: turn on review mode and nothing the AI writes reaches your visitors until you approve it — previewed on your live site first, in your real theme. Versions are now written with much more context (what the region currently says, your brand colors pulled from your own CSS, how each visitor type actually arrives), a new project can have its first drafts waiting before its first visitor, and writing limits are now monthly and set by your plan.

featureReview inbox — approve or reject every written version

Turn on "Require my approval" in Who sees what and every new version parks in a review inbox instead of going live: you see it rendered in your brand colors, read why it was written, and approve or reject in one click. Rejections take an optional note — it makes future versions better. Rejecting an improvement keeps your current winner serving, untouched.

featurePreview on your site — not a mockup

Every pending version has "Preview on your site": it opens your live page with the version rendered in its real place — your theme, your fonts, your layout — with a bar naming what you are previewing and an exit button. Works on React sites and snippet sites alike, and nothing is tracked while you look.

featureFirst drafts before your first visitor

New projects can check "Write first versions with AI" at creation: as soon as your site’s sections are known — from the site scan, or the moment your code registers a region — drafts for each visitor type are queued and parked for your approval. The checkbox forces review mode on, so nothing publishes without you.

improvementWritten versions know your brand and your page

Generation now reads what the region currently says before writing an alternative, matches your site’s register instead of drifting salesy, and pulls brand colors (accent, surfaces, borders) from your site’s own CSS during the site check-up — so designed layouts render in your palette, and a version whose button colors would be unreadable is rejected before it can publish. Non-English sites get the same no-invented-offers protection English sites always had.

improvementMonthly writing limits, guardrails page, and a clearer dashboard

Writing limits are now monthly and set by your plan, with usage shown right on the grid. Guardrails have a real page (Advanced → Guardrails): every automatically paused version, why it was paused, and one click to resume. Project settings has its own place in the navigation, Shopify projects get the no-code experience everywhere, and the install guide now covers AdaptiveSlot — including the server-rendering requirement, up front.

0.29.0— Adaptive UI — Who Sees What

September 10, 2026

SentientUI now writes the versions, not just picks between them. A new grid answers the question personalization always dodged — who sees what, exactly? Rows are your visitor types, columns are the adaptive sections of your page, and every square gives a straight answer: your original, a version being written, or a personalized version with a plain verdict on how it is doing. Every generated version is locked to your brand, explains why it exists, and is measured against a holdout that always keeps seeing your original.

featureWho sees what — one grid, no blank squares

Project → Audiences → Who sees what shows every visitor type against every adaptive section of your page. No square is ever empty: each one reads Your original, Writing…, Waiting (queued behind the daily limit, and it says when it resumes), Improving… (a winning version keeps serving while a challenger is written), or Personalized with a plain verdict — better, behind, about the same, or too early to tell. Generate a version for one square, or Fill the rest for every visitor type still on the original — it honestly skips types with too little traffic to learn from. New & undecided visitors always see your original, by design.

featureGenerated versions are written on brand — and validated, not trusted

Versions are built from a closed set of typed building blocks — headings, text, buttons, badges, images, forms — styled from your site’s own colors and corner radius. Never free-form HTML, CSS, or scripts. A version may re-emphasize offers, prices, and deadlines that already exist on your page, but it can never invent a discount, fake urgency, or mint social proof, and links stay on your own domain. Output that fails validation is rejected with the reason shown — never quietly patched into something servable. Every live version stores a plain-language rationale ("why this exists") and reports how it is doing vs your original, from the same card where you pause, pin, or regenerate it.

feature<AdaptiveSlot> + form blocks for React

Wrap a region in <AdaptiveSlot id="hero-cta">…</AdaptiveSlot> and its content can be served per visitor type — your JSX children are the original and render untouched for holdout traffic, unknown visitors, and every error path, so the worst case is always "nothing changed". Versions can now include a small form (max 5 labeled fields; never password, file, or hidden inputs): submitting fires one of your own project goals and hands the values to your onFormSubmit handler — SentientUI credits the conversion and never stores the values. Mounted slots auto-register in the dashboard as drafts, so the grid grows a column before anything is live in it. Requires SSR preloading via loadAdaptiveDecision({ slotsFrom: 'registry' }).

featureAuto-fill — off by default, and honest about what on means

Flip auto-fill on and, when a visitor of a type with no version yet arrives at an adaptive section, SentientUI queues a version automatically — the visitor’s page never waits. The toggle says exactly what you are agreeing to: new versions go live without review. It ships off, it is a paid-plan feature, and it is capped per day. Leave it off to review every version yourself before it serves.

improvementThe same grid, for agents

Three new MCP tools give AI assistants exactly what the dashboard shows: get_cell_matrix reads who sees what (with per-visitor-type traffic share and auto-fill status), get_cell_detail returns one version’s stored rationale and a plain-language verdict vs your original, and generate_cell queues a new version — same endpoints, same brand lock, operable from Claude, Cursor, or any MCP client.

0.24.0— Declared Personas & Discovered Audiences

August 2026

Your app can now tell the optimizer who it is optimizing for. Declare the role you already know — admin, evaluator, member — and layouts and variants learn per role, reported in your own words. And for the roles nobody declares, SentientUI now discovers candidate audiences from where visitors actually spend attention, and shows you the evidence before any of it touches serving.

featureDeclared personas — optimize per role your app already knows

Pass the visitor’s role at init — init({ persona: 'admin' }) in the SDK, a persona prop on <AdaptiveRoot>/<AdaptiveProvider> (forwarded through SSR), or window.sentient.persona in the snippet, including a function form that reads your own session state. A declared persona is ground truth, so it serves at full confidence from the first request instead of waiting for behavioral inference. Personas are now a per-project vocabulary (Settings → Personas): add the roles your product splits by, rename with the old key kept as an alias so your CSS hooks and history stay intact, retire what you no longer serve. Keep them role labels — never a user id.

improvementTypos can’t silently disappear anymore

A declared value that isn’t in your vocabulary is deliberately not served — but until now it vanished without a trace. The dashboard now counts those values and nudges you: “your app sent staff 1.2k times this week — add it?”, with a one-click add that starts working retroactively for new decisions. Audiences also shows a declared / inferred coverage split, so you can watch adoption as you roll declarations out.

featureDiscovered audiences — segments found from real attention, gated by evidence

A weekly job clusters your traffic by where sessions actually spend attention (share of dwell per section type, with device and traffic-source context) and proposes named candidate segments — “pricing-first mobile visitors”, not personality adjectives. The number of segments comes from your data, never forced. Candidates live in Settings → Personas as a read-only panel and change nothing about serving: each segment must first prove your variants perform differently for it (the same deterministic evidence machinery as the variants page, multiplicity-corrected). Only when every segment passes can you explicitly promote the set to serving — and roll back any time, with nothing deleted.

0.20.0— Devtools Layout Preview

August 2026

The devtools panel now lets you drag page sections into a new order and see the change in place, without touching your live data. Two conversion-goal helpers also got sharper: a dedicated hook for "visitor reached this page" goals, and a way to stop a state-based goal from double-counting on remount.

featureDrag-and-drop layout preview in devtools

The devtools panel now lists your declared page sections and lets you drag any block to a new position — the page reorders in place, no reload. Previewing sets preview mode, so trying an arrangement never trains the optimizer, and a reset restores the decided order. AdaptiveRoot now forwards its sections to the provider so the panel has something to show even before a decision has arrived — previously it was empty in the exact situation you'd reach for it, a consent-gated site before the banner is accepted.

featureusePageGoal — record a conversion when a page is reached

For funnel steps that are a destination rather than a click — pricing viewed, signup form reached, checkout opened — usePageGoal(name, opts?) records the arrival once and holds it until the SDK is running, so a consent gate that opens after the page mounts doesn't lose it. Pass componentId to credit the variant that sent the visitor there. Replaces the hand-rolled useAdaptiveGoal-in-an-effect pattern, which silently double-counted on remount without a manual latch.

improvementonce on useAdaptiveGoal, for state-based conversions

fireGoal(name, { once: true }) records at most once per mounted component — for a conversion that's a state rather than an action ("reached step 3"), not a repeatable click like "add to cart". Without it, an effect that re-runs could double-count the same conversion.

0.19.0— Honest Traffic Numbers

August 2026

If you run ads behind a cookie banner, you were losing visitors you had already earned. Consent now starts tracking instantly instead of waiting on a page re-render, campaign tags survive past the first page, and the dashboard separates visits from unique visitors so you can finally line your numbers up against an ad platform.

fixConsent starts tracking immediately — no reload

grantConsent() only ever worked if you had also opted into preConsentBehavior "statistical_winner". In "control" mode — the default, and the only one that makes no request before consent — it did nothing at all, silently, so the only way to start tracking was a full page reload. Every gated client can now be upgraded in place the moment a visitor accepts. Control mode still sends nothing until they do.

fixAdaptiveRoot honours consent on the server

AdaptiveRoot ran its server-side decision and created a session even when you passed consent={false}, which contradicted the documented promise of no cookies and no events. It now skips both, exactly as it already did for Do Not Track. That means you can render it unconditionally and let the consent prop do the gating, instead of hiding it behind a conditional render and calling router.refresh() — the pattern that quietly lost every visitor who accepted and left within a second or two. See the docs for the recipe.

fixCampaign tags survive the second page

A visitor who arrived from an ad and then clicked through to another page lost their utm_ tags entirely, because a pageview with no tags overwrote the ones already stored. Attribution now persists for the life of the visit. If you run paid traffic, your campaign numbers were undercounting before this.

featureVisits and unique visitors, split out

The dashboard now shows both: visits counts every arrival, including someone coming back three times, while visitors counts people. Paid traffic is broken out separately and labelled with the platform and campaign it came from — the only slice that is comparable with an ad platform's own reporting, since your site total also includes organic and direct traffic it never sent you.

featureconsentFrom — point the SDK at your cookie banner

Tell us where your consent decision lives and the SDK handles the rest: consentFrom={{ cookie: 'cookie_consent', value: 'accepted', event: 'consent-decided' }}. It reads the source on mount, re-reads it whenever your event fires, and starts tracking the moment it grants — nothing requested and no cookie written before that. Keep your own banner or CMP; pass a check() predicate instead of a cookie for Cookiebot, OneTrust and friends. This replaces hand-wiring grantConsent() in your own component.

improvementAdaptiveRoot reads your consent cookie for you

On Next.js, AdaptiveRoot is a Server Component and already has the request cookies, so a cookie-based consentFrom is resolved server-side automatically. A visitor who has already consented gets server-rendered variant assignment with zero layout shift on first paint, and you never call cookies() or name the cookie twice.

improvementgrantConsent() ships with the React package

For apps that drive consent manually rather than with consentFrom, wiring a banner no longer means adding @sentientui/core as a second dependency — import grantConsent straight from @sentientui/react.

0.18.0— Agent Analytics

August 2026

AI assistants now read the web on behalf of your visitors — and you finally get to see it. SentientUI shows which AI agents fetch your site, what they read, and, crucially, when a real person is asking an assistant about you versus a bot just training on your content.

featureSee which AI agents read your site

A new AI agents view shows every AI assistant and crawler that fetched your pages — GPTBot, ChatGPT-User, Claude and Claude-User, PerplexityBot, and more — with what they fetched and how often. It is tracked entirely separately and never counted in your conversion rate.

featureKnow when a real person is asking AI about you

Every fetch is labelled by intent — a live user fetch (someone asked ChatGPT, Claude, or Perplexity and it pulled up your page, right now), search indexing, or model training. "Live user fetches" is the number that matters: it is AI putting you in front of a real person. The assistant never shares the user's actual question, so we surface the purpose, not the prompt.

featureZero-setup capture for Next.js

Most AI crawlers run no JavaScript, so client-side analytics can never see them. AdaptiveRoot now captures them server-side — no middleware, no extra install. Add captureAgents={false} to opt out. (Available on Next.js, where AdaptiveRoot runs on the server.)

improvementStricter privacy defaults

Graph sync now sends only the page path — never query strings or fragments, which can carry tokens or emails. Captured heading text is opt-in (captureDomText), and SentientUI's inline scripts accept a CSP nonce for strict Content-Security-Policy deployments.

0.16.0— Audiences Out of the Box

July 2026

Audience profiles used to require manual setup that almost nobody did — so for most projects they stayed empty. No more. The SDK now understands your pages and how visitors engage with them by default, with zero tagging and zero configuration. Install it, and your audiences fill themselves in.

featureAudience profiles with zero setup

The React SDK and the no-code snippet now detect what each page section is (pricing, hero, social proof, …) and measure how long visitors actually look at it — on by default, no tagging needed. That's the raw material for audience profiles, so Buyers, Researchers, and friends now appear for a standard install instead of requiring manual instrumentation. Explicit data-sentient-type tags still win when you want precision, and everything can be switched off (enableGraph={false}, engagement={false}, or sectionCapture: false). Do-Not-Track, Global Privacy Control, and your consent gate always take precedence.

featureSee how visitors behave on each experience

Expanding a component on the Experiences page now shows behavioral signals per option: frustration clicks, quick exits, long hovers, reading pauses, and text copies. These signals never change your scores — they're there to tell you why an option might be winning or losing.

improvementWho's visiting, over time

The Home page now charts your audience mix over time — how many visitors from each audience were active per day or week — replacing the old single-moment snapshot. Audience growth in Trends also reads chronologically now (prior period first) with a change indicator per audience.

improvementOne audience, one name

Audiences no longer show up twice under singular and plural names — legacy labels are merged onto one canonical audience each. Goals fired straight from code now read in plain language everywhere and can be promoted to primary from the dashboard. The DOM Graph moved under Advanced with a clearer explanation of what its relationships mean.

0.15.0— Numbers You Can Trust

July 2026

A measurement-integrity release. Every project now measures its conversion lift against a built-in control group by default, every dashboard number counts human visitors only, and every surface says exactly what it is measuring. If SentientUI is making you money, the lift card proves it — and if it isn't yet, it says that too.

featureControl group on by default

New projects hold out 10% of visitors as a control group that sees your unmodified site — across every surface: styles, content variants, and section order. The lift card compares converted control visitors against personalized ones with a proper significance test, and is honest when there isn't enough data to call it. Adjustable or disabled per project in Settings.

improvementDashboard counts human visitors only

Automation traffic — E2E test drivers, agentic browsers, bots — is now excluded from every conversion rate, trend, insight, and suggested winner, matching what the optimizer learns from. Agent and crawler activity still shows up, in its own traffic breakdown where it belongs.

improvementForced variants record nothing

Forcing a variant with ?sentient_variant= or the devtools override now records no exposures, goals, or signals — so browsing your own site in a forced state can never teach the optimizer the wrong thing.

improvementProfiles follow sign-in

client.identify(userId) now carries the visitor's best profile onto the current device the moment the identity is linked — returning users get their personalized experience on a new device without re-learning from scratch.

featureAudit log export + team-aware access

The Activity page can now export the filtered audit trail as CSV. Audit history and webhooks both respect per-project member access: admins see everything, editors and viewers see the projects they've been granted.

fixRight-to-erasure hardened

DELETE /v1/visitor now removes every visitor-keyed record in a single atomic operation. Previously the erasure could fail for visitors who had converted; it now completes for everyone, every time.

0.14.0— The Adaptive Ladder

July 2026

Four rungs, one concept: declare a bounded set of variations — styling, content, or section order — and the optimizer learns which one converts best for each visitor type. Start with CSS-only adaptation and climb one rung at a time. Try everything with no account: one command runs the whole SDK in keyless local mode on your machine.

featureStyle rung: persona attributes + useAdaptiveTokens

The SDK sets data-sentient-persona and data-sentient-confidence on <html> before first paint — style visitor types with plain CSS. useAdaptiveTokens declares a bounded token set (e.g. tone: calm/urgent) and serves the best-converting look per visitor type as data-* attributes, server-rendered with zero flicker.

featureSwap rung: useAdaptive

Headless variant selection with measurement built in — a required goal and a bind you attach to the rendered element wire exposure tracking and goal listeners automatically. Supersedes useAssignment (which stays for backward compatibility).

featureReorder rung: <AdaptiveGroup>

Reorder a region into designer-approved arrangements of keyed children — never free shuffling, locked per visit, and any mismatch falls back to your declared order.

featureKeyless local mode + npx @sentientui/cli init

Run the entire SDK with no account and no API key: development builds simulate decisions deterministically on your machine with zero network. One command detects your framework, wires the provider, and scaffolds an example — then open your app with ?sentient_persona=buyer to watch it adapt. Production bundles physically exclude the local engine.

feature@sentientui/snippet for non-React sites

One script tag brings the Style rung to any website: persona attributes plus learned style tokens, applied as data-* attributes so your CSS does the visual work. It never reorders the page, and any error or timeout leaves the page exactly as it was.

improvementHonest learning accounting ("times shown")

Learning now counts one result per completed visit per component, closed out after 30 minutes of inactivity — fixing a bug where extra goal events inflated some variants’ results. Dashboard copy now says "times shown" everywhere, and per-visitor-type learning powers every new surface.

improvementDashboard: adaptive slots, suggestions, per-surface lift

New overview cards show what each visitor type sees and the conversion rate of every look, plus a "Suggested next step" card with ready-to-paste snippets. The conversion lift card now breaks out layout changes vs. style & content changes against your control group.

0.12.0— Testing Toolkit

July 2026

Make adaptive UI deterministic in your own tests. @sentientui/react/testing forces variants and layouts, mocks the API, and asserts goals across Jest, Vitest, React Testing Library, Playwright, and Cypress — so a test that looks for specific copy never breaks when the optimizer serves a different variant, and CI never sends fake traffic into your project.

featurerenderWithSentient + deterministic default

Render any SentientUI component with the control variant and default layout by default (no network), or pass a scenario to force specific variants/layout. Existing tests keep passing with zero per-test setup.

featureMock server + event assertions

setupSentientServer() is an MSW-backed mock backend for every endpoint, with API error injection and event capture — assert that a goal fired with hasFiredGoal(getSentientEvents(), …).

featurePlaywright + Cypress adapters

mockSentient(page, scenario) and mockSentientCypress(cy, scenario) force variants/layout, stub the API, and capture events in E2E. The ?sentient_variant= URL param still works for a zero-import pin.

improvementSSR preload timeout default lowered to 1s

AdaptiveRoot and preloadDecisions/preloadAssignments now default timeoutMs to 1000 ms (was 1500 ms). A decide served from the API in-process cache typically returns in well under 150 ms; the full budget is only reached on a cold start or an API geographically distant from your SSR host, after which default variants render with no layout shift. Override timeoutMs if your API is co-located and warm.

0.11.0— Adaptive DevTools

July 2026

A dev-mode floating widget for @sentientui/react that confirms your integration is wired up and lets you preview it with zero data written. See every <Adaptive> component on the page with its variants and goals, force any variant live, and preview any persona's layout — then ship nothing to production, because the widget is a separate, tree-shaken subpath.

feature@sentientui/react/devtools

Import AdaptiveDevtools from @sentientui/react/devtools and render it inside your provider during development. It lists your components, variants, and goals, forces a variant live via an override, and previews any persona through the new /v1/explain endpoint. Guarded by NODE_ENV so production bundles ship none of the devtools UI.

featurePreview writes nothing

Entering preview mode swaps in an event-suppressing client, so forcing a variant or persona never sends a variant_assigned, goal, or session event — you explore safely against your real page.

0.10.0— Do Not Track

July 2026

SentientUI now honors the browser's Do Not Track signal by default. When a visitor has DNT enabled, the SDK sets no cookies and sends no tracking data — a privacy-first default you can override with your own consent gate.

featurerespectDoNotTrack (default on)

New respectDoNotTrack option on init() and <AdaptiveProvider> (default true). With DNT enabled the SDK stores nothing and sends nothing, overriding consent: true and preventing grantConsent() from re-enabling tracking. Set it false to make your own consent gate authoritative. Also exports isDoNotTrackEnabled() from core.

0.9.0— On-Demand Component Graph

July 2026

The component dependency graph — DOM scanning and reward propagation across related components — is now opt-in per app. A new enableGraph prop on <AdaptiveProvider> and <AdaptiveRoot> lazy-loads @sentientui/core/graph only when you ask for it, so apps that don't need graph-aware rewards keep the smaller bundle. Turning it on powers the dashboard Graph page with live structural and semantic relationships between your components.

featureenableGraph prop on AdaptiveProvider / AdaptiveRoot

Set enableGraph on <AdaptiveProvider> (or <AdaptiveRoot>) to load @sentientui/core/graph on demand and initialise the client with graph scanning + sync enabled. This is what feeds the dashboard Graph page — component relationships and cross-component reward propagation. It is off by default, so lean consumers keep their bundle size unchanged.

0.8.0— Custom API Domain

June 2026

The SDK now defaults to api.sentient-ui.com — SentientUI's own domain with global edge routing. Latency is lower for visitors worldwide, and the integration is no longer coupled to any underlying infrastructure hostname. Existing integrations keep working without any changes.

improvementDefault endpoint moved to api.sentient-ui.com

@sentientui/core and @sentientui/react now point at https://api.sentient-ui.com out of the box. No action required — new and existing installs work without changes. If you proxy the API through your own domain, continue using the ingestUrl or baseUrl overrides in init() / AdaptiveRoot as before.

Phase 5 · SDK 0.6.0— Inferred Goals + Faster Funnels

June 2026

SentientUI now learns from partial funnel completion and discovers meaningful goals on its own. Weighted composite goals let the optimizer converge 3–5× faster on long funnels by crediting each step independently as it fires. Micro-signal detection passively tracks rage clicks, text selection, scroll hesitation, and early tab abandonment — no developer configuration. After 500 sessions in observation mode, SentientUI automatically groups these signals and suggests which ones to promote to real goals.

featureWeighted composite goals

A new WeightedCompositeGoal type on <Adaptive> gives each funnel step its own fractional score. A visitor who viewed pricing (weight 0.2) but bounced before signing up still generates signal. Steps fire independently — the optimizer does not wait for all steps to complete. Existing CompositeGoal behavior (all-or-nothing, full score) is unchanged.

featureMicro-signal detection

Every <Adaptive> component now passively observes four behavioral signals: rage clicks (3+ within 500 ms), text selection / copy, scroll hesitation (3 s of no scroll while visible), and early tab loss (hidden within 15 s). Signals are sent through the existing event pipeline as micro_signal events. No developer configuration required — detection attaches automatically on mount.

improvementSDK performance pass (0.6.0)

Fixed a cache-key mismatch that caused unnecessary /assign calls when sessionSegment was not set, coalesced concurrent assigns for the same component into one request, and capped previewHtml uploads to once per variant per session. Bundles are now minified (react: ~3.7 KB gzip). Breaking for direct core users: preloadAssignments, preloadDecisions, and readSessionCookie moved from '@sentientui/core' to '@sentientui/core/server'. Imports from '@sentientui/react/server' are unaffected.

featureAuto-discovery: inferred goal suggestions

New observation mode for projects. While active, the optimizer computes portraits and audience groups but withholds variant weight updates — every session contributes data without committing to a winner. Once 500 sessions accumulate, SentientUI groups micro-signals by component, labels the top behavioral patterns with AI, and surfaces them in the dashboard as "Moments we noticed". Developers confirm or dismiss each suggestion; confirming shows a ready-to-copy SDK snippet.

Phase 4— AI Intelligence Layer

June 2026

SentientUI adds its first AI layer. Every project page now opens with AI-generated observations about what changed this week — narrator bullets for all paid plans, action recommendations for Growth. Persona audience-group names are generated dynamically from behavioral patterns. Guardrail alert emails include an AI-written diagnosis of why a variant dropped. Agent endpoint usage is now fully observable.

featureAI Insights — narrator bullets and advisor recommendations

Every project overview now shows an InsightsFeed: 3–5 plain-English observations about what changed this week (variant CVR shifts, persona velocity, session volume, guardrail events). Growth tier projects also get 1–2 specific recommended actions. Insights are generated on-demand and cached for 6 hours. The Refresh button triggers a new generation; results appear in under 30 seconds.

featureDynamic persona audience-group labels

Persona audience groups are no longer hardcoded as "buyers", "researchers", "deal-seekers", "browsers". On each insights refresh, AI reads the behavioral profile of each audience group and generates a human-readable label — "Cautious Evaluators", "Fast Converters", and so on. Dynamic labels appear on the Visitors page alongside the raw portrait dimensions.

improvementAI diagnosis in guardrail alert emails

When a variant is auto-paused by the guardrail (CVR dropped below threshold), the alert email now includes a 1–2 sentence AI-written diagnosis of the most likely cause. If the diagnosis is unavailable, the email sends without it rather than being delayed.

improvementAgent call observability

GET /v1/agent/layout calls are now fully tracked — project, visitor, resolved persona, and blocks served are all recorded. The project health endpoint exposes an agent call count. Previously, agent calls were fire-and-forget with no usage visibility.

improvementTrends layer shipped

The dashboard now computes week-over-week CVR deltas, momentum scores (gaining / stable / losing), persona velocity, portrait drift, session volume trends, and per-device / per-source CVR breakdowns. A TrendsCard on the project overview surfaces the top signals. A dedicated Trends tab shows the full breakdown.

Phase 3— Layout Intelligence & Cross-Session Identity

May 2026

SentientUI expands from component-level A/B testing to full-page layout optimisation. A single server roundtrip now decides both section order and variant assignments. Cross-session identity links anonymous visitors to authenticated users so optimizer learning carries over across sign-in. Text content variants ship as a first-class primitive.

featureLayout reordering via /v1/decide

Pass a sections array to <AdaptiveRoot> and SentientUI will reorder your page sections for each visitor in a single server roundtrip — no extra network call, no layout shift. Section order is determined by persona: visitors whose audience group matches a section's historical engagement pattern see that section promoted to the top. The resolved order is seeded into React context so client components stay in sync.

feature<AdaptiveText> — text content A/B testing

A new <AdaptiveText> component lets you run copy experiments without wrapping entire subtrees. Provide a default string and an experiment ID; the SDK fetches the winning content variant from the API and swaps it in after mount. Impressions are tracked automatically.

featureCross-session identity

Call client.identify(userId) after sign-in to link the anonymous session to an authenticated user. Optimizer weights, portrait scores, and persona assignments carry over — returning users see the variant that worked for them last time, not a fresh exploration draw. Pass userId at init time if the identity is already known on page load.

featureNamed goal events from the client

client.goal(name, metadata?) lets any client-side code fire a named conversion event — form submissions, checkout steps, video plays — without wiring up a full event schema. Goals are correlated with the active variant assignments server-side and feed directly into the optimizer as conversion signal.

improvementSingle-roundtrip SSR decide

preloadDecisions() replaces preloadAssignments() for pages that use layout reordering. One POST /v1/decide call resolves section order and all variant assignments together, reducing server-side latency before the first byte is sent to the browser.

improvementLayout scoring and per-persona layout optimizer

Goal events now train a per-persona optimizer on which section orders convert best. The winning layout per persona improves automatically over time as more sessions accumulate. Layout order is also locked per session, so returning visitors within the same session always see a consistent page structure.

improvementSmarter exploration strategy

The per-component optimizer replaced its launch-era fixed exploration schedule with a smarter exploration strategy driven by statistical uncertainty about each variant's conversion rate — variants with less data are explored more, confident winners are served more often — so convergence is faster with nothing to tune.

Phase 2— Intelligent Experimentation

May 2026

SentientUI graduates from a single-component optimizer to a full adaptive experimentation platform. Portraits, persona audience groups, and graph-aware score sharing between related components ship in production.

featureVisitor portraits

The SDK now builds a six-dimensional behavioural profile for every session as events arrive: urgency, attention span, decision stage, price consciousness, risk aversion, and social influence. Each dimension is a 0–1 score computed from dwell time, scroll depth, and event patterns. Portraits update continuously as events arrive; a reliability score (0–1, based on data volume) indicates how much weight to place on each profile.

featurePersona audience groups

A nightly job groups sessions into four behavioural personas — buyers (high urgency, ready to convert), researchers (thorough, high attention, late decision stage), deal-seekers (price-conscious, heavy comparison), and browsers (exploratory, low urgency). Once a session accumulates enough events for a reliable portrait (reliability ≥ 0.3), the optimizer switches from generic device+source segments to persona-specific weights. Each persona can now have a different winning variant.

featureComponent dependency graph and score sharing between related components

The SDK optionally scans the DOM to discover structural and semantic relationships between components — hero → CTA → pricing, for example. These relationships are used to share conversion credit up to two hops: when a goal fires on one component, variants on related components receive a weighted fraction of that score. This means a headline variant gets partial credit for a pricing conversion it influenced, and the optimizer learns faster on low-traffic components by borrowing signal from high-traffic neighbours.

featureSegment-aware assignment

Assignment now resolves the richest available segment for each session: device + source when a session is new, expanding to device + source + persona group once audience grouping has run. Each segment has its own independent optimizer weights, so buyers and researchers can be served entirely different winning variants from the same experiment.

improvementAdaptive exploration per variant

Exploration rate now decays independently per variant as traffic accumulates. High-traffic variants converge to exploitation faster, while low-traffic variants stay exploratory longer so no variant is starved of signal early in an experiment.

improvementDirect vs shared score split in the dashboard

Variant cards now show the breakdown between direct score (events on the component itself) and shared score (credit flowing in from graph neighbours). This makes it clear why a variant won even when its direct conversion rate looks low.

improvementBilling, plan management, and session-limit enforcement

Full billing integration ships: upgrade flows, self-serve plan changes, and session-limit enforcement at the API layer. At launch the Free tier (10k sessions/month) and paid tiers (Starter 100k, Growth 1M) were enforced in production; these limits have since been revised — see the pricing page for current plans.

improvementRate limiting and response caching

The event-ingest and assign endpoints are now rate-limited per project. The current best-variant snapshot per segment is cached server-side, so assignment latency stays low at scale without sacrificing freshness.

Phase 1— Open Beta

April 2026

Initial launch. Core self-learning variant optimizer, <Adaptive> React component, SSR preloading, live dashboard, and the Free plan.

featureSelf-learning variant optimizer

Per-component optimizer with segment-aware weights. Exploration decays as data accumulates; exploitation shifts traffic to the highest-CVR variant automatically.

feature<Adaptive> React component and SSR preloading

Wrap any element in <Adaptive>. Variant assignments are fetched server-side by <AdaptiveRoot> and injected into the initial HTML — zero layout shift, no loading flash, crawlable markup.

featureLive dashboard

Live variant stats via SSE: CVR, Wilson 95% confidence intervals, lift vs control, and segment breakdown by device and traffic source. One-click promote locks the winner.

featureCookie consent integration

Pass consent={false} to AdaptiveRoot or AdaptiveProvider to gate all SDK behaviour behind explicit visitor consent. The SDK does nothing until consent is granted.