Buyer Journey Simulator

Live URL: ppc.io/buyer-journey-simulator Shared results: ppc.io/buyer-journey-simulator/r/[id] (noindex)

What It Does

Free tool that takes any website URL, scrapes it, extracts business context + buyer personas via Claude, then simulates each persona’s complete purchase journey in first person. Outputs gap analysis, competitor switch detection, and a full Google Ads playbook with per-persona media plans.

Architecture

File Map

API Routes (src/pages/api/journey/)

FileMethodPurpose
scrape.tsPOSTTakes URL, scrapes homepage + 4 subpages via Firecrawl, returns markdown
extract.tsPOSTTakes scraped content, Claude extracts business context + personas
simulate.tsPOSTTakes business + personas, Claude streams journey simulation via SSE
save.tsPOSTSaves results to KV, returns short ID for sharing
load.tsGETLoads saved results by ID

React Components (src/components/JourneySimulator/)

FilePurpose
JourneyApp.tsxRoot state machine - orchestrates all screens + API calls
InputScreen.tsxURL input with 3 feature bullets (matches swipe-wall pattern)
LoadingScreen.tsxProgress steps + orbital animation, two phases (scrape/simulate)
ContextScreen.tsxBusiness intel review - positioning, competitors, trust signals, editable fields, extra context box
JourneyScreen.tsxTimeline with color-coded stages, search terms, channel badges, ad hints per stage, sticky persona sidebar
ResultsScreen.tsx3-tab dashboard: Persona Debrief, Google Ads Playbook (campaigns, keywords, ad copy, media plans, budget), Cross-Persona Summary
UsageGateModal.tsx3-run limit modal with waitlist CTA
types.tsAll TypeScript interfaces
useUsageGate.tslocalStorage-based usage tracking (3 free runs)

Astro Pages

FilePurpose
buyer-journey-simulator.astroMain page - CSS vars, atmosphere orbs, noise texture, scroll reveal
buyer-journey-simulator/r/[id].astroShared results page (noindex, nofollow)

User Flow

  1. Input - Enter any URL (+ optional context)
  2. Scrape + Extract - Firecrawl scrapes site, Claude extracts business context (loading: “Analyzing Business”)
  3. Context Review - User sees positioning, competitors, trust signals, content gaps. Can edit classification fields and add extra context
  4. Simulate - Claude builds personas + simulates journeys with streaming SSE (loading: “Simulating Journeys”)
  5. Journey Timeline - Per-persona first-person narratives with color-coded stages:
  6. Results Dashboard - Three tabs:
  7. Export - Download JSON, share link (KV-backed, 30 days), run another simulation

Environment Variables

Both are set in wrangler.jsonc as vars (private repo):

VariablePurpose
ANTHROPIC_API_KEYClaude API (rate-limited key)
FIRECRAWL_API_KEYFirecrawl scraping API

Deployment

cd ppc-io-frontend
npm run deploy   # builds + wrangler deploy

Requires wrangler login first (OAuth). Deploy is manual, not auto-triggered by git push.

Key Decisions / Gotchas

  1. prerender = false - This page MUST be server-rendered (API routes need server-side env vars). Cannot be static.

  2. not_found_handling: "none" in wrangler.jsonc - Changed from "single-page-application" because the SPA fallback was serving index.html (homepage) for SSR routes like this one. This was the deployment blocker that took multiple attempts to diagnose.

  3. client:only="react" - React components hydrate client-side only. An earlier approach using manual createRoot in a <script> tag failed because Astro processes scripts differently.

  4. Cache-Control: no-store - Set in middleware.ts for /buyer-journey-simulator* routes to prevent Cloudflare CDN caching SSR responses.

  5. CSP connect-src - API calls to Firecrawl and Anthropic happen server-side (Worker), so no CSP changes needed for those domains.

  6. Usage gate - localStorage-based, trivially bypassable. Just a soft gate for the free tool launch.

  7. Streaming - The simulate endpoint uses SSE (Server-Sent Events) to stream Claude’s response. The client accumulates text chunks and parses the complete JSON when done. This is NOT progressive rendering - it just prevents timeout on long responses.

Design Tokens

Matches the swipe-wall design system: