The Real Problem: You Built It and Nobody Came
You pushed to production on a Tuesday night, stayed up to wire in Stripe, wrote a half-decent README, and posted it to your personal Twitter account with 200 followers. The next morning you checked your analytics: one user. You. The session lasted 47 minutes because you were debugging the onboarding flow at 2am. That’s a story I’ve lived, and based on how many “show HN” posts I’ve watched sink with zero comments, it’s disturbingly common.
The gap between launched and has users is where micro SaaS products go to die quietly. Not with a dramatic crash β just a slow flatline in PostHog while you add features nobody asked for. Most founders treat distribution as something you do after the product is ready. It’s not. The people who hit 100 users fast treated distribution as a parallel workstream starting before the first commit. By the time they pushed v1 to prod, they already had a warm list of 40 people waiting to try it.
What I’m not going to do here is give you a generic “post on Product Hunt and do content marketing” checklist. I’ve read those posts. They’re useless. What actually works for a micro SaaS with zero budget and zero audience is a specific sequence β who you talk to first, what you say, which communities you don’t spam, and how you convert a Reddit comment into a paying user without being that person. The tools matter too: I’ll give you the actual Typeform links, the Apollo.io free tier limits, the exact cold DM structure that gets responses instead of ignores.
5 UI/UX Research Tools I Actually Use as a SaaS PM (And One I Dropped After 3 Months)
One important framing before we get into it: the first 100 users are not your permanent customer profile. They’re signal. You’re looking for which use case resonates, which pricing tier people actually pay for, and which distribution channel has any pull at all. Treat every one of those 100 conversations as a product research session. I kept a Notion table with columns for source, pain point mentioned, plan chosen, and churned/stayed. By user 80 I could see clearly which channel was bringing people who stuck around and which was bringing people who signed up for the free tier and never came back.
Once those users start arriving, you’ll need infrastructure that doesn’t fall apart under even modest load β things like email delivery, billing edge cases, and support workflows. I’ve found the rundown over at Essential SaaS Tools for Small Business in 2026 genuinely useful for that second phase. But first you need actual humans using the thing, which is what this entire guide is about.
Before You Do Anything: Set Up Baseline Tracking
Most first-time micro SaaS builders skip tracking entirely until they have “real users.” That’s exactly backwards. The moment you’re flying blind during your first 10 signups is the moment you lose the most valuable signal you’ll ever get. Early users behave differently β they’re explorers, not optimizers β and if you’re not watching every click, you’ll spend the next three months guessing why no one converted.
I use PostHog for this. The self-hosted option exists, but honestly the cloud free tier is fine until you’re doing serious volume β it’s generous enough for the first few thousand events. The install is one copy-paste away:
I Used Canny, Productboard, and a Self-Hosted Alternative to Decide What to Build β Hereβs What Actually Worked
# If you're on a JS/TS frontend
npm install posthog-js
# Then in your app entry point (e.g. main.ts or _app.tsx):
import posthog from 'posthog-js'
posthog.init('your_project_api_key', {
api_host: 'https://app.posthog.com',
autocapture: true, // catches clicks, inputs, form submits automatically
capture_pageview: true
})
Autocapture is useful but don’t rely on it alone. You want three explicit events wired up before launch: signup_completed, first_meaningful_action (whatever that means for your product β first project created, first report generated, first import done), and upgrade_clicked. Autocapture will miss context you care about, like which pricing tier the user was on when they clicked the button. Fire these manually with posthog.capture('signup_completed', { plan: 'free', source: 'landing_page' }) and you’ll thank yourself in week two.
The Stripe webhook is the other piece people skip. Stripe’s own dashboard is fine for accounting, but you want your own record of who converted, when, and from what state in your funnel. Wire up checkout.session.completed to a simple endpoint and log it to your DB alongside the user’s ID:
# Simple Express endpoint β adapt to whatever you're running
app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), async (req, res) => {
const sig = req.headers['stripe-signature']
let event
try {
event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET)
} catch (err) {
return res.status(400).send(`Webhook Error: ${err.message}`)
}
if (event.type === 'checkout.session.completed') {
const session = event.data.object
// Log to your DB β this is your source of truth, not Stripe's dashboard
await db.conversions.insert({
stripe_customer_id: session.customer,
user_id: session.client_reference_id, // pass this when creating the checkout session
amount: session.amount_total,
converted_at: new Date(),
})
}
res.json({ received: true })
})
The reason you do this before user #1 shows up: UTM parameters and referrer data exist in the browser at signup time and nowhere else. If you’re not capturing utm_source, utm_medium, and utm_campaign on every signup event, you’ll never know whether your first paying customer came from a Reddit comment, a cold email, or an indie hackers post. PostHog captures this automatically if you pass it through, but you should also persist it to your user record in your DB at signup. By the time you get to 50 users you’ll be doing channel-by-channel conversion analysis, and that only works if the data was there from day one.
Step 1: Mine Your Own Network First (Users 1β15)
The biggest mistake I see first-time micro SaaS builders make is treating their Twitter following as their user base. Your followers know you, not the problem you solved. The people you want are in Slack communities for solo agency owners, Discord servers for indie freelancers, LinkedIn threads where your exact user archetype complains about their exact problem. I’ve gotten more qualified beta users from a single niche Slack workspace than from posting to 5,000 Twitter followers.
5 AI Chatbots My Team Actually Uses for SaaS Customer Support (And One We Dropped)
Before you send a single message, do this search on Twitter/X to find people who have publicly vented about your problem in the last 90 days:
# Replace with your actual problem keyword
[problem keyword] until:2024-12-01 since:2024-09-01 min_replies:2
# Real example if you built a client reporting tool:
"client reports" until:2024-12-01 since:2024-09-01 min_replies:2 -filter:links
# Same logic works on Reddit β use pushshift or reddit search:
site:reddit.com "[problem keyword]" after:2024-09-01
The min_replies:2 filter matters. Anyone who got replies to a complaint tweet is someone other people agreed with β that’s social proof that the pain is real. Save those profiles. Check if they’re active. If they’ve complained publicly, a DM that references their specific situation will feel like you read their mind, not like spam.
Your DM template should lead with their pain, not your product. The difference between a 25% response rate and a 5% one is almost entirely this:
BAD:
"Hey, I built a SaaS tool for agency owners. Would love your feedback!"
GOOD:
"Hey [Name] β saw your tweet about spending Sundays
manually pulling client metrics into spreadsheets.
I built something that automates exactly that for solo agencies.
Would you try it free for 30 days? Happy to set it up with you."
The second message names their role, names their specific complaint, offers a concrete thing, and removes the financial risk. Specificity is the entire trick. Generic messages get ignored because people assume they went to 500 people. Specific messages feel like you spotted them in a crowd.
Offer a 30-minute onboarding call even though it doesn’t scale. I know, I know β but here’s why it’s non-negotiable at this stage: you don’t have enough churn data to see patterns yet. The call is how you find out that users sign up, get confused at step 3, and quietly leave. You won’t catch that in Mixpanel with 12 users. On the call, share your screen, let them drive, stay quiet when they hesitate. Every hesitation is a product bug. I found out my biggest onboarding drop-off came from a single field label that made no sense to anyone but me β I only learned that from call number 4.
- Slack and Discord communities: Search for communities in your niche on Slofile.com or just Google “[niche] slack community“. Most have a #tools or #show-and-tell channel where organic posts are welcome.
- LinkedIn: Search your exact user job title, filter by 2nd-degree connections, look at their recent activity for complaint signals before you message.
- Reddit: Comment first, DM second. A genuinely helpful comment in r/freelance or r/agency builds enough goodwill that the follow-up DM doesn’t feel cold.
Fifteen users from your own network with a 30-minute call each sounds like 7.5 hours of work. It is. But those 15 people will tell you whether your retention is a product problem or an onboarding problem before you spend a dollar on ads.
Step 2: Post in the Right Reddit Communities (Users 15β40)
The biggest mistake I see micro SaaS founders make on Reddit is treating it like a billboard. You paste a link, write two sentences, and wonder why you got three upvotes and a mod removal. The posts that actually convert spend 80% of their words on the problem and 20% on the product. Reddit users are allergic to being sold to, but they will click through on a genuine story.
The subreddit selection matters more than most people think. r/SideProject is the most forgiving β self-promotion is explicitly in the rules, so you won’t get banned for having a link. r/Entrepreneur has a larger audience but is much stricter; lead with the journey, not the product. r/indiehackers on Reddit is smaller than the actual Indie Hackers forum but converts well because readers are pre-filtered β they understand bootstrapped tools and will actually pay for something useful. The one most founders skip is the niche subreddit for the exact problem you’re solving. If your tool manages freelancer invoices, r/freelance or r/smallbusiness will outperform all the startup subs combined. The audience there has the pain, not just intellectual curiosity about the solution.
The post format that works is a Show HN-style write-up adapted for Reddit. Structure it like this:
Title: I spent 6 months manually tracking client payments in spreadsheets β so I built a tool that does it automatically
Body:
Every month I'd lose 2-3 hours hunting down which invoices
were paid, which were overdue, and which clients I hadn't
followed up with. I tried [FreshBooks] β too expensive for
my volume. I tried [a spreadsheet template] β broke every
time I had more than 15 active clients.
So I built [YourTool]. It does X, Y, Z.
Here's what I learned building it: [one genuine technical
or business insight β this is what gets upvotes]
If you've had the same problem, I'd love feedback: [link]
Read each subreddit’s rules before posting β I mean actually read them, not skim. r/Entrepreneur bans anything that looks like a direct product pitch. Some niche subs require you to be an active community member before posting a project link. Reddit bans are hard to recover from because they’re often account-level, and you lose all karma history. A shadow ban is even worse β your posts appear live to you but are invisible to everyone else. Check your account status at reddit.com/r/ShadowBan if something feels off.
Timing is one of those levers that’s almost free to pull. Tuesday through Thursday, posted between 9am and 12pm EST, consistently outperforms weekend posts or late evening drops. The reason is mechanical: Reddit’s ranking algorithm weighs early velocity heavily, so you need East Coast users awake and active to give the post its first wave of engagement before it gets buried. Schedule your post for when you can physically sit at your computer for two hours straight β because the comment velocity window is real. Every comment you respond to in the first two hours signals to the algorithm that the post is generating conversation. I’ve watched posts with 8 early comments outrank posts with 30 later comments purely because of that early engagement burst.
One more thing I learned the hard way: cross-posting the exact same text to multiple subs on the same day will get you flagged as spam. Write a genuinely different post for each community. The r/SideProject version can be product-forward. The niche subreddit version should barely mention the product until paragraph three. Different audiences, different pain points, different framing. This phase should get you somewhere in the 15β40 user range β not because Reddit users convert at high rates, but because the right post in the right sub puts your link in front of people who already have the problem you’re solving.
Step 3: Hacker News ‘Show HN’ β High Risk, High Reward (Users 40β70)
The thing nobody tells you about Show HN is that it’s not a marketing channel β it’s more like a live code review where the audience is hostile and the stakes are real users. I’ve seen products that weren’t ready get shredded in comments and never recover reputation-wise. I’ve also seen scrappy solo projects hit the front page and sign up 200 users in a day. The difference usually comes down to preparation in the 48 hours before you hit submit, not the product itself.
The 30-Minute Window Is Real
HN’s ranking algorithm weights velocity heavily. If your post doesn’t get 3β5 upvotes in the first 30 minutes, it slides off the Show HN page and you’re done. This means you need a small, genuine network ready to look at the post β not to spam-vote (HN detects coordinated voting and will penalize or kill the post), but to actually engage with it if they find it interesting. Three developer friends who genuinely look at your product and upvote if they think it’s worth sharing is all you need to survive the initial window. Anything more manufactured than that will backfire.
Write the Title Like It’s a One-Line Pitch
The format that consistently works is Show HN: [What it does in plain English] β [one-line differentiator]. Spend an hour on the Show HN page reading titles before writing yours. Notice that the ones that perform well are embarrassingly literal β no clever wordplay, no jargon. “Show HN: A self-hosted Notion alternative that works offline” beats “Show HN: KnowledgeOS β reimagine your second brain.” The HN crowd doesn’t respond to marketing language. They respond to “oh, that’s actually a solved problem in an interesting way.” Your comment in the thread matters as much as the title β write 3β4 sentences covering what it does, what problem triggered you to build it, and what you’re looking for from the community.
Turn on Error Monitoring Before You Post, Not After
Get Sentry running before your Show HN moment. The free tier handles 5,000 errors/month which is plenty. The setup for a Node app takes under 10 minutes:
npm install @sentry/node
# In your app entry point
const Sentry = require("@sentry/node");
Sentry.init({
dsn: "https://[email protected]/project-id",
// Capture 100% of transactions during launch β tune this down later
tracesSampleRate: 1.0,
});
HN users will hit every edge case your QA didn’t. They’ll paste Unicode into your text fields, use Firefox with uBlock, hit your API from the command line, and try your product on a 10-year-old iPad. Without error monitoring live, you’ll watch signups plateau and have no idea why. With Sentry open on a second monitor, you’ll see the exact line throwing a 500 and can push a fix within minutes while the traffic is still coming.
Pre-Draft Your Answers to the Inevitable Questions
Three questions show up in almost every Show HN thread for a SaaS product:
- “Why not just use [Airtable/Notion/Zapier]?” β Have a concrete answer that’s honest about the gap, not defensive. “It’s 80% cheaper for teams under 10 and the API doesn’t rate-limit you at the free tier” is a real answer. “We focus on simplicity” is not.
- “What’s the tech stack?” β HN readers are genuinely curious. Being specific (“Next.js 14, Postgres 16, hosted on Fly.io”) builds credibility. Vague answers make people assume you’re hiding something embarrassing.
- “What’s the pricing model?” β If you don’t have clear pricing, say so directly and explain what you’re thinking. Uncertainty is fine; evasion is not.
Write these out in a doc before posting. When the thread goes live, you’ll be too anxious to think clearly. Having pre-drafted answers means you respond fast and confidently, which signals that a real person who knows their product is behind it.
Watch PostHog Realtime While the Thread Is Active
If you have PostHog set up (free tier up to 1M events/month, self-hostable if you want to own the data), open the Realtime view the moment your post goes live. You’ll see users hitting your site within minutes of a successful post. More importantly, you’ll see where they’re dropping β if 80 people hit your landing page and only 4 sign up, that’s signal. If 30 people start the onboarding flow and 28 bail on step 2, that’s a specific problem you can fix before the thread dies. The realtime data tells you whether you have a traffic problem or a conversion problem, and that distinction determines every decision for the next 6 hours.
Step 4: Product Hunt Launch (Users 70β100)
Product Hunt will probably not change your business. I want to be upfront about that before you spend two weeks prepping for it. What it will do is give you a credible backlink, a “Featured on Product Hunt” badge you can put on your landing page, and a burst of traffic that’s useful for social proof screenshots. The sustained signups people brag about on Twitter are mostly outliers β most micro SaaS products get a spike on launch day, then maybe 2β5 organic signups a week from PH discovery after that. Treat the whole thing as a one-day sprint with specific deliverables, not a growth strategy.
The single biggest mistake I see is people waking up on launch day and submitting cold. Product Hunt’s algorithm heavily weights early upvotes β specifically in the first few hours. If you don’t have a Ship page with followers before launch, you’re starting with zero social proof when the listing goes live at 12:01 AM PT. Create the Ship page at least two weeks out. The setup is straightforward β it’s basically a pre-launch landing page inside PH that lets people subscribe for updates. Post one or two updates to that Ship page before launch day. Even 30β40 subscribers makes a meaningful difference on launch morning.
Tuesday and Wednesday are the sweet spots for launch day. Monday is competitive because it gets the most traffic but also the most launches β everyone who thought about it over the weekend posts Monday. Weekends are genuinely dead. I launched a tool on a Thursday once thinking it would be less competitive and watched it stall out because the browsing behavior just isn’t there. If you can’t do Tue/Wed, Thursday is acceptable. The listing goes live at 12:01 AM Pacific Time β that’s when the clock starts and when early upvotes matter most.
Your first comment on the listing needs to go live the moment it appears. Not an hour later. Set a timer for 12:01 AM PT and post it yourself. Skip the marketing copy entirely β nobody reads “We’re excited to launch X which solves Y for Z users.” Write the actual story: what broke in your life or work that made you build this, how long it took, what you got wrong in the first version. Something like:
Hey PH π I built this after spending 3 months manually copying data
between two tools that had no integration. I'm a solo dev and this
is my first product. Happy to answer anything β would especially love
feedback on the onboarding flow, which I rewrote twice.
Authenticity converts on Product Hunt. The audience skews toward builders and early adopters who can smell a press release from miles away. A real comment also signals to hunters browsing at that hour that there’s an actual human behind the product.
Your 70 existing users are your launch team whether they know it or not. Send a direct email β not a newsletter blast, not a tweet β with the exact URL of your Product Hunt listing. Make it one click to upvote. The email should be short and personal:
Subject: Quick favor β I'm on Product Hunt today
Hey [first name],
I launched [Product] on Product Hunt today and would really appreciate
an upvote if you've found it useful. Takes 10 seconds:
π https://www.producthunt.com/posts/[your-product]
Thanks for being an early user β means a lot.
[Your name]
The conversion rate on a personalized direct message versus a generic tweet asking for upvotes is not even close. People who already use your product have real motivation to help β they just need the exact URL and a frictionless ask. If you have users who’ve given you positive feedback in the past, DM them individually on whatever channel you’ve been talking. Those personal asks convert at a much higher rate than broadcast messages, and Product Hunt’s algorithm rewards genuine engagement from real accounts.
The Tools You Actually Need for This (Nothing More)
The thing that wastes the most time at the zero-to-100 stage isn’t building β it’s procrastinating on distribution because your tool stack feels incomplete. I’ve watched people spend two weeks evaluating Mixpanel vs Amplitude before they had a single paying user. Pick boring, proven tools and move on. Here’s the exact stack I’d use today.
Analytics: PostHog
Self-hosted or cloud, PostHog gives you funnels, session recording, and feature flags without writing custom event pipelines. The cloud free tier covers 1 million events per month β that’s more than enough until you have a few hundred active users. The thing that caught me off guard the first time was how fast funnel analysis is out of the box. You don’t have to configure anything custom to see where users are dropping off between signup and activation. Just drop in the snippet and start querying the next day.
# Install the JS snippet or npm package
npm install posthog-js
# Then in your app init (Next.js example):
import posthog from 'posthog-js'
posthog.init('YOUR_PROJECT_API_KEY', {
api_host: 'https://app.posthog.com',
// Set to true to capture pageviews automatically
capture_pageview: true
})
Payments: Stripe
Don’t overthink your pricing page until you’ve talked to 50 users. Pick one price, ship it, and iterate. What you actually need early on is the local webhook testing setup so you’re not deploying every time you tweak your billing logic:
# Install Stripe CLI, then:
stripe listen --forward-to localhost:3000/webhooks
# You'll see events like this in your terminal:
# --> payment_intent.succeeded [evt_1Ox...]
# --> customer.subscription.created [evt_1Ox...]
That single command saves you from deploying to staging just to test a checkout flow. The Stripe CLI also lets you replay specific events with stripe events resend evt_XXXX, which is genuinely useful when you’re debugging webhook handlers and don’t want to fire a real payment.
Email: Resend + Loops or ConvertKit
Split your email into two categories and use different tools for each. Resend handles transactional β password resets, receipts, onboarding triggers. It has a dead-simple API, generous free tier (3,000 emails/month), and SPF/DKIM setup takes about 10 minutes. For sequences β your onboarding drip, trial expiration nudges β use Loops if you want something built for SaaS, or ConvertKit if you want more flexibility. Building your own SMTP setup is a trap. You’ll spend a weekend on deliverability, bounce handling, and unsubscribe compliance instead of talking to users. I’ve seen it happen to smart engineers repeatedly. Just don’t.
// Resend β send a transactional email in 4 lines
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
await resend.emails.send({
from: '[email protected]',
to: user.email,
subject: 'Your account is ready',
html: 'Click here to get started...
',
});
Error Tracking: Sentry Before You Go Public
Add Sentry before your first user lands, not after. You’ll miss the exact error that’s causing 40% of signups to fail silently. The free tier covers 5,000 errors/month and keeps 30 days of history β more than enough for early stage. On Next.js, the wizard handles sourcemaps, API route instrumentation, and the config file automatically:
npx @sentry/wizard@latest -i nextjs
# This scaffolds sentry.client.config.ts, sentry.server.config.ts,
# and patches next.config.js β review the diff before committing
The one gotcha: if you’re on Next.js 14+ with the App Router, double-check that the wizard version you’re running supports it. Some older wizard versions only partially instrument server components. Run npx @sentry/wizard@latest (literally latest) and you should be fine.
Support: Email Alias + Notion FAQ
A [email protected] alias forwarded to your personal inbox plus a public Notion page covering the top 10 questions is genuinely all you need until 200 users. Intercom starts at $39/month and you’ll spend more time configuring chatbot flows than you will answering actual support tickets. The real advantage of raw email at this stage is that every support request is a direct line to user frustration β you’re reading unfiltered feedback, not summaries. Once the same question appears three times, add it to the Notion FAQ and link it from your app’s help icon. That feedback loop alone will improve your product faster than any support platform.
Gotchas That Will Slow You Down
The thing that keeps tripping up first-time micro-SaaS founders isn’t the hard technical stuff β it’s the silent failures that waste entire afternoons before you even realize something’s wrong.
Stripe has separate webhook endpoints for test mode and live mode, and they don’t cross over. This sounds obvious until you’ve spent four hours staring at your checkout flow wondering why events aren’t firing, only to realize your server is listening on the live mode endpoint while your dashboard is showing test mode events (or vice versa). When you go live, add the webhook endpoint explicitly under Developers β Webhooks in live mode β it does not inherit from test mode. Verify with:
# After you add your live endpoint, trigger a test event from Stripe's dashboard
# then grep your server logs immediately
grep "stripe-signature" /var/log/yourapp/production.log | tail -5
PostHog’s autocapture is great right up until you build a React or Next.js SPA and wonder why your pageview counts look wrong. The default autocapture doesn’t know about client-side route changes β it fires once on initial load and that’s it. Fix it by hooking into your router:
// Next.js 13+ with App Router β put this in a layout component
import { usePathname } from 'next/navigation'
import { useEffect } from 'react'
import posthog from 'posthog-js'
export function PostHogPageView() {
const pathname = usePathname()
useEffect(() => {
// Fires on every client-side navigation, not just first load
posthog.capture('$pageview', { $current_url: window.location.href })
}, [pathname])
return null
}
Reddit’s shadowban is brutal because it’s completely silent to the account being banned. If you created a fresh account specifically to post about your product β which is a red flag to Reddit’s systems β your post might appear to exist from your perspective but be invisible to everyone else. Always check by opening an incognito window or logging out before you assume your post is live. A shadowbanned post getting zero traction looks identical to a post that simply didn’t resonate, which means you could spend weeks iterating on the wrong problem.
Product Hunt runs on Pacific time and the leaderboard resets at 12:01am PST sharp. If you launch at 11pm PST on a Tuesday, you get one hour of Tuesday’s votes before they disappear and you start Wednesday from zero. Launch at 12:05am PST instead and you get the full 24-hour window. I’ve watched people do everything right β good product, real following, scheduled emails β and still tank their launch by getting this one timezone detail wrong. Set a calendar alert, use a time zone converter, and just don’t wing it.
Your first 100 users are genuinely the most forgiving cohort you will ever have. They signed up early, they’re curious, and many of them want to help you succeed because they’re invested in the outcome. That goodwill evaporates fast β user number 500 expects things to work and has alternatives. The mistake I see over and over is founders treating early access like a soft launch where you clean things up before asking for feedback. Do the opposite: ship rough, put a Tally or Typeform feedback link directly in the UI, and do manual outreach to every single one of those first users. An hour of polish buys you nothing; a 15-minute call with user number 12 might tell you the entire positioning is wrong.
What to Do When Someone Churns Before You Hit 100
The instinct when someone churns is to immediately blame the product β rewrite the onboarding, add a tooltip, schedule a feature sprint. I’ve done all of that. None of it helped until I actually talked to the people who left. The most valuable thing you can do in the first 100 users phase isn’t write code. It’s send an embarrassingly simple email.
Within 24 hours of someone going quiet or canceling, send this. Plain text, no template, no unsubscribe footer:
Subject: quick question
Hey [name],
I noticed you didn't come back after signing up β totally fine if the timing was off,
but I'd genuinely love to know what happened. Was it confusing? Missing something?
Just not the right fit?
Even a one-line reply helps more than you know.
β [Your name]
That’s it. No HTML, no logo, no “we noticed you haven’t logged in recently (automated).” The thing that makes this work is that it looks like a human wrote it in 45 seconds β because you did. Response rates on plain-text churn emails are noticeably higher than polished ones. People will reply with paragraphs when they’d normally just ghost a marketing email. I’ve gotten replies from users that revealed entire product assumptions I’d had completely wrong.
Before you write a single line of new code based on what users tell you, watch session recordings first. PostHog has this built in β go to your project settings, find Session Replay, and toggle it on. It’s free up to 15,000 sessions/month on the cloud plan. Watch five recordings of users who churned. You’ll see things no interview or survey captures: the mouse hovering confused over a button for eight seconds, the user clicking something three times expecting a reaction that never comes, the rage-click on a form that silently failed validation. Five recordings will give you more signal than twenty survey responses.
// PostHog session replay filter β filter by churned users using a cohort
// In PostHog UI: Insights β Recordings β Add filter:
// Person property: subscription_status = 'churned'
// Then watch with 1.5x speed, annotate timestamps where confusion happens
Here’s the thing that caught me off guard the first time I audited churn properly: it usually wasn’t bugs. The app worked. Users just closed the tab before they ever understood what the app was for in practice β not in theory. They read the landing page, got it intellectually, signed up, hit a blank state or a setup screen, and bounced. The “aha moment” β that specific interaction where the product suddenly clicks β never happened. For a project management tool it might be the first time you see a task auto-assigned. For an analytics tool it’s the first graph that shows you something surprising. You need to know what yours is, and then obsessively measure how many users actually reach it.
Map your activation funnel explicitly. Three steps minimum:
- Step 1: Signup complete (email confirmed, account exists)
- Step 2: First key action (uploaded a file, connected an integration, created a project β whatever the irreversible first thing is)
- Step 3: Second key action (whatever happens right before users “get it”)
Track drop-off between steps 1 and 2 in PostHog or Mixpanel. If more than 60% of users who sign up never reach step 2, acquiring more users is actively counterproductive β you’re just pouring people into a leaky bucket. Fix the funnel first. Usually this means either the blank state is doing nothing (add a “try this first” default), the first required setup is too heavy (defer it), or the value isn’t visible until too late in the flow (surface it earlier). Spend a full sprint here before running another ad or posting another Product Hunt comment.