Paywall Standardization Guide
Framework T1–T4 · Petewall / Wally
Apple + Google policies, dark patterns, pre-launch checklist
5 mandatory zones, block specs, experimentation dimensions
Block↔component mapping, gap registry, implementation patterns
26 rules for AI generation, unified source of truth
This framework establishes the design, compliance and technical architecture rules for all paywalls generated in Wally (both AI-generated and manual). Every paywall must pass the runPolicyChecks() checks and validate against paywall.schema.json before publishing on Adapty.
Apple App Store Policies
T1 · Section A — Subscription and paywall UI rules
No text string may contain a price or currency symbol. Prices must be dynamically resolved from the store.
The billing period (weekly, monthly, annual, lifetime) must be visible in the pricing block. Showing the price alone is not sufficient.
Prohibited: "guaranteed", "risk-free", "100% safe", "free forever", "last chance" and their equivalents.
If the annual plan is advertised with a broken-down monthly price, the total annual price must also be visible.
The trial period duration must be stated precisely (e.g. "7 days free"). Cannot simply say "free trial".
The legal block must include a reference to the cancellation policy.
The Restore Purchases button/link must be visible. show_restore cannot be false.
The legal block must include privacy_url pointing to the real privacy policy.
The legal block must include terms_url pointing to the real terms of use.
4 testable sub-rules: (1) no plan may be visually pre-selected as the primary action without user choice; (2) the real price cannot be hidden with tiny typography or contrast lower than the broken-down price; (3) the dismiss button must be visually distinguishable from the CTA (cannot have the same color, size or deceptive position); (4) timers cannot be used without a real deadline_utc (fake timers = dark pattern).
The main CTA text must be readable. style_tokens.typography.cta_size ≥ 14.
The contrast between cta_background and cta_text must exceed the 4.5:1 ratio required by WCAG AA.
If there is a timer block, it must use deadline_utc reflecting a real deadline. Infinite or fake timers are prohibited (T1 · X7).
The paywall must include a hero block with a clear product/benefit title.
Google Play Policies
T1 · Section G — Billing Policy and UI requirements
Google explicitly rejects any claim implying a total absence of financial risk.
The phrase "free forever" and equivalents are prohibited by Google Play Billing Policy.
For annual plans, the total amount charged in the period must be visible, not just the monthly breakdown.
Payments must be processed exclusively through Google Play Billing. Prices from other payment gateways cannot be shown.
The user must understand that the subscription renews automatically. This must be in the legal block.
If there is a trial period, the duration must be stated in number of days/weeks. Ambiguous text is not allowed.
The billing frequency must be stated: weekly, monthly, annual, etc. It cannot be inferred from the price alone.
Privacy Policy and Terms of Use links must point to real, active URLs — not placeholders.
If there are multiple plans, no logic may automatically select the most expensive one without user choice.
The user must be able to understand how to cancel before purchasing. This must be referenced in the legal block.
The 5 Mandatory Zones
T2 · Every paywall must include these zones in this order
Main title and value proposition. Position 0, or position 1 if a timer precedes it.
Only 1 hero allowed. heroIdx ≤ 1.List of product features or benefits. Always before pricing.
benefitsIdx < pricingIdxOne card per product_ref. Shows price, period and optional badge.
1 pricing per product_ref. product_ref_id required.Primary action button. Immediately before the legal block.
ctaIdx + 1 === legalIdx. text.cta cannot be "continue", "next", "ok", "accept".Legal text, privacy_url, terms_url and Restore Purchases. Always the last block.
Always last position. privacy_url and terms_url required.Block Specifications
T2 · Required fields, optional fields and constraints
The hero is usually complemented by assets.hero_image_url at the payload level.
items must be an array of strings. Recommended: 3–6 items.
product_ref_id must match an id in payload.product_refs.
text.cta cannot be: continue, next, ok, accept. position: "sticky" anchors the CTA to the footer.
show_restore defaults to true. Cannot be set to false.
deadline_utc is required by policy (X7). duration_seconds is discouraged.
Experimentation
T2 · Allowed variation dimensions, rollout limits
{
"rollout_percent": 10, // ≤ 25. Schema: maximum: 25
"ttl_utc": "2026-06-01T00:00:00Z", // Requerido
"rollback_variant_id": "v0" // Requerido — ID de la variante control
}Design Tokens & Layout Reference
Values extracted from production paywalls — FET D and Popcorn D
#0D0D0DbackgroundApp background#1A1A1AsurfacePlan cards#FFFFFFtext_primaryTitles & prices#AAAAAAtext_secondaryPrice/week, subtitles#8B5CF6accentBadge background (purple)#FFBF1Ecard_borderPlan card border · 2px#FFBF1Ecta_backgroundSubscribe CTA#000000cta_textCTA label · 10.7:1 ✅#777777legal_textDisclaimer copy#BBBBBBfooter_linksTerms / Privacy / Restore#0A0A0AbackgroundApp background (dark teal texture)#1C1C1CsurfacePlan cards#FFFFFFtext_primaryTitles & prices#CCCCCCtext_secondaryPrice/week, subtitles#C8FF00accentBadge bg (lime) · text #000000#D946EFcard_borderFeatured card border (magenta) · 2px#C8FF00cta_backgroundSubscribe CTA (lime)#000000cta_textCTA label · 17.7:1 ✅#666666legal_textDisclaimer copy#D946EFfooter_linksTerms / Privacy / Restore (magenta)xsIcon–text gap, badge vertical padding, dot spacing
smCarousel dot gap, inline element spacing
mdCard inner padding, gap between plan cards, hero→title gap
lgScreen horizontal margin, major section separation
390 × 844 px24 px (lg token)36 px circle · top 50 px · right 20 px~200 px height · image only, no text32–34 px · weight 700 · #FFFFFF · centered16 px · weight 400 · muted · centered · max 2 lines8 px dot diameter · 8 px gap · 32 px total zonepill 999 px radius · 32 px h · overlaps card top~90 px h · 2 px border · 18–20 px radius20 px · weight 40034 px · weight 70013 px · muted color2–3 equal cards · ~70 px h · 2 px border · 16 px radiusfull-width −48 px · 56 px h · 999 px radius · 18–20 px bold10–11 px · 4 lines · muted · centered3 links (Terms · Privacy · Restore) · 14 px · ~40 px hTechnical Validation
T3 · Gap registry, block↔component mapping
AI System — Generation Rules
T4 · 26 rules for app/api/generate/route.ts
Production Examples
12 active paywalls on Adapty — FET D (6) + Popcorn D (6)
Pre-launch Checklist
0/27 completed · 0/11 critical
