DEV Community

Cover image for The Day We Fixed Our Signup Pipeline
Oge Obubu
Oge Obubu

Posted on

The Day We Fixed Our Signup Pipeline

It started with a graph.

Our signup numbers were climbing every week. The team was excited—growth was happening. But something felt off. A lot of those "users" never came back. Their email addresses looked strange. And our activation rate was quietly dropping.

One Friday afternoon, I decided to dig into the data.

What I found was not growth. It was noise.


The Diagnosis

I ran a simple query: group signups by IP address, count them, and sort descending.

The top result: one IP address had registered hundreds of accounts in the past 24 hours.

Same browser fingerprint. Same pattern. A script, probably hitting our register endpoint, generating accounts with throwaway email domains, and moving on.

I checked the user agents. Tools, not people.

I checked the email domains. Addresses that expire before the welcome email is even sent.

Our signup pipeline was wide open. Anyone, or anything, could walk in.


The Approach

We needed protection in layers. Not a single gate, but a series of filters. Each one catches something the others might miss.

We decided on three layers. And we built them all in a single sprint.


Layer 1: Throttling

The most obvious fix: rate limiting. But not just one limit, two.

Per-IP throttling: A small number of signup attempts per IP address within a short window. If you hit the limit, you get a clear response telling you when to retry.

No ambiguity.

Per-domain throttling: An even smaller tolerance for signups from the same email domain within a longer window. This catches distributed attacks, a bot using different IPs but always the same throwaway domain.

Two counters. A bot that shares either an IP or a domain gets stopped.


Layer 2: Blocklists

Rate limiting slows things down, but it doesn't stop determined attackers. They'll wait and come back. We needed permanent blocks.

Blocked email domains: We maintain a list of disposable email domains. Any registration attempt using one gets rejected before the data touches the database.

Blocked user agents: If the request comes from a non-browser tool, it's rejected with a simple error. No explanation. No details. Attackers don't need to know why they were blocked.


Layer 3: IP Blocklist

Some IPs are persistent. They've been flagged before. They've abused other endpoints, not just signup. Rate limiting won't stop them. Blocking their user agent won't stop them if they switch.

We needed a hard blocklist, IPs that are rejected for every request, not just registration.

The message is deliberately terse. No explanation. No recourse. The middleware runs on every route, every method, every request. If your IP is on the list, you don't get through.


Before and After

Before:

  • Hundreds of accounts from a single IP in 24 hours
  • Throwaway email domains made up a significant percentage of new signups
  • Activation rate was diluted by fake accounts
  • Every data-driven decision was slightly wrong because the denominator was inflated

After:

  • Same-IP registration farming dropped to zero
  • Disposable domain signups disappeared
  • Our signup numbers reflected actual human intent
  • Activation rate recovered, because the denominator now represented real users

What We Learned

1. Signal matters more than volume.

When signups are inflated by bots, every metric that depends on user count becomes unreliable. Activation rate. Retention. Revenue per user. Cleaning the pipeline made every downstream number trustworthy again.

2. A small amount of code can fix a big problem.

The solution wasn't complex. It was layered. Three simple mechanisms, each handling what the others miss.

3. Layers matter.

A single rate limit would have slowed the bots but not stopped them. A single blocklist would have caught the obvious ones but missed the persistent ones. The combination covers more surface area than any one approach.

4. Not all rejections are equal.

We chose our responses carefully. Legitimate users get useful feedback. Bad actors get silence. The message you send reveals how much information you want the requester to have.


The Takeaway

A healthy signup pipeline doesn't make the news. Nobody sends a tweet saying "I tried to sign up and couldn't because the IP throttling worked correctly."

But the absence of this work would eventually make headlines, just not the kind you want.

Growth is not just about getting users in the door. It's about making sure the users who come through are real. Every decision you make, product direction, marketing spend, feature priorities, depends on the quality of your data. And your data quality starts at the first line of defense: the registration endpoint.

The bots stopped. The data cleaned up. And our growth metrics finally told the truth.

Top comments (0)