Lynkz Docs

Documentation

Everything you need to set up, deploy, and use Lynkz.

Overview

Lynkz is an open-source link-in-bio platform. Users create a public page at lynkz.app/username secured with a PIN — no account or email required.

Built with Next.js 16, Firebase Firestore, Resend, Framer Motion, and @dnd-kit. Deploy to Vercel in minutes.

Next.js 16

App Router + API Routes

Firebase

Firestore only, no auth

Resend

Magic link emails

Vercel

Hosting + serverless

Quick Start

1. Clone and install

git clone https://github.com/harshilarora250/lynkz
cd lynkz
npm install

2. Configure environment

cp .env.example .env.local
# Edit .env.local with your Firebase + Resend credentials

3. Run locally

npm run dev
# Open http://localhost:3000

Firebase Setup

Create a project

Go to console.firebase.google.com and create a new project.

Enable Firestore

Build → Firestore Database → Create database → choose your region → Start in production mode.

Set Firestore rules

Go to Firestore → Rules and paste the contents of firestore.rules from the repo, then click Publish.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /pages/{username} {
      allow read: if true;
      allow write: if !('pinHash' in request.resource.data)
                   && !('email' in request.resource.data);
    }
    match /analytics/{username} {
      allow read: if false;
      allow write: if true;
    }
    match /analytics/{username}/daily/{day} {
      allow read: if false;
      allow write: if true;
    }
    match /lockouts/{id} { allow read, write: if false; }
    match /magic_tokens/{token} { allow read, write: if false; }
  }
}

Get your web app config

Project Settings → Your apps → Add app → Web — copy the config values into your .env.local.

Get service account key

Project Settings → Service accounts → Generate new private key — download the JSON file and paste the entire contents as FIREBASE_SERVICE_ACCOUNT_KEY.

⚠️
The service account key is sensitive. Never commit it. Only add it as a Vercel environment variable.

Resend (Email)

Resend is optional — only needed for magic link PIN recovery. The app works without it.

⚠️
With Resend's free tier using onboarding@resend.dev, you can only send to the email registered on your Resend account. To send to any email, verify a custom domain at resend.com/domains and set RESEND_FROM_DOMAIN.

Setup steps

1. Create a free account at resend.com

2. Get your API key from the Resend dashboard

3. Add to Vercel: RESEND_API_KEY=re_xxxxxxxxxxxx

4. Optionally verify a domain and set RESEND_FROM_DOMAIN=yourdomain.com

Deploy to Vercel

Option A — GitHub import (recommended)

Push to GitHub → vercel.com → New Project → Import → Add environment variables → Deploy.

Option B — Vercel CLI

npm install -g vercel
vercel
💡
After adding environment variables in Vercel, always redeploy for them to take effect.

Environment Variables

VariableRequiredDescription
NEXT_PUBLIC_FIREBASE_API_KEYFirebase web config
NEXT_PUBLIC_FIREBASE_AUTH_DOMAINFirebase web config
NEXT_PUBLIC_FIREBASE_PROJECT_IDFirebase web config
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKETFirebase web config
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_IDFirebase web config
NEXT_PUBLIC_FIREBASE_APP_IDFirebase web config
FIREBASE_SERVICE_ACCOUNT_KEYFull JSON from service account
RESEND_API_KEYOptionalFor magic link emails
RESEND_FROM_DOMAINOptionalCustom sender domain
NEXT_PUBLIC_APP_URLRecommendedYour production URL
NEXT_PUBLIC_APP_NAMEOptionalDefaults to Lynkz

Features

PIN authentication

SHA-256 hashed with salt. 3-attempt lockout per IP, 24-hour ban stored in Firestore.

Magic link recovery

Single-use token, 15-minute expiry. Sent via Resend to a recovery email set in the dashboard.

Analytics

Page views + link clicks tracked server-side. Traffic sources, devices, browsers, daily chart for 7/14/30 days.

Themes

8 color themes, 3 button styles, 5 background animations (Static, Gradient, Bubbles, Mesh, Wave).

Link scheduling

Per-link start/end datetimes. Links outside their window are hidden automatically on the public page.

Drag to reorder

dnd-kit based, works on mouse and touch. New order saves automatically.

Export

JSON (structured data), CSV (spreadsheet), HTML (standalone self-hostable page).

Custom favicon

Per-page favicon via direct URL. Applied client-side via document.head injection.

Hide branding

Toggle to remove the Made with Lynkz footer on your public page.

Social icon detection

YouTube, Instagram, Twitter/X, TikTok, GitHub, LinkedIn, Spotify, Discord, Twitch, Patreon.

Security

Server-side only

All PIN logic, IP lockout, magic token generation/validation, and email sending run in Vercel serverless functions. FIREBASE_SERVICE_ACCOUNT_KEY and RESEND_API_KEY never reach the browser.

Client-side

The Firebase client SDK runs in the browser for dashboard reads/writes. The NEXT_PUBLIC_FIREBASE_* variables are intentionally public — security comes from Firestore rules, not key secrecy.

Sensitive field stripping

pinHash, email, updatedAt, and createdAt are deleted in lib/firebase-admin.ts before any data reaches a client component. Firestore rules also block clients from writing these fields.

💡
Run firebase deploy --only firestore:rules to push rules via CLI, or paste manually in the Firebase console.

FAQ

What if I forget my PIN?

If you've set a recovery email in Settings → PIN recovery email, use 'Forgot PIN?' on the login screen for a magic link. Without a recovery email, there's no recovery — write your PIN down.

Can I change my username?

Not yet. The username is the Firestore document ID. Create a new page and re-add your links.

Is my data private?

Page content (title, bio, links, theme) is publicly readable. Your PIN hash and recovery email are never exposed to clients.

Can I self-host?

Yes. Replace Firebase with any Firestore-compatible DB, Resend with any email provider, and Vercel with any Node.js host.

Why does the magic link fail?

With Resend's free tier, you can only send to your own Resend account email. Verify a domain at resend.com/domains to send to any address.

How do I add a custom domain?

Not built-in. Point a custom domain to your Vercel deployment and all pages work at your domain automatically.

Something missing?

Open an issue or PR on GitHub.

Open issueCreate your page →