product

Odessa → Audiobook — distribution plan (organic → paid)

Goal: take the "turn your imported journal into an inspiring fiction audiobook" creative from a static card to a measured, scalable paid channel — without spending a dollar before the funnel is measurable.

Audience (locked): consumer journalers (Day One / Journey migrants, r/Journaling), not EmberKiln authors. The funnel is:

ad impression
  → /odessa landing            [odessa_landing_view]
  → CTA click                  [odessa_landing_cta_clicked]
  → signup                     [signup_completed]
  → import / first entry       [journal_import_completed | first_entry]
  → Odessa seed                [odessa_seed_generated]
  → story started              [odessa_story_started]
  → ported to Graphene w/audio [odessa_story_ported_to_graphene {kick_off_audio:true}]  ← north-star

The north-star conversion is a ported season with audio kicked off — the moment an audiobook of the journaler's life actually exists. First-touch UTM is attached to the PostHog person by PostHogProvider (captureFirstTouchAttribution), so every rung is segmentable by campaign.

The honest constraint: this is a long funnel with a paid render at the end. Cold paid traffic into it is expensive until (a) every rung is measured and (b) the biggest drop-off (almost certainly time-to-first-audiobook) is reduced. Hence measurement-first.


Decisions locked (2026-06-12)

DecisionChoice
Primary audienceConsumer journalers
First buildPhase 0 measurement instrumentation
First paid budgetDecide after Phase 2 — set from real funnel data + CAC ceiling

Phase 0 — Readiness gates (before $1 of spend)

Instrumentation substrate already exists for the Studio/author funnel and is reused here — pixels (FacebookPixel/TikTokPixel/RedditPixel/PinterestPixel, gated on NEXT_PUBLIC_*_PIXEL_ID, mounted globally in app/layout.tsx), first-touch UTM capture (src/lib/analytics.ts), and the ad-efficiency admin dashboard.

  • Top-of-funnel events on /odessaodessa_landing_view (with paid + traffic-source) and odessa_landing_cta_clicked (per-CTA). Shipped in src/app/odessa/page.tsx + event union in src/lib/analytics.ts. This was the only fully-missing rung; everything downstream already fired PostHog events.
  • Share-card metadatasrc/app/odessa/layout.tsx (OG + Twitter summary_large_image) so shared /odessa links render the promo card.
  • Paid-mode flag ON for the render path (gate from the Graphene Studio rollout plan).
  • TOS / ad-policy pass — product reads personal journals; keep ad copy to "inspiring fiction audiobook," avoid therapeutic/mental-health claims (Meta/TikTok policy + app-store scrutiny).
  • Landing sample audiobook — a real "press play" proof on /odessa so a cold visitor hits the aha without journaling for two weeks first. (Point at an existing published season's audio.)

Pre-Phase-3 (needed before paid optimization, NOT before Phase 2)

  • Fire pixel conversions on mid-funnel rungsodessa_seed_generated and the north-star to Meta/TikTok via trackFBConversion/trackTikTokEvent so the ad algorithms can optimize toward them. Currently PostHog-only.
  • Server-side CAPI relay — none exists today (all pixel firing is client-side). Add a Meta Conversions API relay in apps/backend for the north-star; server-side beats browser-only under iOS/ad-block.

Phase 1 — Organic / owned (free; validates the hook)

Ready-to-post kit: ODESSA_ORGANIC_KIT.md — UTM convention, per-channel captions, demo-video shot list, owned-surface copy.

  • Push the card through owned surfaces: in-product, the /dashboard/import success screen (already has a "See your story with Odessa →" CTA — add the audiobook hook), and an email to existing journalers.
  • Post the 9:16 story cut as Reels/TikTok with a real screen-recorded demo (journal → story → press play); 1:1 in feed.
  • A/B the 3 ranked headlines organically (variants in apps/frontend/public/promo/build-promo.mjs): the winner becomes the paid creative. Free message-testing before spend.

Phase 2 — Measurement bake (~1–2 weeks of organic traffic)

  • Build a PostHog funnel insight over the event sequence above; read each rung's conversion %. Slice by first_touch_utm_source / campaign.
  • Find the biggest drop-off and fix it before paying to fill a leaky funnel.
  • Compute LTV (render pricing + any subscription + Amazon-affiliate tail) → set a target CAC ceiling = LTV ÷ payback. Rule: don't spend until you can finish "a converted listener is worth $X."
  • Then set the first paid budget.

Phase 3 — Paid test (small, structured)

  • One channel first — recommend Meta (IG/FB); TikTok second, Reddit third (cheap, precise: r/Journaling, Day One).
  • Test top-2 headlines × 2 formats, optimize to the north-star event (needs the pixel/CAPI items above), kill/scale criteria defined up front (CPA < CAC ceiling).

Phase 4 — Scale + iterate

  • Scale winners; retarget landing-bouncers with the sample audiobook; lookalikes off converters; refresh creative against fatigue (the generator makes new cuts nearly free — a real moat for paid).

Where things live

  • Creative + generator: apps/frontend/public/promo/ (build-promo.mjs, render-promo.sh)
  • Landing + funnel events: apps/frontend/src/app/odessa/page.tsx
  • Share-card metadata: apps/frontend/src/app/odessa/layout.tsx
  • Analytics utils + event union: apps/frontend/src/lib/analytics.ts
  • Paid-traffic dashboard: apps/frontend/src/app/dashboard/admin/ad-efficiency/page.tsx
  • Pixel env vars: NEXT_PUBLIC_FB_PIXEL_ID, NEXT_PUBLIC_TIKTOK_PIXEL_ID, NEXT_PUBLIC_REDDIT_PIXEL_ID, NEXT_PUBLIC_PINTEREST_TAG_ID
ODESSA AUDIOBOOK GTM — Docs | HiveJournal