Skip to main content

Competitor Onboarding Comparison + OptoLink Onboarding Recommendation

Scope studied: the full "time to first value" path — from the Sign Up button through to the moment the user sees the result of clicking a generated link reflected in their dashboard.

sign-up → account creation → workspace/org creation → plan selection → (payment) → first link creation → first click → click result visible in analytics

Purpose: ground OptoLink's own onboarding design in what 12 competitors actually do, then propose a concrete flow that respects OptoLink's locked decisions (Clerk, 5-role RBAC, EntitlementsService, subscription+overage billing, SandboxPaymentProvider).

Status: Research + recommendation only. No source code changed. Date: August 2026 Author: Product research agent


1. Executive Summary​

  • There are two onboarding worlds, and they don't mix. Link-shorteners / dedicated deep-linkers (Bitly, dub.co, ChottuLink) get you to a visible click in 2–5 minutes — no SDK, no app, no sales call. Mobile Measurement Partners (AppsFlyer, Adjust, Branch, Kochava, Singular, Airbridge, Tenjin) require SDK integration into a real, live app before you can see any attribution data — a multi-day-to-multi-week bottleneck. Airbridge pegs average MarTech time-to-value at ~44 hours with the lowest onboarding-completion rate of any SaaS category (source: Airbridge blog — self-serving, but directionally consistent with every MMP doc) [airbridge.io/en/blog/mmp-time-to-value].

  • Most MMPs now offer self-serve free signup (AppsFlyer Zero, Adjust Base, Kochava Free App Analytics, Singular Free, Airbridge DeepLink, Tenjin Free) — but "you can sign up" ≠ "you can see value." The signup-to-first-click gap is where they all bleed. This is verified for all six [appsflyer.com/pricing, adjust.com/pricing, kochava.com/get-started, singular.net/pricing, airbridge.io/en/pricing, tenjin.com/pricing].

  • The card question splits cleanly by archetype. Self-serve link tools: no card, free forever (dub.co, Bitly, ChottuLink). Branch is the outlier — its free tier (~10K MAU) requires a credit card within 30 days [help.branch.io/v1/docs/self-serve-gating]. MMPs gate real features behind sales conversations.

  • The "first value" mechanism is the crux, and it's where OptoLink has a structural edge no competitor has. MMPs can't show deferred deep-link resolution without a real install. Shorteners can show a click but can't show deferred deep-link resolution at all (Bitly doesn't do it; dub.co's iOS deferred support is "coming soon") [bitly.md, dub-co.md]. OptoLink already has a deferred-flow simulator backend (POST /dev/deferred/simulate, currently only wired to the admin sandbox) that synthesizes a full click → fingerprint → deferred match → resolution result without a real app or SDK [optolink-backend/src/sandbox/sandbox.controller.ts, optolink-portal/src/hooks/use-sandbox.ts].

  • OptoLink's current onboarding is the thinnest in the set. A single "Name your workspace" screen → dashboard. The PRD §4.1.2 plan chooser and 4-step wizard (register app → configure domain → first link → SDK guide) were never built [optolink-portal/src/app/(auth)/onboarding/page.tsx, v2-backlog.md Phase 2]. Shipped plan config is Free (10 links / 1K clicks / owner-only / hard block) + Starter (200 links / 50K clicks / overage) [optolink-backend/src/entitlements/plans.config.ts].

  • OptoLink should target the "self-serve PLG deep-linker" archetype (like dub.co / ChottuLink), NOT the sales-led MMP archetype. The PRD positions OptoLink explicitly below every MMP and above every shortener [comparison-summary.md §8]. The onboarding must feel like dub.co, not like AppsFlyer.

  • Single strongest recommendation: make "see your first click result" a simulated, in-portal step — surface a portal-facing wrapper around the existing deferred simulator so a brand-new Free user creates a link and watches a synthetic click resolve (with match tier, confidence, and deep-link payload) in under 5 minutes, zero app/SDK setup. No competitor on this list can do that. Pair it with Free-default + no-card + inline first-link creation.


2. Competitor-by-Competitor Onboarding Teardown​

Sources are cited inline. "Unverified" marks anything I could not confirm. Competitor docs in docs/competitors/ are feature/pricing-rich but thin on signup-flow detail, so most onboarding facts below come from web research against official help/pricing pages.

