Vibe Code a Link-in-Bio Tool (A Complete Micro-SaaS)

Build a Linktree alternative with AI — custom slugs, themes, analytics, and the reserved-word and impersonation problems nobody warns you about.

C
CodeIllusion Team
#vibe-coding #micro-saas #tutorial #saas
Vibe Code a Link-in-Bio Tool (A Complete Micro-SaaS)

This is the smallest thing that’s still a real SaaS. Accounts, public pages, custom URLs, analytics, and an obvious free/paid line — all in a project you can finish in a weekend.

It also has two security problems that are specific to letting users claim URLs on your domain, and neither is obvious.

The Build

Next.js App Router, TypeScript, Tailwind, Supabase.

Tables:

  • profiles: id, user_id, username citext unique, display_name, bio, avatar_url, theme, created_at
  • links: id, profile_id, title, url, icon, position integer, is_active boolean, click_count
  • link_clicks: id, link_id, clicked_at, referrer, country, device_type

Routes: /[username] public profile (no auth), /dashboard editor (auth required), /dashboard/analytics.

Public profiles statically generated with ISR, revalidating when the owner edits. Editor is dynamic.

Splitting static public pages from the dynamic editor is the architectural decision that makes this scale — public pages take essentially all the traffic.

Username Claiming: Two Real Problems

Reserved words

Without a blocklist, someone claims /admin, /login, or /api. Now their profile shadows your own routes, or worse, sits at a URL people trust.

Enforce a reserved username list covering: all existing app routes (dashboard, login, signup, api, admin, settings, pricing, blog), plus impersonation risks (support, help, billing, security, team, staff, official, verified), plus common file paths (favicon, robots, sitemap).

Validate usernames: 3–30 characters, lowercase letters, numbers, hyphens and underscores only. Normalise to lowercase before storing and checking.

Homograph impersonation

Subtler and worth catching. Unicode contains characters that render almost identically to ASCII — Cyrillic а looks like Latin a. Someone registers аpple (Cyrillic first letter) and it’s visually indistinguishable from apple.

Reject any username containing non-ASCII characters. Additionally, check that a new username isn’t visually confusable with an existing one after normalising common lookalike substitutions.

The Editor

Build the dashboard editor: edit display name, bio and avatar; add, edit, delete and reorder links via drag and drop; toggle links active without deleting them; live preview alongside the editor.

Reordering must persist the position field. Save the whole order in one request, not one request per link.

That last point matters — dragging one item to the top otherwise fires twenty requests.

Upload avatars to Supabase Storage. Validate: images only, max 2MB, resize server-side to 400x400. Never trust the client-reported content type — check actual file bytes.

Trusting the declared MIME type lets someone upload a script with an image extension.

Click Tracking Without Slowing Redirects

Route outbound clicks through /r/[linkId], which records the click and then redirects. Record after issuing the redirect using waitUntil so the user never waits. Use a 302, not a 301, so links stay editable and clicks keep counting.

Don’t store full IP addresses — derive country and discard.

Then the analytics:

Analytics page showing total clicks, clicks per link, clicks over time, top referrers, and device breakdown. Aggregate in SQL. Free tier sees 7 days, paid sees unlimited history.

Themes

The most-requested feature and the one most likely to become unmaintainable.

Implement themes as a set of predefined CSS custom property values stored as a theme name on the profile — not as arbitrary user CSS. Provide 6 presets. On paid plans, allow custom accent colour and font choice from a fixed list.

Letting users supply raw CSS on a page you serve is a cross-site scripting vector. Constrained options are both safer and produce better-looking results.

The Free/Paid Line

Natural split for this product:

FreePaid
Up to 5 linksUnlimited links
Preset themesCustom colours and fonts
7 days of analyticsFull history
Branded footerRemove branding
Custom domain

Enforce plan limits server-side in the API, not by hiding buttons. Attempting to add a sixth link on the free plan must fail at the endpoint with a clear upgrade message.

See vibe code a pricing page for the gating helper and Stripe checkout for billing.

Performance

Public profiles are your entire product surface.

Statically generate every public profile with ISR. Revalidate on edit via an on-demand revalidation call. Inline critical CSS. Preload the avatar. Target sub-1-second load on mobile.

The Checklist

  • Reserved username list covering routes, roles, and file paths
  • Usernames ASCII-only, normalised lowercase
  • Homograph confusion check
  • Avatar uploads validated by actual bytes, size-limited, resized
  • Themes constrained to presets, no user CSS
  • Reorder saves in one request
  • Clicks recorded after redirect, 302 not 301
  • No full IPs stored
  • Plan limits enforced server-side
  • Public profiles statically generated with ISR
  • Ownership filters on every editor query

On Actually Shipping This

The market is crowded and a generic Linktree clone won’t win. Narrow ones can — a version built for musicians with embedded players and tour dates, or for restaurants with menus and booking links, competes on fit rather than features.

The build is a weekend either way. The positioning is the hard part, and no amount of vibe coding helps with that.

Related reading:

Frequently Asked Questions

Is a link-in-bio tool a good project to build with AI? +

Yes — it's the smallest project that's still a complete SaaS. It has accounts, public pages, custom URLs, analytics, and a natural free/paid split, so you learn the full shape of a product without a large surface.

How do I handle custom usernames safely? +

Maintain a reserved word list covering your own routes plus impersonation risks like admin, support, and billing. Enforce a character whitelist, normalise to lowercase, and reject Unicode characters that look like ASCII letters.

How do public profile pages stay fast? +

Statically generate them with incremental static regeneration, so a page is served from cache and revalidates when the owner edits it. Public pages get far more traffic than the editor, so they're where caching matters.

Can this actually make money? +

It's a crowded market, so a generic clone won't. Narrow versions do better — a link-in-bio tool built specifically for musicians, restaurants, or newsletter writers can compete on fit where it can't compete on features.

Tagged:

#vibe-coding #micro-saas #tutorial #saas

Enjoyed this article?

Get more AI tool picks, coding tutorials, and no-code automation guides every week. No spam, ever.

Found this useful? Share it:

More in AI Coding Tools