DEV Community

Cover image for I Abandoned My Side Project. 210 Strangers Found It Anyway.
Umair Shakoor
Umair Shakoor

Posted on

I Abandoned My Side Project. 210 Strangers Found It Anyway.

I built a tool in React + TypeScript, got frustrated with it, and moved on to other ideas.

Three months later I opened Google Search Console out of curiosity.

6,700 impressions. 283 clicks. Position 6.5 on Google.

For a project I had completely abandoned.


The backstory

This was my second SaaS attempt. I'd already failed once and was deep in the "just ship something" mindset.

The idea was simple: URL shortener with expiry. When the time runs out, the link dies. No backend. No database. No auth.

I built it, looked at TinyURL and Bitly, thought "these already exist and they're worth $48M, I can't compete" — and moved on.

That was a mistake in reasoning. More on that in a second.


Google Search Console Performance ScreenShot of oneTimeLink

The accidental traction

When I came back to check on it, the keywords ranking were interesting:

  • "expire link generator"
  • "temporary link"
  • "one time use link"
  • "expiring link"

These aren't brand searches. These are problem-aware searches. People knew they had a problem and were looking for a solution.

I set up GA4. Within 24 hours:

  • 45 users
  • 20% generated a link
  • 72.5% bounce rate (bad, but the intent traffic was real)

The bounce rate told me the landing page was wrong. The usage rate told me the problem was real.


The technical decision that made this possible

Here's the part developers find interesting.

I had a constraint: no backend. I was building in React + TypeScript only, deployed on Vercel. No Node.js, no database, no server.

So how do you build expiring links without storing anything?

Encode everything in the URL itself.

When a user creates a link with an expiry, the app:

  1. Takes the destination URL
  2. Takes the expiry timestamp
  3. Encodes both into a single URL-safe string
  4. Passes that to TinyURL's API to shorten it

When someone visits the link:

  1. The short URL expands to the encoded long URL
  2. The app decodes the destination and expiry from the URL parameters
  3. Checks current timestamp against expiry
  4. If expired: shows expiration screen. If valid: redirects.

No database query. No server call. No stored data. The link carries its own expiry inside itself.

// Simplified encoding logic
const payload = {
  url: destinationUrl,
  exp: expiryTimestamp
};

const encoded = btoa(JSON.stringify(payload));
const longUrl = `https://onetimelink.vercel.app/r?d=${encoded}`;

// Then shorten via TinyURL API
const shortUrl = await shortenWithTinyURL(longUrl);
Enter fullscreen mode Exit fullscreen mode

This has a counterintuitive benefit: zero server storage = zero breach risk. There's nothing to hack. The data lives in the URL and nowhere else.

For freelancers sharing sensitive client links, that's not a technical footnote. That's the entire value proposition.


The validation mistake I almost made

After seeing the traction, my first instinct was to look at Google Drive's sharing features and think "people can already control access there, my expiry idea isn't a moat."

I almost pivoted away from it.

Instead I sent 21 DMs to freelancers, founders, and CTOs asking one question:

"When you send a client a password or sensitive link — what do you actually do?"

Three replies came back:

Djune (Founder & CEO): "I encrypt it in a message with a 1-hour life span with a PIN only they know."

Uzair (Top Rated Freelancer): "I just send them a document with the credentials."

Waqas (CTO): "Yes, this is a real problem. I use 1Password sharing or split the info across two channels. If you're building something: focus on one-time access, expiry, and making it easy for non-technical clients."

That last reply rewrote my entire positioning.

The insight wasn't "expiring links." The insight was "easy for non-technical clients."

Every existing solution — 1Password sharing, encrypted messages, split credentials — requires the recipient to do something. Install an app. Enter a PIN. Have an account.

OneTimeLink requires nothing from the recipient. They click. It works. Or it's expired.


Google Analytics G4A overview for oneTimeLink

What I changed after validation

Repositioned headline:
Before: "Share URLs that expire automatically"
After: "Share Sensitive Links Your Clients Can Actually Use"

Bounce rate: 72.5% → 51.9% after the copy change alone.

Average engagement: 9s → 19s.

Same product. Different words. Completely different results.


Current state: honest numbers

  • 210 organic users (zero paid traffic)
  • 26 users generated at least one link (12.4% activation)
  • 5 users attempted Pro waitlist signup
  • Revenue: $0.00
  • Paying customers: 0

I'm building in public because I think the honest version of this journey is more useful than the highlight reel.

The next milestone is the first paying user. Not the first hundred. Just one person who values this enough to pay $7/month.


What I'd do differently

  1. Set up analytics on day one. I flew blind for months.
  2. Don't confuse "utility" with "demand." Useful ≠ something people will pay for.
  3. Talk to users before building features. Three DM replies taught me more than three months of solo building.
  4. The technical constraint became the product. No backend wasn't a limitation. It became the trust signal: "nothing stored on our servers, ever."

Try it / feedback welcome

If you're a freelancer or developer who shares sensitive stuff with clients, I'd genuinely love brutal feedback:

👉 onetimelink.vercel.app

What would make you actually pay $7/month for this?

Drop it in the comments. I read everything.


Building OneTimeLink in public. Follow along if you want the unfiltered version.

Top comments (1)

Collapse
 
unseenumair profile image
Umair Shakoor

This can a 4 minute read but its lessons of my 4 months 🤫