2.1 Branch.io — Self-serve MLP, but card-gated and tightening​

  • Sign-up methods: Email + OAuth (self-serve account creation at help.branch.io) [help.branch.io/onboarding-guide].
  • Workspace/org creation: "Step 1: Branch account" — set default timezone, link domain, attribution windows in App Settings [help.branch.io/onboarding-guide].
  • Plan selection / card: Free tier (~10K MAU) is self-serve but requires a payment method within 30 days of account creation [help.branch.io/v1/docs/self-serve-gating]. Branch has been tightening self-serve — "limiting access to creating Branch Links and certain [features]" for non-paying apps [help.branch.io/v1/docs/self-serve-gating]. Paid plans are sales-led and opaque [branch-io.md].
  • First link: "Basic Link Configuration" covers redirects, social previews, deep linking (URI schemes), UTM tags [help.branch.io/account-hub/docs/basic-link-configuration]. You can create a link without SDK integration, but it won't deep-link.
  • See a click result: Requires the Branch SDK integrated into a live app + real installs for attribution data. A link can be created and clicked, but deep-link/deferred value is invisible without the app. Unverified: whether Branch shows a test/sandbox click in the dashboard before SDK integration.
  • Time to first value: Hours to days for a click count; days to weeks for deferred-deep-link value (SDK + app release cycle). Friction: card-required free tier, SDK integration, app store release.
  • Steal / avoid: Avoid the 30-day card demand on a "free" tier (bad first impression). Avoid gating link creation for self-serve apps. Branch's domain-config-first structure is fine but front-loads config that a new user can't meaningfully complete without a live app.

2.2 AppsFlyer — Self-serve Zero plan, but value is SDK-blocked​

  • Sign-up methods: Self-service signup at appsflyer.com/sign-up; no card [appsflyer.com/pricing].
  • Workspace/org creation: Account → register an app (platform, app ID, SDK key). "Zero" plan is free-for-life, explicitly owned/earned media only — not for paid campaigns [appsflyer.com/pricing, businesswire.com AppsFlyer Zero launch].
  • Plan selection / card: Zero = free, no card. Includes a "Welcome Package" of 12K free conversions over the first 12 months (a one-time pool, not monthly-renewing) + 30 days of premium add-ons [appsflyer.md, what-is-free.md]. Growth is $0.07/conversion; Enterprise is sales-led.
  • First link: A marketer alone can create a OneLink (redirect to app stores / web URL) without a developer — "Only a marketer is required" [support.appsflyer.com OneLink creation]. True deep-link-into-app needs the OneLink template + Universal Links/App Links configured.
  • See a click result: Attribution data requires SDK integration + real installs [support.appsflyer.com Basic SDK integration guide]. OneLink click counts appear once the SDK is live and clicks flow.
  • Time to first value: Days to weeks (SDK QA + app release). Friction: SDK integration is the dominant cost; the 12-month free pool expiry is a time bomb.
  • Steal / avoid: Steal the "marketer can make a link without a dev" separation. Avoid the one-time-pool + 12-month-expiry "free" — it's a trial in disguise [what-is-free.md].

2.3 Adjust — Self-serve Base, SDK-blocked value, 12-month free clock​

  • Sign-up methods: Self-serve signup; free "Base" plan [adjust.com/pricing].
  • Workspace/org creation: "Getting started with Adjust" — login, create app, configure [help.adjust.com getting-started-with-adjust].
  • Plan selection / card: Base = free, 1,500 attributions/month for up to 12 months, no card [adjust.md]. Paid (Core ~$79–199/mo) and Enterprise are usage-based/custom-negotiated [adjust.md].
  • First link: TrueLink branded links created post-app-setup. Deferred linking via TrueLink.
  • See a click result: Requires SDK integration + real installs [adjust.md]. No documented simulator/test-click path for new users. Unverified.
  • Time to first value: Days to weeks (SDK). Friction: 12-month free expiry; SDK integration; opaque paid pricing.
  • Steal / avoid: Avoid the time-limited free tier (12 months then forced pay). The free tier that expires is the worst onboarding promise in the set.

2.4 Kochava — Self-serve Free App Analytics, SDK-blocked value​

  • Sign-up methods: Self-serve signup form — "Complete the sign-up form below to create your own Free App Analytics® account" [kochava.com/get-started].
  • Workspace/org creation: Form-based; app registration follows [kochava.com/get-started].
  • Plan selection / card: Free App Analytics = 10K conversions/month forever (renews monthly), SAN-only attribution + SKAN + basic fraud, no card [kochava.md, what-is-free.md]. Foundation = $500/mo; Enterprise = $2,000/mo (sales-led).
  • First link: SmartLinks created post-app-setup; enhanced deep linking on Foundation+ [kochava.md].
  • See a click result: Requires SDK integration (Kochava "Free Growth SDK") + real installs [kochava.com/get-started]. No documented demo-data/simulator. Unverified.
  • Time to first value: Days to weeks (SDK). Friction: the $0 → $500/mo jump is the steepest in the market; complex omnichannel platform for a deep-link-only need.
  • Steal / avoid: Steal the genuinely-forever free tier. Avoid the giant free→paid gap ($0 → $500).

