Personalization & optimization

MIDL is personalization-first: a page is data, not markup, so the runtime can serve a different variant of a page (or a different style) to each visitor, measure what works, and promote the winners — with no redeploys. This is the loop that makes MIDL more than a renderer.

author variants ─▶ SERVE (assign per visitor) ─▶ TRACK (impressions + conversions)
       ▲                                                        │
       └──────────────── OPTIMIZE (promote winners) ◀───────────┘

1. Variants

A stored page (frame) can hold several content variants, each with a traffic_percentage. The same idea applies to design systems (styles): several competing DESIGN.md themes can run at once. You author variants once; you don't redeploy to change the split.

2. Serve — deterministic, sticky, per-visitor

On every request the server picks one variant deterministically from a hash of (visitor key + frame id) mapped over the variants' cumulative weights:

  • Sticky — the same visitor always sees the same variant for a page, so the experience is stable (and conversions attribute cleanly).
  • Weighted — across visitors the split matches each variant's traffic_percentage; change a weight and assignment deterministically re-shuffles.
  • Edge-safe — pure hashing (no Math.random, no Node crypto), so it runs on the Cloudflare edge.

Design systems are assigned the same way but site-wide (one style per visitor for the whole site), on an independent seed so a visitor's style and content assignments don't correlate.

Targeting (who sees what)

A variant can carry a targeting rule and take precedence over the weighted pool. Rules match on the visitor context the edge derives per request:

  • geo — country (the trusted edge geo, not a spoofable header)
  • device — mobile / desktop
  • returning — first-time vs returning visitor
  • referrer — where they came from

Targeted visitors get the matching variant; everyone else falls back to the weighted/sticky pool. The served-page cache is segmented by the resolved segment, so personalization is never cached away.

3. Track

Each render emits an impression (frame_id + variant_id + visitor context) off the hot path, and the rendered output is tagged (data-midl-frame / data-midl-variant) so clicks and conversions attribute to the variant that was actually served. Style impressions are tracked separately by design-system id.

4. Optimize — promote winners automatically

A scheduled optimizer Worker reads the telemetry and, per variant, computes the conversion + engagement rate, the sample size, and a statistical confidence (95% level). Once a variant clears a minimum sample (so you're not acting on noise) and is a confident winner, the optimizer promotes it — shifting traffic toward it by adjusting the weights the serve step reads. The loop then repeats with the new split. No human redeploy; the site self-improves on real outcomes.

How you use it

  • Author variants — via the authenticated write API (@wisepunk/sdkframes.create / frames.update) or the admin Studio. Add content variants (or competing design systems) and set each one's traffic_percentage.
  • Target — attach a geo/device/returning/referrer rule to a variant for context-driven selection.
  • Let it run — the optimizer promotes winners on a schedule; watch the admin dashboards for per-variant performance and confidence.
  • Machine-readable — a page's served variant + extracted facts are available at /render/<slug>.midl.json and /render/<slug>.facts.json for agents and crawlers.

Because selection happens at render time over stored data, you change who sees what by editing data — never by shipping code.