← 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