2.5 Singular — Self-serve Free, most generous MMP free tier, SDK-blocked​

  • Sign-up methods: Self-serve signup; also a "Request a Demo" sales path [singular.net, support.singular.net Complete Onboarding Guide].
  • Workspace/org creation: Sign up → "Complete Onboarding Guide" assumes you have Singular access + the SDK [support.singular.net Complete Onboarding Guide].
  • Plan selection / card: Free = 15K conversions/month forever, includes full attribution + fraud + cost aggregation + APIs — the most feature-rich free tier among MMPs, no card [singular.md, what-is-free.md]. Growth = $0.05/conversion; Enterprise sales-led.
  • First link: Tracking links created post-app-setup; deep linking available [singular.md].
  • See a click result: Requires SDK integration + real installs [singular.md]. No documented simulator. Unverified.
  • Time to first value: Days to weeks (SDK). Friction: conversion-based billing scales linearly; SDK is mandatory.
  • Steal / avoid: Steal the "everything included on free" philosophy (it converts). The dual self-serve + demo path is sensible for a hybrid market.
  • Sign-up methods: Self-serve; DeepLink Plan is explicitly "a self-serve plan" [airbridge.io/en/pricing]. Core plan signup at app.airbridge.io/signup.
  • Workspace/org creation: Marketer's onboarding overview + developer getting-started guide split [help.airbridge.io airbridge-onboarding-overview, /developers/getting-started].
  • Plan selection / card: DeepLink Plan = permanently free below 10K MAU, no card; $3/1K MAU above [airbridge.md]. Core = $40/mo with 30-day free trial. Growth = custom/sales [airbridge.md].
  • First link: Deep links, short links, QR codes created in-dashboard; FDL migration bulk-import tool [airbridge.md].
  • See a click result: Requires SDK integration. Airbridge's own content argues MMP SDK setup "takes weeks" and MarTech TTV averages ~44h — positioning Core as the faster alternative via native S2S subscription integrations [airbridge.io/en/blog/mmp-sdk-setup-takes-longer-than-first-campaign, mmp-time-to-value].
  • Time to first value: Days to weeks (SDK). Friction: SDK; the DeepLink/Core/Growth split is confusing.
  • Steal / avoid: Steal the explicit "self-serve plan" labeling (removes sales-call anxiety). Avoid the three-plan-type confusion. The 44h-TTV framing is a useful competitive argument OptoLink can borrow.

2.7 Tenjin — Self-serve free, all-features-included, SDK-blocked​

  • Sign-up methods: Self-serve — "Sign up with Google" or work email, no credit card [tenjin.com/pricing].
  • Workspace/org creation: Quick; all features on every plan [tenjin.md].
  • Plan selection / card: Free = 2K conversions/month forever, all features, no card [tenjin.md, what-is-free.md]. S/M/L plans $200–$700/mo. Enterprise sales-led.
  • First link: Tracking links via dashboard/API; deferred via deeplink_url param — basic, not a dedicated link product [tenjin.md].
  • See a click result: Requires SDK (iOS/Android/Unity only — no Flutter/RN). No documented simulator. Unverified.
  • Time to first value: Days to weeks (SDK). Friction: limited SDK platforms; basic deep linking.
  • Steal / avoid: Steal the "Sign up with Google + no card + all features" zero-friction entry. Tenjin is the closest in spirit to OptoLink's target vibe, but for MMP not deep-linking.

