User → Customer Conversion Flow (MAI-23)
User → Customer Conversion Flow (MAI-23)
This document defines how Mailoo converts a regular user into a paying customer: the canonical funnel, activation and value moments, paywall logic, pricing and checkout experience, and post-purchase lifecycle. It is the product and UX source of truth; analytics events and KPI formulas live in conversion-flow-analytics{.interpreted-text role="doc"}.
Design principle
Users pay to solve a problem, not to unlock abstract features. Paywalls and copy should anchor on outcomes (reliable capture, scale, team workflow, compliance), not feature checklists alone.
Recommended monetization baseline (v1)
- Hybrid: a free tier (Starter) for activation plus short, contextual trials for selected premium capabilities where seeing is believing.
- Provider-ready checkout: the flow below assumes an external payment provider (e.g. Stripe-style Checkout + webhooks). This doc specifies states and contracts, not a concrete integration.
Canonical funnel
Stages (measurement definitions align with conversion-flow-analytics{.interpreted-text role="doc"}):
- Visit --- landing or deep link without authenticated session.
- Activate --- user completes the minimum setup to use Mailoo for their primary job (see per--use-case activation below).
- Value moment --- user observes a positive outcome tied to their intent (message captured, subscriber created, chat reply sent, campaign delivered, etc.).
- Paywall shown --- user hits a limit, premium gate, or trial boundary; the product surfaces upgrade UI.
- Checkout started --- user initiates paid plan selection / payment handoff.
- Purchase success --- provider confirms payment; entitlement updates.
- Retained --- e.g. D7/D30 active use post-purchase (cohort definitions in analytics doc).
User journey (linear funnel):
Visit → Activate → ValueMoment → PaywallShown → CheckoutStarted
→ PurchaseSuccess → RetainedD7
PaywallShown → Dismissed → ReminderLoop (capped) → CheckoutStarted
Extended journey (decision points):
- Activation: Sign in/up → Create project → Create integration.
- Value: First webhook or message → Subscriber or chat outcome (use-case specific).
- Monetization: Limit / gate / trial end → Paywall modal or sheet → Pricing or checkout → Purchase success; dismiss path applies suppression rules before re-showing paywall.
Activation and value moments (by use case)
Use these as event definitions for product and analytics owners. Exact instrumentation names belong in conversion-flow-analytics{.interpreted-text role="doc"}.
Use case Activation (minimum setup) Value moment (primary) Secondary value signals
FORM / newsletter Project exists; FORM integration created; server or BFF can call webhook with scoped key; at least one allowed origin or endpoint configured. First production form submission creates a Message and Subscriber (or equivalent success path). Campaign created; resubscribe flow used; template used in send.
CONTACT_FORM / feedback CONTACT_FORM integration created; feedback webhook path verified. First production feedback submission stored as message with expected metadata. SLA-oriented teams: first export or dashboard triage action.
JSBOX chat JSBOX integration created; widget snippet deployed on allowed origin; operator session possible. First visitor message received and first operator reply (or resolved session), proving realtime loop. WebSocket stability in production window; CSAT if collected later.
Campaigns / subscribers Subscriber list non-empty OR template ready; integration linked. First campaign or bulk send completes without hard failure. Repeat sends; segment or source filters used.
Blog / MARKET (if in scope for billing) Integration + first published entity or first external API read. First consumer-facing page served from Mailoo content or first order submitted (per product packaging). Repeat orders or catalog sync jobs; editorial pipeline milestones.
If a user skips straight to limits without a value moment, prefer educational nudges (how to finish setup) before aggressive paywalls.
Paywall logic
Trigger families
Family Examples Typical UX
Usage / quota Messages per month, integrations count, API rate tier, storage, seats. Inline meter + modal at threshold; soft warning before hard block.
Premium feature gate Advanced analytics, team roles, custom domains, priority support SLAs, enterprise-only APIs. Contextual sheet on action click; short trial where applicable.
Time-based trial N-day trial of Professional-tier features after explicit opt-in or first premium action. Banner (days left) + final-day modal; never surprise-charge without checkout confirmation.
Priority order (deterministic):
- Critical path completion --- never block saving draft config, signing out, or viewing billing/support. Prefer deferring paywall until after save.
- Hard quota exceeded --- block only the specific action that consumes quota (e.g. reject new webhook), not entire dashboard navigation.
- Trial expired --- gate premium actions; keep read-only access where possible.
- Soft quota / approaching limit --- banner + optional light modal (respect frequency caps).
- Discovery upsell --- lowest priority; only on high-intent screens.
Anti-annoyance and suppression rules
- Frequency cap: at most one paywall modal per session for the same trigger family; at most three per 7 days per user for non-blocking upsells.
- Dismiss cool-down: after dismiss, suppress identical copy/trigger for 48 hours unless quota crosses next hard tier.
- Purchase intent: if
checkout_startedfires, suppress competing paywall modals until checkout succeeds, fails, or expires (e.g. 24 h). - Post-success: no upgrade modals for 72 hours after
purchase_success; show onboarding only. - Quiet hours: optional product policy --- no email reminders 22:00--08:00 local (if timezone known).
- Power users: if user repeatedly hits limits without converting, switch to Contact sales / human outreach instead of stacked modals.
Screen inventory and trigger mapping
Screen / pattern Primary triggers Notes
Pricing hub (/{locale}/pricing) Marketing visit; nav/footer; "upgrade" from dashboard. Plan comparison, FAQ, trust; CTAs vary by audience (below).
Contextual paywall (usage) Soft/hard quota thresholds; API 402/429-style responses mirrored in UI. Show current usage, next tier benefit, link to checkout.
Feature-gate paywall Click on premium-only control or route. Offer trial start if eligible; else checkout.
Trial status banner Trial active, ending (≤3 days), expired. Persistent but dismissible per session for "ending soon" only.
Checkout handoff User chose plan on-site or from paywall CTA. Redirect or embedded provider session; preserve return_url intent.
Payment result Return from provider; webhook latency. Success / failure / pending states (see checkout model).
Post-purchase onboarding purchase_success entitlement active. Checklist: confirm limits, invite team, first premium action.
Lifecycle reminders (in-app + email) Dismissed paywall; trial ending; soft quota sustained. Tied to goals (e.g. "send first campaign"), not clock-only spam.
Pricing hub: contextual CTAs
The live pricing page is implemented in the web app (e.g. apps/web/src/app/[locale]/pricing/page.tsx). Product expectations:
Audience CTA emphasis Destination
Anonymous "Get started" / "Create account" Sign-in / sign-up, then dashboard project creation.
Free plan (logged in) "Upgrade" / "Compare plans" Plan selection or checkout with current project context.
Trialing "Add payment" / "Choose plan before trial ends" Checkout with trial metadata; clear renewal date copy.
Near limit "Raise your limit" with meter snippet Recommended tier pre-selected in checkout.
Enterprise needs "Contact sales" Support / sales form with project id.
Content blocks: hero, comparison table (limits + who each plan is for), FAQ (billing, trials, data, cancellation), optional social proof, footer CTA to support.
Provider-ready checkout state model
States
State machine (text):
[*] → PlanSelected
PlanSelected → CheckoutSessionCreated (create_checkout_session)
CheckoutSessionCreated → AwaitingPayment (redirect_to_provider)
AwaitingPayment → Succeeded (webhook: invoice paid)
AwaitingPayment → Failed (webhook or return_url: failed)
AwaitingPayment → Pending (async_payment_pending)
Pending → Succeeded (webhook: settled)
Pending → Failed (webhook: void or timeout)
Failed → PlanSelected (user_retry)
Succeeded → EntitlementsActive → [*]
Handoff contract (conceptual):
- Client or BFF creates a checkout session with:
user_id,price_id/plan_id,success_url,cancel_url,client_reference_id(e.g. project uid), optionaltrial_days. - Provider redirects user back with session id; app shows pending until webhook confirms (never trust return URL alone for entitlement).
- Idempotent webhooks: processing the same event twice must not double-grant or corrupt state.
- Failure recovery: show reason (card declined, authentication incomplete), preserve cart/plan selection, single primary "Try again" action.
Post-purchase onboarding and upgrade reminders
Onboarding (first 24--72 h)
- Confirm plan name, renewal cadence, and new limits in plain language.
- Guided checklist: invite teammate, rotate API key if needed, enable premium feature user purchased for.
- One optional "celebration" modal; then tool-first UI.
Reminders (non-annoying)
- Prefer goal-based prompts: e.g. user hit paywall for campaigns but has no template --- suggest template + single upgrade CTA, max once per week.
- Trial ending: email + in-app at 7 days, 3 days, 1 day; in-app banner not more than once per day.
- After dismiss: honor suppression; do not escalate to modal without new trigger (hard limit or new premium click).
Rollout recommendation
- Phase 1 --- Baseline: instrument funnel + soft quotas only; paywall modals on hard limits and explicit premium clicks; ship pricing CTAs by audience.
- Phase 2 --- Optimize: A/B copy on paywall headline (problem vs feature), trial length, and comparison table order; read cohort metrics in
conversion-flow-analytics{.interpreted-text role="doc"}.
Related
conversion-flow-analytics{.interpreted-text role="doc"} --- events, KPIs, baseline checklistgetting-started{.interpreted-text role="doc"} --- first-time setup aligned with activation