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 / desktopreturning— first-time vs returning visitorreferrer— 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/sdk→frames.create/frames.update) or the admin Studio. Add content variants (or competing design systems) and set each one'straffic_percentage. - Target — attach a
geo/device/returning/referrerrule 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.jsonand/render/<slug>.facts.jsonfor agents and crawlers.
Because selection happens at render time over stored data, you change who sees what by editing data — never by shipping code.