2.8 Bitly — Self-serve URL shortener, instant first click (no deep linking)​

  • Sign-up methods: Email or Google login; plan selection (free/paid) during signup [bitly.com/blog/how-to-get-started-with-bitly].
  • Workspace/org creation: Implicit on signup; no separate org step.
  • Plan selection / card: Free = 5 links/mo forever, no card. Paid Core $10/mo+ [bitly.md].
  • First link: "Quick Create on your homepage (fastest)" — paste URL, get short link instantly; can even create without signing in [bitly.com blog].
  • See a click result: Instant — clicks visible in real-time analytics immediately after creating and clicking the link [bitly.md].
  • Time to first value: ~2 minutes. Friction: none for a click; but no deferred deep linking at all [bitly.md].
  • Steal / avoid: Steal the Quick Create / instant-first-link pattern and Google OAuth. Avoid gating real value (device data, deep linking) behind $199/mo Premium.
  • Sign-up methods: Email/OAuth; self-serve [dub.co].
  • Workspace/org creation: Create workspace (name + slug) — the central org unit [dub.co/help/article/what-is-a-workspace].
  • Plan selection / card: Free = 25 links/mo + 1K events, no credit card, includes deep links + A/B testing + 3 custom domains [dub.co/pricing, dub.co/help/article/free-trial]. Separate 14-day trial of paid features (per workspace; card requirement for the trial not explicitly confirmed — unverified) [dub.co/help/article/free-trial].
  • First link: Revamped onboarding has guided steps: create a link → add custom domain → invite teammate [dub.co/changelog/new-onboarding].
  • See a click result: Instant — real-time analytics, time-series charts; "Dub Analytics tracks upwards of 10M clicks/day" [dub.co/help/article/dub-analytics].
  • Time to first value: ~2–5 minutes. Friction: minimal. But iOS deferred deep linking is "coming soon" (Android only) [dub-co.md].
  • Steal / avoid: Steal the workspace→link→domain→teammate guided wizard. This is the single best onboarding template for OptoLink. Avoid shipping deep-linking as a half-baked feature.
  • Sign-up methods: Self-serve; no sales call [chottulink.com/pricing].
  • Workspace/org creation: Guided: "set up your link domain, choose where you want deep links to work, and define a safe fallback experience" [chottulink.com onboarding docs].
  • Plan selection / card: Free = 25K MAU forever, unlimited links/clicks/QR, no card [chottulink.md]. Indie $19/mo. No card on free.
  • First link: Part of the guided domain+routing setup.
  • See a click result: Link resolution/click tracking works without SDK (redirect to store/web); full deferred deep-link delivery requires the SDK. Unverified: whether ChottuLink shows a test click in-dashboard.
  • Time to first value: ~5–15 minutes for a working redirect link; deferred delivery needs SDK. Friction: SDK for true deferred value; free tier hides analytics behind Indie [chottulink.md].
  • Steal / avoid: Steal the domain-first guided setup and "Firebase DL replacement" positioning. Avoid stripping analytics from the free tier (it hurts the "see your first click" moment).

2.11 Linkrunner — Self-serve MMP, per-install, India-focused​

  • Sign-up methods: Self-serve [linkrunner.io].
  • Workspace/org creation: App registration; SDK setup docs for iOS/Android/KMP [docs.linkrunner.io].
  • Plan selection / card: Free = 25K attributed installs (one-time pool, never expires), all MMP features, no card [linkrunner.md, what-is-free.md]. Growth postpaid ($0.01/install).
  • First link: OneLink format; created in-dashboard.
  • See a click result: Requires SDK + real installs (attributed installs are the billing unit). No documented simulator. Unverified.
  • Time to first value: Days to weeks (SDK + installs). Friction: SDK; one-time free pool; India-focused support hours.
  • Steal / avoid: Steal the postpaid/no-annual-lock-in model vibe. Avoid the one-time free pool.
  • What it was: Completely free, no tiers, no card. Integrate SDK → create links → done. Set the market expectation that deep linking should be free and simple [firebase-dynamic-links.md].
  • Time to first value: Was minutes post-SDK-integration.
  • Why it matters: Every competitor is measured against the "free + simple" FDL baseline. OptoLink's positioning is the alive, maintained FDL replacement [comparison-summary.md §8].
  • Lesson: Simplicity + free was the winning combo; the product died from Google neglect, not from the model.

3. Comparison Matrix​

CompetitorSignup methodSales-led?Card required upfront?Plan chosen during onboarding?Can create link in onboarding?Can see click result in onboarding?Time-to-first-valueFriction level
BranchEmail/OAuthNo (free) / Yes (paid)Yes (within 30 days)Implicit (free default)✅ (no deep-link w/o SDK)❌ (needs SDK+app)Hours–weeksHigh
AppsFlyerEmail (self-serve)No (Zero) / Yes (Ent)NoImplicit (Zero default)✅ (OneLink by marketer)❌ (needs SDK+installs)Days–weeksHigh
AdjustEmail (self-serve)No (Base) / Yes (paid)NoImplicit (Base default)✅ (TrueLink)❌ (needs SDK)Days–weeksHigh
KochavaForm (self-serve)No (Free) / Yes (paid)NoImplicit (Free default)✅ (SmartLinks)❌ (needs SDK)Days–weeksHigh
SingularEmail / Demo req.No (Free) / Yes (Ent)NoImplicit (Free default)✅ (tracking links)❌ (needs SDK)Days–weeksHigh
AirbridgeEmail (self-serve)No (DeepLink/Core) / Yes (Growth)NoSelf-serve plan pick✅ (deep links)❌ (needs SDK)Days–weeksMed–High
TenjinEmail / GoogleNoNoImplicit (Free default)✅ (tracking links)❌ (needs SDK)Days–weeksMed–High
BitlyEmail / GoogleNoNo✅ during signup✅ (Quick Create)✅ instant~2 minVery Low
dub.coEmail/OAuthNoNo (free); trial card unverifiedImplicit (Free default)✅ (guided wizard)✅ instant~2–5 minVery Low
ChottuLinkEmail (self-serve)NoNoImplicit (Free default)✅ (domain-guided)🔶 redirect-click yes / deferred needs SDK~5–15 minLow
LinkrunnerEmail (self-serve)NoNoImplicit (Free default)✅ (OneLink)❌ (needs SDK+installs)Days–weeksMed–High
Firebase DL(Google account)NoNoN/A (all free)✅ (SDK/API)🔶 after SDKMinutes (dead product)Low
OptoLink (current)Clerk <SignUp> (email/OAuth)NoNo (Free)❌ not built❌ (no wizard)❌ (no simulator surfaced)N/A — wizard stops at "name workspace"Med (thin)

