PPactDocs
Productivity

Personalization

Edge web personalization: A/B variant blocks served to your website by a lightweight snippet, with Wilson-scored stats and one-click winner promotion.

Personalization

Personalization is Pact's edge web experimentation surface. You define a block on your own website (a hero headline, a CTA, a pricing banner), give it two or more variants, and Pact decides which variant each visitor sees — then measures which one converts. A lightweight JavaScript snippet on your site does the fetching and event reporting; everything else lives in Pact.

Live, with a real backend

Blocks, variants, targeting rules, exposures, conversions, and Wilson-scored stats are all real and enforced. The admin routes derive tenant_id from the auth context; the public serve/record routes are authenticated by a per-tenant HMAC write key. Data lives in personalization_blocks, _variants, _rules, _exposures, and _conversions.

The moving parts

  • Blocks — a named slot on your site. GET/POST /v1/personalize/blocks, PATCH /v1/personalize/blocks/{id} (update / archive).
  • Variants — the competing versions. POST /v1/personalize/blocks/{id}/variants. A default variant is auto-created so the snippet always renders something.
  • Rules — targeting predicates that decide who is eligible for a block. POST /v1/personalize/blocks/{id}/rules; resolved server-side by core.personalization.rules_engine.resolve_block.
  • StatsGET /v1/personalize/blocks/{id}/stats returns Wilson lower-bound conversion intervals per variant, so a variant isn't declared a winner on a handful of lucky clicks.
  • PromotePOST /v1/personalize/blocks/{id}/promote makes the winner the new default and archives the losing rules in one call.

How a page view flows

code
visitor loads your page
        │
        ▼
  p.js snippet  ──GET /v1/personalize/serve?host=…&visitor=…──▶  resolved variant
        │                                                         (rules + variant pick)
        ▼
  renders variant, fires  POST /v1/personalize/expose
        │
   (visitor converts)
        ▼
        └────────────────  POST /v1/personalize/convert

The public serve, expose, and convert endpoints take no bearer token — they run on your visitors' browsers. Instead they are authenticated by a per-tenant write key derived by HMAC in core.personalization.signing. A cross-tenant attempt fails signature verification with a 401, and rotating the signing secret invalidates every active snippet at once. Visitor identifiers and user agents are hashed (hash_visitor_id, hash_user_agent) before storage.

AI-suggested variants

POST /v1/personalize/blocks/{id}/ai-variants returns AI-drafted variant copy for a block's prompt. When an LLM provider is configured it calls it; when none is wired it falls back to a deterministic heuristic so the button is never broken in dev. Suggestions are returned without being persisted — the editor previews them and the marketer chooses which to save.

Requires the marketing module

Every personalization route is gated behind require_module("marketing"). The surface is unavailable to tenants without that module enabled.