Back to Blog
build-in-publicindie-hackersoauthretentionsolo-saas

7 of our last 17 signups bounced in under a minute. Here is the Google OAuth redirect that killed them.

Nemo4 min
Share:
TL;DR — We audited 30 days of BlogBurst signups. 7 of 17 real users bounced within 60 seconds of finishing Google OAuth. 1 user spent 46 hours on our /free-tools page without ever triggering an onboarding event. Root cause: the OAuth callback sent every new user to /login/dashboard regardless of whether they had completed onboarding. They landed on a blank dashboard with nothing to do. Fix was two files and about 60 lines. Shipped at 14:17 Beijing today.

7 of our last 17 signups bounced in under a minute.

I audited every non-test signup on BlogBurst from the last 30 days this morning.

17 real people clicked "Sign in with Google."

7 of them never produced a single event after the signup row landed in our database. No page view. No onboarding step. Nothing. Their last_active_at timestamp equals signup timestamp to the second. They closed the tab before any telemetry could fire.

1 of them — Jaroslaw — came through Google OAuth, saw something, and bounced in the same minute.

Another one — Johan — did not bounce. Johan spent 46 hours on our site over the next two weeks. 185 analytics events. All of them on /free-tools/ai-post-generator. He never once fired an onboarding_v2_view event. He used our free tool as if the rest of the product did not exist, because for him it did not.

Only 4 of the 17 actually activated: created a product, connected a platform, generated some content.

That is a 23% activation rate. Which would be fine — except we were optimizing the wrong funnel entirely.

I thought our onboarding wizard was the problem.

It wasn't. Our wizard is fine. Most of these users never saw it.

Here is the Google OAuth callback we shipped months ago. See if you spot it:

# apps/api/app/routers/google_auth.py
jwt_token = create_access_token(user.id, user.email)
redirect_base = mobile_redirect or f"{FRONTEND_URL}/login"
return RedirectResponse(url=f"{redirect_base}?token={jwt_token}")

New user or returning user, it doesn't matter. Every Google sign-in lands on /login?token=XXX.

Now look at what /login does when it sees a token in the URL:

// apps/web/src/app/(auth)/login/page.tsx
if (token) {
  Cookies.set('token', token, { expires: 7 })
  const redirect = searchParams.get('redirect')
  router.push(redirect && redirect.startsWith('/dashboard') ? redirect : '/dashboard')
}

Stores the cookie, then pushes to /dashboard. Every time. Even if a caller passed redirect=/onboarding in the URL, the startsWith('/dashboard') check would silently reject it.

Want this done automatically for your product?

Try BlogBurst — 7 Days Free

So for 30+ days, every brand-new BlogBurst user was being sent to a dashboard with zero products, zero connected platforms, zero content, and zero "do this next" prompts. A blank page. Then we scratched our heads about why nobody was activating.

The fix was embarrassingly small.

Two files. About 60 lines of actual change.

Backend — after creating the JWT, check whether the user has any real product. If they don't, append a redirect parameter:

if not mobile_redirect:
    has_product = db.query(UserProduct).filter(
        UserProduct.user_id == user.id,
        UserProduct.name != "_global_learning",
    ).first() is not None
    if not has_product:
        extra = "&redirect=/onboarding"

return RedirectResponse(url=f"{redirect_base}?token={jwt_token}{extra}")

Frontend — loosen the startsWith('/dashboard') check to accept /onboarding too:

const allowed =
  redirect && (redirect.startsWith('/dashboard') || redirect.startsWith('/onboarding'))
router.push(allowed ? redirect : '/dashboard')

Deployed at 14:17 Beijing time. Every new Google signup from now on gets routed into the flow we actually designed for them.

The lesson I keep re-learning

The bug was not in the onboarding wizard. It was in the door we shipped to get people to the wizard. I was staring at our onboarding_v2_view event, trying to understand why half the funnel never fired it — because the event genuinely was firing for everyone who made it to onboarding. The problem was that almost no one made it.

You cannot diagnose what you cannot see. And you cannot see what never happened.

I am also now watching every signup event for the next 7 days to verify the fix. If the numbers do not move by next week, the fix is not enough and something else is broken. I will post again.

What I specifically wish I had a month ago

  • An automated weekly diff of "users who signed up but produced N≤2 events in the following 48h" with their referrer + registration source, emailed to me.
  • A /debug/post-signup-trace?user_id=X admin endpoint that replays a user's complete event timeline.
  • A single integration test that asserts "new OAuth signup lands on /onboarding". We did not have one. We do now.

If you are running a SaaS and any of those sound like "I do not have that either" — the 30-day audit I did this morning took about 20 minutes. It is the highest-leverage thing I have done in weeks.

Stop posting manually. Let AI do it 24/7.

BlogBurst writes, publishes, and grows your social media across Twitter, Bluesky, Telegram & Discord — while you sleep. 7-day free trial, no credit card.

Start 7-Day Free Trial

7-day free trial · No credit card required