OptoLink's friction is "medium-thin": low effort, but zero value delivered — the user names a workspace and lands on an empty dashboard with no link, no click, no proof the product works.


4. Key Patterns / Archetypes​

Archetype A — Sales-led MMP (high power, high friction)​

Members: AppsFlyer, Adjust, Kochava, Singular, Branch (paid), Airbridge (Growth), Linkrunner, Tenjin. Shape: Self-serve signup exists, but real value is gated behind SDK integration into a live app + real installs. "First click result" takes days–weeks. Free tiers are generous but often time-bombed (Adjust/AppsFlyer 12-month expiry) or one-time pools (AppsFlyer/Linkrunner). Paid plans are conversion/MAU-based and escalate to sales conversations. The lesson: This is the world OptoLink is explicitly priced below [comparison-summary.md §8]. Do not copy this archetype.

Members: dub.co, Bitly, ChottuLink. Shape: Email/Google signup → workspace → create a link inline → see a click instantly. No card on free. Guided wizard (dub.co: link → domain → teammate). Time-to-first-value in single-digit minutes. Deep linking is present but shallow (Bitly doesn't do deferred; dub.co iOS deferred "coming soon"; ChottuLink needs SDK for deferred delivery). The lesson: This is the UX bar OptoLink must meet. Steal the wizard shape; beat them on deferred-deep-link completeness.

Archetype C — Developer-first / API product​

Members: dub.co (open-source, API-first), Tenjin (API + raw data). Shape: API keys and raw data access front-loaded; onboarding assumes a technical user. Lower polish, higher flexibility. The lesson: OptoLink's API-key flow (Phase 7) and analytics export (Growth) belong here — but not in the critical onboarding path. Keep them as post-first-value steps.

Archetype D — Dead-but-legendary free-simple (Firebase DL)​

The "free + dead simple" baseline. OptoLink's stated positioning is the alive FDL replacement [comparison-summary.md §8]. The onboarding must feel as simple as FDL felt.

Archetype B (self-serve PLG deep-linker), with a deferred-deep-link completeness none of them offer. OptoLink is a deep-linking+attribution+billing product priced at $19–$149 [optolink-pricing.md] / €0–€199 [PRD §5.3], below every MMP and above every shortener. The onboarding must deliver a visible click result in minutes like dub.co/Bitly, but for deferred deep linking — which shorteners can't show and MMPs can't show quickly. The mechanism that makes this possible is OptoLink's existing deferred-flow simulator (see §5).


Design north star: a brand-new user clicks Sign Up and, in under 5 minutes, watches a synthetic click on their first link resolve into a deferred deep-link payload in their dashboard — with zero app setup and zero SDK integration. Then they get a clear "connect your real app" path.

Locked constraints respected (audit)​

  • ✅ Clerk creates the org (clerk.createOrganization); webhook seeds org_plans [AGENTS.md, v2-backlog.md Phase 2].
  • ✅ 5-role RBAC — the creator becomes OWNER via Clerk membership (Phase 3).
  • ✅ EntitlementsService — checkQuota('links') before link create; recordUsage after (Phase 4). Simulated clicks are not recorded (demo flag).
  • ✅ Subscription + overage — Free = hard cap; Starter = overage on clicks [plans.config.ts].
  • ✅ SandboxPaymentProvider — only invoked if the user picks Starter (Phase 5 wires Stripe); Free never touches payment.
  • ✅ Link resolution never blocked by quota [PRD §5.4].

The flow, step by step​

Step 0 — Sign Up (Clerk <SignUp>)​

  • Screen: existing Clerk <SignUp> component [register/page.tsx]. Email + OAuth (Google, per Clerk config).
  • Data collected: email, password / OAuth identity. Clerk handles email verification.
  • Backend call: none from portal — Clerk creates the user; Clerk session established.
  • Rationale: already built; reuse. Google OAuth matches Bitly/Tenjin zero-friction entry.

Step 1 — Name workspace + pick plan (replaces the current name-only page)​

  • Screen: one card with two fields: Org name (prefilled from email domain, editable) + plan choice (two tiles: Free [default, "No card required"] / Starter ["$49/mo, custom domains + overage"]). This is the plan chooser PRD §4.1.2 specified but Phase 2 never built.
  • Data collected: org name, selected plan key.
  • Backend call: clerk.createOrganization(\{ name }) → setActive(\{ organization }). The Clerk organization.created webhook seeds the org_plans row (Free default) [v2-backlog.md Phase 2]. If Starter selected → redirect to Stripe checkout (Phase 5; until then, the existing Phase-2 "Payment coming soon" placeholder) — card collected only here, only for Starter.
  • Decision — when is the plan chosen? Up-front, but Free is the frictionless default. Rationale: aligns with dub.co/Bitly/ChottuLink (plan implicit/default-free), respects the EntitlementsService model (org needs a plan row before any quota check), and isolates the card to the single Starter tile. No paywall trigger later — mid-flow paywalls have the worst conversion and OptoLink's quota model already handles overage without interrupting resolution.
  • Decision — card required? Free = never. Starter = yes, via Stripe checkout (Phase 5). Until Phase 5 ships, Starter selection shows the placeholder and still creates the org on Free so the user isn't blocked.
  • Screen: a compact link builder inside the wizard. One required field (Destination / deep-link path, e.g. product/12345). Everything else pre-filled with sensible defaults: domain = the org's managed subdomain (Free can't use custom domains — custom_domains: false [plans.config.ts]); iOS/Android fallbacks = app-store URL placeholders the user can paste later; link type = deferred (default). Shows a live short-code preview and QR code on the right.
  • Data collected: destination path (+ optional tag).
  • Backend call: POST /portal/links (EntitlementsService.checkQuota(orgId, 'links') before write; recordUsage(orgId, 'links', 1) after) [Phase 4]. Returns \{ shortUrl, qrPng, qrSvg }.
  • Decision — inline vs separate page? Inline in the wizard. Rationale: matches dub.co/Bitly/ChottuLink (instant first link); a separate "Links → New" page adds a navigation hop and an empty dashboard first. Inline is one click to value.

