skillmake
← marketplace
creatorsconceptsha:a561ea0d152894fbmanual

link-in-bio

Use when building a self-owned alternative to Linktree — single-page minimal link list with analytics, theming, scheduled-link toggles, and zero monthly fees, deployed under your own domain.

Tutorials · creator-attached
One-line install
curl --create-dirs -fsSL https://skillmake.xyz/i/link-in-bio -o ~/.claude/skills/link-in-bio/SKILL.md

The hash above pins this exact content. The file we serve at /api/marketplace/link-in-bio-a561ea0d/raw always matches sha:a561ea0d152894fb.

3,208 chars · ~802 tokens
---
name: link-in-bio
description: Use when building a self-owned alternative to Linktree — single-page minimal link list with analytics, theming, scheduled-link toggles, and zero monthly fees, deployed under your own domain.
source: https://nextjs.org/docs
generated: 2026-05-07T21:42:25.123Z
category: concept
audience: creators
---

## Tutorials

- https://skillmake.xyz/v/link-in-bio.mp4

## When to use

- Replacing a paid Linktree / Beacons / Bento page with one you own
- Single page hosting all your distribution links: YouTube, newsletter, course, socials
- Adding click analytics + UTM tracking without sending users through a third party
- Toggling time-bound promo links (event signups, launch days) without redeploying

## Key concepts

### links-as-config

A single links.json (or MDX file) holding the full link list — title, url, icon, scheduledFrom/To, hidden. The page is a server component reading this file at request time so toggling a link is one commit (or one Cloudflare KV write if you want runtime control).

### analytics-without-tracking

Each link points to /go/<slug> on your domain, which logs the click + UTM source then 302-redirects to the destination. Aggregate counts only — no cookies, no fingerprinting. Counts go to KV / Plausible / a tiny SQLite.

### scheduled visibility

scheduledFrom and scheduledTo on each link let you stage a launch link in advance and let it expire automatically. Page filters by `now()` server-side; no Cron, no scheduler.

## API reference

```
links.json shape
```

One source of truth for the page. Order = display order. Hidden links can sit in the file as drafts.

```
[
  { "title": "Latest video — 5 ways to ship faster", "url": "https://youtu.be/xxx", "icon": "youtube", "highlight": true },
  { "title": "Free newsletter", "url": "https://yourdomain.com/n", "icon": "mail" },
  { "title": "Q1 cohort — 3 spots left", "url": "https://yourdomain.com/cohort", "icon": "calendar", "scheduledFrom": "2026-01-15", "scheduledTo": "2026-02-15" }
]
```

```
/go/[slug] redirect route
```

Logs the click then 302s to the underlying URL. The slug maps back to the link entry; logs are aggregated counts only.

```
// app/go/[slug]/route.ts
import { redirect } from 'next/navigation';
import links from '@/links.json';
import { incrementClick } from '@/lib/analytics';
export async function GET(_req: Request, ctx: { params: Promise<{ slug: string }> }) {
  const { slug } = await ctx.params;
  const link = links.find((l) => l.slug === slug);
  if (!link) return new Response('Not found', { status: 404 });
  await incrementClick(slug);
  redirect(link.url);
}
```

## Gotchas

- Don't hand the page hundreds of links — 5–8 is the sweet spot. The whole point is curation, not a sitemap.
- Highlight one link only (latest, current launch). More than one and the eye doesn't know where to land.
- Mobile is 95% of traffic. Test on a real phone, single-column, 16+ pt body, 48+ pt tap targets.
- If you're going to skip /go/ analytics, at least add UTM params per link so destination analytics knows the source.

---
Generated by SkillMake from https://nextjs.org/docs on 2026-05-07T21:42:25.123Z.
Verify against source before relying on details.

File: ~/.claude/skills/link-in-bio/SKILL.md