Skip to main content
← Back to the ledger

Case study

Calm Sheets

Calm Sheets was running Google Ads with no idea what visitors did after the click. We built them the ability to watch every visit — every click, every scroll, every hesitation. They went from seeing their ad spend to seeing their customers.

Client Calm SheetsStatus Strategy PhaseStarted Feb 28, 2026calmsheets.com
97Sessions
1,833 HrsHours
$165,588Market value
Highlights

Brand naming and domain acquisition

Landing page design with multiple iteration rounds

Customer research strategy with Python automation

SEO research and 90-day rebuild playbook

Cloudflare WorkersStripeGA4Microsoft ClarityCustom event trackingGoogle Ads API
Before

They could see their ad spend but nothing about the people the ads brought in. No way to know which ads actually worked, which pages lost visitors, or which words on the site were pulling their weight. The biggest line item in their business, and they were flying blind.

What we built

We built custom tracking at every step of the visitor's journey — from the ad they saw, to the page they landed on, to the moment they hit checkout. Every click, scroll, and hesitation gets captured. We also turned on screen recordings so the team can literally watch people shop: where they pause, where they leave, what catches their eye. Every visit is now visible.

After

Now they can watch every visitor. For the first time, they can see which ads actually earn customers, which pages lose people, and where shoppers hesitate before buying. They have the evidence they were missing — now the work of testing fixes and proving what works can begin with real data instead of guesses.

Every click, every scrollData captured
Every visitScreen recordings
Ad click → checkoutJourney covered
$5KProject price

Session timeline

The complete record.

Strategy 19Feature 42Bug Fix 23Refactor 2Docs 6DevOps 4Design 1
Fri, May 11
Strategymarketing-strategistexpand

Analyzed Google Ads spend, CPC, funnel scroll depth, CTA behavior, and landing-page performance to identify unprofitable traffic patterns. · Tightened live Google Ads targeting with new campaign-level negatives, confirmed Flight Anxiety pause, set Fear of Flying to $20/day, and kept Night-Before Panicker at $50/day.

Thu, Apr 301
Strategymarketing-strategistexpand

Rebuilt /flight/, /flight/fear-of-flying/, and /flight/anxiety/ around concise $34 paid-traffic messaging, early kit preview, demo tools, one-price checkout, FAQ, and final CTA. · Fixed landing page UX issues including spacing, misleading hero pills, checkout preservation, and funnel section tracking.

Wed, Apr 291
Featuresenior-devexpand

Restored Calm Sheets dashboard live-alert UI with tap-to-enable Web Audio visitor chime · Added active-purchase polling and generated cash-register alert when paid purchases increase

Tue, Apr 282
Bug Fixsenior-devexpand

Fixed dashboard Purchases card showing lifetime totals regardless of 7d/30d/90d range toggle — fetchD1Metrics now accepts a 'since' date and applies WHERE created_at >= ? to the 4 purchase/refund queries (active purchases, revoked, refund requests, refunds confirmed). Both call sites updated (full dashboard render + /dashboard/api/metrics endpoint). · Removed redundant webhook_freshness health check that warned whenever the last D1 purchase was >14 days old. The stripe_d1_sync / orphaned_purchases check is the real signal — it queries Stripe directly and compares to D1 records. Cleared 33 stale webhook_freshness rows from production D1.

Featureux-designerexpand

Audited Google Ads campaign and funnel screenshots; planned a concise paid-traffic rebuild for the highest-spend flight landing pages. · Rebuilt /flight/fear-of-flying/ and /flight/anxiety/ around immediate $34 offer clarity, early kit preview, demos, single checkout card, FAQ, and final CTA.

Wed, Apr 81
Bug Fixexpand