Step 3 — See your first click result (THE CRUX — primary recommendation)​

  • Screen: the wizard now shows the generated short URL + QR + a big "Simulate a click" button. Pressing it runs a portal-facing wrapper around the existing deferred simulator. The result panel animates: click received → device fingerprint captured → deferred match attempted → matched (tier: EXACT/PROBABILISTIC, confidence %, match score) → deep-link payload resolved → destination screen. Shows the resolved deep-link path + simulated device info (platform/OS/browser).
  • Secondary path on the same screen: a "Open on your device" option — copy-link button + the QR code — so the user can do a real click on their own phone if their app is already wired up. (Real clicks flow through the normal pipeline.)
  • Backend call (primary): a new portal endpoint (e.g. POST /portal/onboarding/simulate-click) that internally invokes the existing /dev/deferred/simulate logic with the org's own shortCode [optolink-backend/src/sandbox/sandbox.controller.ts, use-sandbox.ts SimulateDeferredRequest/Response]. The simulated click is tagged demo: true and excluded from recordUsage and billing — it must not consume quota or pollute analytics aggregates.
  • Backend call (secondary): none special — real clicks hit the existing click-tracking pipeline [src/click-tracking/].
  • Decision — how does the user see a click result? Primary = simulated/seeded click via a portal-facing simulator; secondary = QR/copy-link for a real device click. Tradeoff stated below.
  • Rationale (why this is the strongest move): No competitor can do this. MMPs need a real install + SDK to show any deferred resolution (days–weeks). Shorteners can show a click count but cannot show deferred deep-link resolution at all (Bitly doesn't do it; dub.co iOS is "coming soon"). OptoLink uniquely owns a deferred-match engine and a simulator for it. Surfacing the simulator turns OptoLink's hardest-to-demo feature into a 30-second wow moment — and it's the feature the product is built around.
  • Tradeoff to flag: simulated clicks aren't "their" real users — the data is illustrative. Mitigations: (a) clearly label it "Demo click — connect your app to see real data"; (b) it only fires in onboarding (one-shot per link); (c) it's quota/billing-exempt by the demo flag; (d) the real-device QR option is always one tap away for users who want proof.

Step 4 — Land in the dashboard (with the demo click visible + a "next steps" checklist)​

  • Screen: the org dashboard. The org-level summary [PRD §4.5.2] shows: clicks-this-month counter (includes the demo click, badged "demo"), the first link in "Top 5 links," and a "Next steps" checklist (deferred from PRD §4.1.2's wizard into a non-blocking sidebar):
    1. Connect your real app (register iOS/Android app config) [PRD §4.3]
    2. Install the Flutter SDK (copy-paste snippet) [PRD §4.3]
    3. (Starter+) Add a custom domain
    4. Create an API key
  • Backend call: GET /portal/analytics/summary (Phase 6) + GET /portal/entitlements for the quota bar.
  • Rationale: the app-config / SDK / domain steps are valuable but slow (need real app info, DNS, a release cycle). PRD §4.1.2 put them in the wizard — that front-loads blocking work before the user has seen any value. Moving them to a post-value checklist keeps time-to-first-value under 5 minutes while still guiding completion. Each checklist item links to its real settings page; the whole checklist is dismissible.

Decisions, summarized and justified​

DecisionRecommendationJustification
When is the plan chosen?Up-front in Step 1, Free default, Starter opt-inMatches dub.co/Bitly/ChottuLink; org needs a plan row before quota checks; isolates card to Starter
Card required?Free = never; Starter = via Stripe (Phase 5)Every successful self-serve competitor is no-card-on-free; Branch's 30-day card demand is an anti-pattern
First link: inline or separate page?Inline in the wizardLowest hop to value; dub.co/Bitly/ChottuLink all do inline
How to see a click result?Primary: portal-facing deferred simulator (demo-flagged, quota-exempt). Secondary: QR/copy-link for real deviceOptoLink's unique asset; no competitor can show deferred resolution in <5 min; real-device path covers skeptics
App/SDK/domain steps in wizard?No — move to post-value checklistThey block on real-world artifacts (app info, DNS, release); front-loading them kills TTV

6. Open Product Questions for the Team​

  1. Free-tier trial of Starter? Do we offer a time-boxed Starter trial (e.g. 14 days, no card, auto-downgrade to Free) like dub.co's paid-feature trial — or keep Free-as-its-own-tier only? This changes the Step 1 UI and the downgrade logic in EntitlementsService. (Note: PRD §5.3 Free is owner-only/single-seat — a Starter trial would temporarily unlock seats + custom domains.)

  2. Simulated-click provenance & analytics hygiene. Confirm the demo flag design: should demo clicks appear in the dashboard's "clicks this month" counter (badged) or be fully hidden from aggregate analytics and only shown in the onboarding result panel? This affects the Phase 6 analytics query service and billing metering.

  3. Real-device click path: do we surface it in onboarding at all? The QR/copy-link secondary path only "works" if the user's app is already live with our SDK — which a brand-new user's app is not. Is it worth the screen real estate, or should the simulator be the sole first-click mechanism (with QR moving to the link-detail page)?

  4. Plan chooser on Step 1 vs. deferred to first quota wall. The recommendation chooses up-front. Alternative: skip the chooser entirely, default everyone to Free, and only surface Starter at the first quota wall (PRD §5.4) or custom-domain attempt. This is lower-friction but loses the "pick a plan" intent signal. Which do we want?

  5. Should the onboarding wizard be skippable mid-flow? PRD §4.1.2 says the wizard is skippable. With the simulator as Step 3, skipping means the user never sees the wow moment. Do we allow skip before the simulator step, or require the (one-click) simulate step to complete before "Skip to dashboard" is enabled?



Decision (2026-08-11, post-research) — SUPersedes §5 Recommendation​

The §5 recommendation above (Free-default plan chooser, in-wizard first link + simulator wow-moment, app-config/SDK deferred to a post-value checklist) was reviewed against the actual product positioning and revised. The locked flow below is what will be implemented.

Locked onboarding flow​

0. Sign Up (Clerk) — reuse existing <SignUp>
1. Name workspace — org created, plan=null, isOpsOrg=false
2. 🔒 App configuration (gate: while missing) — iOS bundle ID + Android package ID + store URLs + URI scheme
3. 🔒 Select package (gate: while plan===null) — Free / Starter; no card on Free
4. Getting started — distinct route (not the dashboard): primary CTA = *Create your first link*;
secondary = *Connect your app to the SDK* (docs link, honest re: v2 WIP) + *Read the docs*;
explicit *Go to dashboard* escape hatch
5. Dashboard — the real product, reached from Getting started

Key decisions (diverging from §5)​

  • plan = null on org creation, not Free-default. A new org has no plan until the user picks one. While plan === null, every route force-redirects to the Select Package screen. ⚠ Requires changing the resolvePlan discriminator from plan === null → isOpsOrg && plan === null (null currently means OPS_PLAN — everything unlimited — a dangerous overload for customer orgs). Add a NO_PLAN blocking sentinel for non-ops null.
  • App config comes BEFORE plan selection (swap of §5 Step 1/2). Rationale: app config is the substantive org/app setup data; plan is the commercial choice that follows. Gates are independent conditionals, not a linear sequence: !hasAppConfig → step 2, else plan === null → step 3, else dashboard.
  • App config is a HARD gate (required) before the first link can be created. A link without a registered app (bundle IDs + store URLs) is a broken redirect.
  • No in-wizard first-link creation, no in-wizard simulator wow-moment. Dropped from §5. Rationale: OptoLink is a B2B developer tool; a forced fake-click step feels gimmicky to that audience. Get them to the real product fast. Link creation happens naturally from the dashboard.
  • "Getting started" is a distinct route (step 4), not the dashboard. It's the post-gate landing screen: primary CTA = Create your first link; secondary = Connect your app to the SDK (docs link, honest about Flutter SDK v2 WIP) + Read the docs; plus an explicit Go to dashboard escape hatch. The dashboard (step 5) is reached from there. This replaces both the §5 in-wizard simulator step and the earlier SDK-docs interstitial idea.
  • Simulator stays admin-only for now (not surfaced in the portal). Deferred until the Flutter SDK v2 work lands; revisit then.

Backend implementation shape​

  1. clerk-sync.service.ts organization.created handler: plan: 'free' → plan: null.
  2. entitlements.service.ts resolvePlan: org.plan === null ? OPS_PLAN → org.isOpsOrg && org.plan === null ? OPS_PLAN : org.plan === null ? NO_PLAN : getPlan(org.plan). NO_PLAN = all features false, all quotas 0, onExhausted: 'block'.
  3. Backend enforcement: EntitlementsService (or a guard) throws 402 "no plan selected" on quota-gated actions when a non-ops org has plan === null. Never trust the frontend gate alone.
  4. App-config gate: link creation must reject (409/422) when no AppConfig row exists for the org.
  5. Frontend route gate: org.plan === null && !isOpsOrg → redirect /onboarding (select-package step).

Appendix — Source Index​

OptoLink internal (read & verified):

  • AGENTS.md — tech stack, locked decisions
  • docs/OptoLink_PRD_v2.md §4.1.2 (onboarding), §4.5 (analytics), §5.3–5.4 (plans/quota)
  • docs/v2-backlog.md Phase 2 (onboarding scope shipped) & Phase 5 (Stripe)
  • docs/research/optolink-pricing.md, docs/research/what-is-free.md
  • optolink-portal/src/app/(auth)/onboarding/page.tsx (current name-only page)
  • optolink-portal/src/app/(auth)/register/page.tsx (Clerk SignUp)
  • optolink-portal/src/lib/constants.ts (API_PATHS.SANDBOX.DEFERRED_SIMULATE)
  • optolink-portal/src/hooks/use-sandbox.ts + src/types/sandbox.ts (SimulateDeferredRequest/Response)
  • optolink-backend/src/sandbox/sandbox.controller.ts, src/entitlements/plans.config.ts

Competitor docs (in repo): docs/competitors/\{branch-io,dub-co,chottulink,linkrunner,bitly,firebase-dynamic-links,appsflyer,adjust,kochava,singular,airbridge,tenjin}.md + comparison-summary.md + glossary.md

Web sources cited:

  • Branch: help.branch.io/onboarding-guide, help.branch.io/v1/docs/self-serve-gating, help.branch.io/account-hub/docs/basic-link-configuration
  • dub.co: dub.co/changelog/new-onboarding, dub.co/pricing, dub.co/help/article/{free-trial,what-is-a-workspace,dub-analytics}
  • Bitly: bitly.com/blog/how-to-get-started-with-bitly
  • AppsFlyer: appsflyer.com/sign-up, appsflyer.com/pricing, businesswire.com (Zero launch), support.appsflyer.com (OneLink creation, SDK integration)
  • Adjust: help.adjust.com/getting-started-with-adjust, adjust.com/pricing
  • Kochava: kochava.com/get-started, kochava.com/pricing
  • Singular: singular.net/pricing, support.singular.net Complete Onboarding Guide
  • Airbridge: airbridge.io/en/pricing, airbridge.io/en/blog/mmp-sdk-setup-takes-longer-than-first-campaign, airbridge.io/en/blog/mmp-time-to-value
  • Tenjin: tenjin.com/pricing
  • ChottuLink: chottulink.com/pricing, chottulink.com onboarding docs

Unverified items (flagged inline): Branch in-dashboard test-click-before-SDK; dub.co 14-day-trial card requirement; ChottuLink in-dashboard test click; any MMP "demo data" mode. None of the MMPs document an in-product click simulator for new users — consistent with the SDK-blocked-value thesis.