Rate limit /api/track (60/min) and dashboard login (10/15min brute-force protection)\n- Email format + 254-char length validation on magic link and refund flows\n- Input truncation (500 chars) on all tracking string fields\n- CORS scoped to calmsheets.com on /api/track (was wildcard)\n- Replaced SELECT * with named columns in 8 queries across 5 files\n- Added Strict-Transport-Security header\n- All 178 unit tests passing, deployed to production

Mon, Apr 64
Featureexpand

Live audio notifications via Web Audio API: warm triangle-wave two-note chime for new visitors (660-880Hz, distinct from Spark's brighter sine-wave), A-C#-E-A arpeggio for purchases · Alert banner UX: tap-to-enable, pulsing indicator, localStorage persistence, preview sound on activation

Featureexpand

Dashboard UX port from Spark Academy: center-aligned filter buttons, moved page selector to own section with title/description, friendly date format, renamed tabs Overview→Visitors / Funnel→Page Activity, removed redundant text from Funnel Overview and Page Comparison · Added Visitor Actions section with engagement stats: Button Taps, Started Checkout, Opened an FAQ, Tried Breathing Tool, Started Meditation (all hidden if 0)

Featureexpand

Ported all 12 funnel tab UX improvements from Spark Academy: friendly section names, Visited Page/Reached X labels, stacked bar layout, delta inside/count outside, simpler column headers, < 1s display, friendlier descriptions, scroll depth labels, full section depth with PAGE_SECTIONS, All Pages vs Single Page view, tab persistence via URL hash · Added friendly page names to dropdown and comparison table (Night-Before Panicker not /flight/tomorrow/)

Bug Fixexpand

Fixed dashboard tab persistence: auto-refresh now preserves active tab via URL hash instead of resetting to Overview\n- Fixed funnel API 500 error: var hoisting bug where _funnelDays was undefined during hash restore, plus hardened days param parsing\n- Sorted funnel page dropdown dynamically by session count from D1\n- Removed pricing from 18 early CTAs across all 6 landing pages (hero + social proof + after What's Inside) to reduce early bounce — visitors now see content before price\n- Added owner exclusion: ?notrack URL sets permanent cookie, tracker skips, API drops beacons server-side\n- Added Chesterfield MO to GA4 city exclusion for both report and realtime queries\n- Improved funnel API error reporting with stack traces and client-side response body\n- Updated funnel-tracker-blueprint.md v1.0 → v1.1 with all lessons learned

Sun, Apr 51
Featureexpand

Built 3 Google Ads API scripts: keyword report (metrics, search terms, impression share, QS), optimizer (batch pause/negative keywords), scheduler (ad schedules + day-of-week bid mods)\n- Applied live Google Ads changes: 43 negative keywords, paused QS 1 keyword, shifted 4 campaigns to 5pm-midnight, added day-of-week bid modifiers (Thu/Sat +20%, Tue -20%)\n- Built funnel tracking system: client-side JS tracker (Intersection Observer, sendBeacon), /api/track POST endpoint, D1 funnel_sessions schema\n- Built dashboard Funnel tab: funnel chart, section engagement table, drop-off report, page comparison, scroll depth distribution, date range + page filters\n- Edited 5 landing pages: added data-section attributes (10 per page), Microsoft Clarity snippet, tracker script, rebranded Reddit r/fearofflying to Anxious Flyers Community\n- Deep research on US flight traffic by day of week to inform bid strategy\n- Wrote reusable funnel tracker blueprint for other projects\n- Fixed dashboard Funnel tab JS bug (escaped apostrophe in template literal)

Sat, Apr 415
Featureexpand

Researched anchor/strikethrough pricing UX best practices for digital products (conversion impact, visual patterns, ethical considerations)\n- Implemented ~~$49~~ $34 strikethrough pricing with 'Save 31%' badge across all 6 landing pages (/flight/, /tomorrow/, /prepare/, /understand/, /fear-of-flying/, /anxiety/)\n- Added reusable CSS classes (.price-anchor, .price-save-badge) with dark mode support\n- Updated pricing cards, section headers, all CTA buttons, and FAQ copy\n- Verified rendering at 375px, 768px, 1440px in light + dark mode via Playwright\n- Fixed dark mode contrast for anchor price and badge elements\n- JSON-LD schema and Stripe checkout unchanged — display-only change\n- Committed and deployed to production (calmsheets.com)

Bug Fixexpand

API security hardening: rate limiting on 5 public endpoints (checkout, verify-magic-link, confirm-refund, refresh-auth, download-pdf) via shared rate-limit.js helper\n- Fixed SQL injection risk in x-scheduled.js ORDER BY clause (status allowlist)\n- Added input validation allowlists to x-replies.js and x-scheduled.js\n- Hardened ADMIN_TOKEN auth on 3 admin endpoints (fail closed with 503 if not configured)\n- Created global API security rule (~/.claude/rules/common/api-security.md)\n- 41 new unit tests across 4 new + 5 existing test files (178 total, all passing)\n- Full production deployment: Cloudflare Pages + health worker + X reply bot

Bug Fixexpand

Diagnosed failing synthetic test: upgrade-rejects-missing-token probe was removed from local code during single-tier consolidation (commit 307c9f6) but health worker was never redeployed\n- Redeployed health worker to remove stale probe\n- Full production health audit: all 5 ad landing pages, checkout validation, auth gating, homepage, health worker — all healthy and stable for ad spend

Featureexpand

Consolidated two-tier pricing (Standard $29 / Pro $34) to single-tier product at $34 — 48 files changed, 2,279 lines removed · Updated all 6 landing pages: single pricing card, 16-item feature list with guides/interactive tools separator

Featureexpand

Full rewrite of /flight/ landing page for organic/direct/X-bot traffic conversion\n- Strategic debate on page positioning: analyzed traffic sources (X bot 6x/day, organic, returning visitors, direct), mapped all 3 personas, adapted PAS framework (lighter agitation, heavier solution)\n- New H1: 'Flight anxiety doesn't have to win' — broad catch-all vs scenario-specific\n- Added 8 new sections: problem validation, persona self-sort (in-page anchors), light agitation with success stories, solution positioning, methodology proof (4 credibility cards), objection handling (4 objections), price anchoring (therapy/courses comparison), FAQ with FAQPage structured data (8 questions)\n- 6 CTAs throughout page, all pointing to #pricing with 14-day refund signals\n- Preserved all functional code: checkout forms, breathing demo JS, meditation player JS, gclid capture, analytics, dark mode, form-guard\n- Kept free articles section as upsell funnel per Stephen's direction\n- Centered all quote cards for visual alignment\n- Committed and pushed to production

Refactorexpand

Audited all 6 free SEO articles against paid product — found severe overlap giving away the store (breathing techniques in 4/6 articles, complete packing lists, crew scripts, sound guides, timelines) · Rewrote all 6 articles as What/Why teasers: removed all How content (techniques, scripts, lists, action plans), kept education and validation, added soft CTAs bridging to paid guide

Bug Fixexpand

Added 'Reddit' prefix to all bare subreddit references (r/fearofflying, r/flyinganxiety) across 6 hand-authored landing pages and 3 content markdown source files\n- Rebuilt guide HTML from updated markdown via build-content.js\n- Verified no duplicate 'Reddit Reddit' or doubled subreddit names\n- Deployed to production (calmsheets.com)

Featureexpand

Full PAS conversion rewrite of /flight/understand/ landing page (Logic Seeker persona)\n- Read & analyzed 11 strategy/context files (copywriting guide, Reddit research, Google Ads campaigns, keywords, ad copy, personas, brand docs)\n- Keyword & audience analysis: 26 keywords across 3 ad groups (Turbulence, Airplane Sounds, Claustrophobia & Control)\n- New sections: Agitate, Solution, Try It Now, Objection Handling, FAQ with FAQPage schema, price anchoring\n- Removed exit ramps: Free Articles (6 cards) and Related Articles (3 cards) sections\n- Extracted interactive demos into dedicated Try It Now section with conversion framing\n- Added Product and FAQPage structured data for SEO\n- 5 CTAs placed at emotional peaks (up from 2)\n- Fixed Reddit attribution (r/ → Reddit r/), centered quote cards, removed redundant login link\n- Deployed to production via Cloudflare Pages

Featureexpand

Full /flight/prepare/ landing page rewrite for conversion optimization (Avoidant Traveler campaign)\n- PAS framework: added Problem, Agitate, Solution, Methodology Proof, Objection Handling, FAQ sections\n- Keyword & audience analysis across 28 keywords in 3 ad groups (Preparation, Returning Flyer, Scared but Must Travel)\n- Read 11 strategy/context files to inform copy decisions\n- Added FAQPage + Product structured data, 6 CTAs, price anchoring (-300 therapy vs )\n- Removed 2 article exit ramp sections, updated nav links\n- Copy fix: added Reddit prefix to all subreddit references\n- Style fix: center-aligned quote card content\n- Deployed to production on main branch

Featureexpand

Full conversion rewrite of /flight/tomorrow/ landing page for Night-Before Panicker persona\n- Read & synthesized 11 strategy/context docs (copywriting guide, Reddit research, Google Ads, keywords, ad copy, personas, brand, site arch, reference rewrite)\n- Keyword & audience analysis: 33 keywords across 3 ad groups, persona mapping, emotional state assessment\n- PAS framework: Hero, Problem, Solution, Agitate, What's Inside, Try It Now, Methodology Proof, Objection Handling, Pricing, FAQ, Final CTA\n- Added 6 CTAs (was ~2), price anchoring (-300 therapy vs ), 3 inline objection handlers\n- Added mobile hamburger menu, FAQ section with FAQPage schema, Product structured data, Twitter meta tags\n- Removed exit ramps (Related Articles section, standalone permission section)\n- Preserved all functional JS (breathing demo, meditation player, checkout forms, gclid, time-aware label, dark mode)\n- Post-write tweaks: centered quotes, Reddit prefix on attributions, removed duplicate login link\n- Committed and deployed to production via Cloudflare Pages

Featureexpand

Full conversion rewrite of /flight/anxiety/ landing page using PAS framework\n- Read 11 context files (strategy, copywriting guide, Reddit research, Google Ads config, personas, reference rewrite)\n- Keyword/audience analysis for Flight Anxiety campaign (22 keywords, 4 ad groups)\n- Added: agitation section, objection handling, price anchoring, FAQ with FAQPage schema, 5 CTAs\n- Removed: exit ramps (articles section, community voices, stat ticker, nav links to non-conversion sections)\n- Preserved all functional code (checkout forms, breathing demo JS, meditation JS, analytics, dark mode)\n- Deployed to production on calmsheets.com

Featureexpand

UI polish on /fear-of-flying/ rewrite: fixed interactive tools grid alignment (lg→xl breakpoint), removed duplicate login link from pricing section, stacked price anchoring lines vertically, fixed spacing · Verified price anchoring accuracy: researched real fear-of-flying course prices, updated from $500+ to $295+ (SOAR program reference)

Featureexpand

Audited codebase for auth cookie (30d), magic link uses (5x), and magic link expiration (24h) settings across all code paths · Audited all user-facing copy explaining auth system (emails, success page, FAQ, login, privacy, terms)

Strategyexpand

Conducted full conversion research: analyzed Reddit deep analysis (100+ posts), audited all 6 free articles + article hub, reviewed /fear-of-flying/ landing page, and researched online copywriting best practices (PAS framework, CXL, CopyHackers, Unbounce, MECLABS) · Analyzed Google Ads keyword data for Fear of Flying campaign (3 ad groups, 27 keywords) to map searcher intent to landing page copy

Strategyexpand

Full Google Ads account audit: analyzed 138 keywords + 195 search terms, identified waste, cannibalization, wrong-intent keywords · Built and deployed /flight/anxiety/ landing page targeting anxiety keyword cluster (validation-first hook, Reddit quotes, full pricing/checkout)

Fri, Apr 31
Featureexpand

Full-screen mobile nav overlay (Spark Academy style) with hamburger-to-X animation, body scroll lock, ESC/click-outside dismiss, dark mode support across all 4 landing pages\n- Standardized nav links: Free Articles + Already Purchased on all landing pages (desktop + mobile)\n- Added 6-card Free Articles sections to /prepare/ and /understand/ landing pages\n- Fixed dark mode article cards blending into background (lighter bg + subtle border in dark-mode.css)\n- Audited and pushed uncommitted changes: bot relocation to bots/, health worker hardening, Google Ads campaign expansion\n- Redeployed health worker to production (external cron trigger, fewer false alarms, Google Ads API v20)

Thu, Apr 27
Docsexpand

Analyzed Google Ads keyword 'flight anxiety' across campaigns; recommended /fear-of-flying/ as best landing page for broad head terms · Updated project CLAUDE.md with /fear-of-flying/ in site architecture and What's Built sections

Featureexpand

Analyzed Google Ads keyword data (Avoidant Traveler campaign), identified budget drains and recommended pausing broad informational ad groups · Built /flight/fear-of-flying/ landing page: keyword-optimized for 'fear of flying' head terms, Reddit-sourced community quotes, persona routing section, Pro tool demos (breathing timer + meditation player), strategic article links, full pricing section

Bug Fixexpand

Fixed synthetic test false failures: removed 5 page-load probes that hit Cloudflare's ~10s Worker-to-Pages subrequest timeout limit · Kept all 12 API probes that test actual server-side logic (auth, checkout, webhooks, refunds, etc.)

DevOpsexpand

Diagnosed health worker cron failure (Cloudflare cron silently stopped after D1 timeout errors) · Migrated health worker scheduling from Cloudflare cron trigger to cron-job.org (external cron, every 5 min)

Featureexpand

Auto-hide System Health & Synthetic Tests dashboard cards when all healthy\n- Fix xFollowers undefined crash (null vs undefined check)\n- X follower count tracking: bot records hourly snapshots to D1, dashboard displays count + change\n- Fix OAuth 1.0a signing to include query params in signature base string\n- Deep research: 40+ X accounts to follow across 8 categories (saved to strategy/x-accounts-to-follow.md)\n- Hashtag monitoring bot: searches 10 flight anxiety hashtags, Gemini filters for real people, auto-replies with helpful tips (max 3/hour)\n- D1 migration for x_hashtag_tweets table\n- Social media expansion analysis: evaluated 10 platforms, ranked by fit/effort/ROI (Pinterest #1, TikTok #2)\n- Updated CLAUDE.md with hashtag monitoring docs + social media expansion plan

Strategyexpand

Analyzed 14 Ahrefs keyword research screenshots and extracted 61 new keywords for Google Ads campaigns\n- Organized new keywords into existing ad groups (B, C, F, H) and 4 new ad groups (J-M)\n- Wrote full RSA ad copy (12 headlines + 4 descriptions each) for Ad Groups J (Fear of Flying Head Terms), K (Flight Anxiety General), L (Coping & Calming Tips), M (First Time & Travel Anxiety)\n- Updated google-ads-keyword-list.md: 56→104 keywords, 9→13 ad groups, with comma-delimited export\n- Updated google-ads-copy.md with all 4 new ad group copy blocks\n- Advised on landing page URL change for Ad Group C (/flight/tomorrow → /flight/)

Bug Fixexpand

Created Google Ads keyword list document (56 keywords across 9 ad groups, comma-delimited) · Diagnosed and fixed Google Ads API v19→v20 sunset issue in dashboard and health worker (silently broken for weeks)