A modern, customizable link-in-bio page built with Next.js and powered by Contentful CMS. Create your own personalized link collection similar to Linktree, but with full control over design and content management.
Perfect for creators, entrepreneurs, and anyone who wants a professional link collection page without monthly subscriptions.
- Node.js 18+ installed
- A Contentful account (free tier is more than enough)
- Git installed
git clone <your-repo-url>
cd dmg-links
npm installCreate a .env.local file in the root directory:
CONTENTFUL_SPACE_ID=your_space_id_here
CONTENTFUL_ACCESS_TOKEN=your_access_token_here
CONTENTFUL_WEBHOOK_SECRET=your_webhook_secret_here
# Optional: Google Analytics 4 tracking
NEXT_PUBLIC_GA_MEASUREMENT_ID=G-XXXXXXXXXXnpm run devOpen http://localhost:3000 to see your link page.
src/
├── app/ # Next.js App Router
│ ├── layout.tsx # Root layout with metadata
│ ├── page.tsx # Main page with dynamic metadata
│ └── globals.css # Global styles
├── components/ # React components
│ ├── LinktreePage.tsx # Main page component
│ └── LinkButton.tsx # Individual link button with smart display logic
├── lib/ # Utilities
│ ├── contentful.ts # Contentful client and API calls
│ └── icons.tsx # Heroicons integration and icon mapping
└── types/ # TypeScript definitions
└── contentful.ts # Contentful data types
npm run dev- Start development servernpm run build- Build for productionnpm run start- Start production server
- Dynamic Metadata: Page title, description, and favicon from Contentful
- Custom Color Palette: Dynamic Primary, secondary, and tertiary color system maintained in Contentful
- Smart Icon System: Heroicons integration with intelligent image/icon display logic
- Link Tracking: Google Analytics 4 integration with custom analytics API
- Social Media Icons: Instagram, LinkedIn, X (Twitter), YouTube with hover effects
- Responsive Design: Mobile-first approach with Tailwind CSS
- Image Optimization: Next.js Image component for optimal loading
- Type Safety: Full TypeScript support with Contentful types
- Cache Invalidation: Automatic cache updates via Contentful Webhooks
- Performance: Optimized caching with Next.js unstable_cache and Contentful Webhooks
Contentful is the main hub for managing all your content. Follow these steps to set up your content model and data.
- Go to contentful.com
- Sign up for a free account
- Create a new space
- Go to Settings → API keys
- Copy your Space ID and Content Delivery API - access token
- Add these to your
.env.localfile
Create a content type called linksMain with these fields:
| Field ID | Field Name | Field Type | Required | Help Text |
|---|---|---|---|---|
title |
Title | Short text | Yes | Your name or page title |
bio |
Bio | Long text | No | Brief description about you |
avatar |
Avatar | Media | No | Your profile picture |
siteTitle |
Site Title | Short text | No | Browser tab title |
siteIcon |
Site Icon | Media | No | Favicon for browser tab |
ogImage |
Open Graph Image | Media | No | Social media preview image (1200x630px recommended) |
instagram |
Short text | No | Instagram username (without @) | |
linkedIn |
Short text | No | LinkedIn username | |
twitter |
Twitter/X | Short text | No | Twitter/X username |
youtube |
YouTube | Short text | No | YouTube channel handle |
links |
Links | References | No | Reference to link entries |
colorPalette |
Color Palette | JSON Object | No | Custom color scheme (see Color Palette section) |
Create a content type called linksLinkContent with these fields:
| Field ID | Field Name | Field Type | Required | Help Text |
|---|---|---|---|---|
title |
Title | Short text | Yes | Link button title |
url |
URL | Short text | Yes | Destination URL |
description |
Description | Long text | No | Link description |
image |
Image | Media | No | Icon or preview image |
imageStyle |
Image Style | Short text, list | No | "Icon Sized" or "Big" |
icon |
Icon | Short text | No | Heroicons icon slug (see Icon Reference) |
displayOrder |
Display Order | Number | Yes | Sort order (lower = first) |
active |
Active | Boolean | Yes | Show/hide this link |
-
Go to Content → Add entry
-
Select LinksMain content type
-
Fill in your information:
- Title: Your name
- Bio: Brief description
- Avatar: Upload your profile picture
- Site Title: Page title for browser tab
- Site Icon: Upload favicon (32x32px recommended)
- Open Graph Image: Upload social media preview image (1200x630px recommended)
- Social Media: Add your usernames (without @ symbols)
-
Publish the entry
-
Create new entries with LinksLinkContent type
-
For each link:
- Title: Button text
- URL: Destination (include https://)
- Description: Optional description
- Image: Optional icon or preview
- Image Style: Choose "Icon Sized" (24px) or "Big" (preview)
- Icon: Optional Heroicons icon slug (see Icon Reference section)
- Display Order: Number for sorting (1, 2, 3...)
- Active: Toggle to show/hide
-
Publish all link entries
- Edit your LinksMain entry
- In the Links field, add references to your link entries
- Publish the updated entry
The platform includes a comprehensive icon system using Heroicons and smart display logic for images and icons.
Icons are powered by Heroicons - beautiful hand-crafted SVG icons by the makers of Tailwind CSS. Use the icon slugs from their website in your Contentful entries.
Popular Icon Slugs:
home- Home iconenvelope- Email iconphone- Phone iconglobeAlt- Website icondocumentText- Document iconphoto- Photo iconvideoCamera- Video iconmusicalNote- Music iconshoppingBag- Shopping iconheart- Heart iconstar- Star iconbookmark- Bookmark iconshare- Share iconchatBubbleLeftRight- Chat iconuser- User iconcog- Settings iconbell- Notification iconmagnifyingGlass- Search iconplus- Add iconarrowRight- Arrow icon
Find more icons at: https://heroicons.com/
The LinkButton component intelligently handles the combination of images and icons:
- ✅ Big image displayed on top (full width, 128px height)
- ✅ Icon displayed on the left in the content area below
- This creates a prominent visual hierarchy
- ✅ Icon-sized image on the left (24x24px)
- ✅ Icon on the right in the content area
- Both elements are displayed side by side
- "Big" style: Shows big image on top
- "Icon Sized" style: Shows icon-sized image on the left
- ✅ Icon on the right in the content area
- In your LinksLinkContent entry, add the Icon field
- Enter the icon slug from Heroicons (e.g.,
home,envelope,phone) - The icon will automatically appear with proper styling and color theming
- Icons adapt to your color palette (primary color for normal state, tertiary for hover)
The platform supports a flexible color palette system using three main colors: Primary, Secondary, and Tertiary.
- In your LinksMain entry, find the Color Palette field
- Add a JSON object with your color scheme:
{
"primary": "#1f2937",
"secondary": "#64748b",
"tertiary": "#f8fafc"
}- Primary: Main text color, hover backgrounds, active states
- Secondary: Secondary text, borders, social icons
- Tertiary: Background colors, hover text
Professional (Default):
{
"primary": "#1f2937",
"secondary": "#64748b",
"tertiary": "#f8fafc"
}Vibrant Alternative:
{
"primary": "#ff6b35",
"secondary": "#f7931e",
"tertiary": "#2d1b69"
}Dark Theme:
{
"primary": "#ffffff",
"secondary": "#a1a1aa",
"tertiary": "#18181b"
}- Images: Use high-quality images, Contentful will optimize them
- Open Graph Image: Use 1200x630px for optimal social media sharing
- URLs: Always include
https://in your URLs - Ordering: Use display order numbers (1, 2, 3...) for easy sorting
- Testing: Use the preview feature to test before publishing
- Backup: Contentful automatically versions your content
Page shows "No Links Found"
- Check your environment variables are correct
- Ensure your LinksMain entry is published
- Verify content type names match exactly
Images not loading
- Check image URLs in Contentful
- Ensure images are published
- Verify image file formats are supported
Social links not working
- Remove @ symbols from usernames
- Check URL formats are correct
- Ensure social media fields are filled
- Push your code to GitHub
- Connect your repository to your hosting service
- Add environment variables:
CONTENTFUL_SPACE_IDCONTENTFUL_ACCESS_TOKENCONTENTFUL_WEBHOOK_SECRET
- Set up Contentful webhook (see Webhook Setup section)
- Ship!
This Next.js app can be deployed to any platform that supports Node.js:
- Netlify
- Railway
- DigitalOcean App Platform
- AWS Amplify
Set up automatic cache invalidation so your site updates immediately when you publish content in Contentful.
- Go to Settings → Webhooks in your Contentful space
- Click Add webhook
- Configure the webhook:
Basic Settings:
- Name:
Cache Invalidation - URL:
https://yourdomain.com/api/webhook/contentful - HTTP Method:
POST - Content Type:
application/json
Headers:
x-webhook-secret: your_webhook_secret_here
x-contentful-topic: ContentManagement.Entry.publish
Triggers (select these events):
- ✅ Entry publish
- ✅ Entry unpublish
- ✅ Entry delete
- ✅ Entry archive
- ✅ Entry unarchive
Content Types (select these):
- ✅
linksMain - ✅
linksLinkContent
- After creating the webhook, copy the Webhook Secret
- Add it to your environment variables as
CONTENTFUL_WEBHOOK_SECRET
# Test manual tag revalidation
curl "https://yourdomain.com/api/webhook/contentful?secret=your_secret&tag=links-main"
# Test with content type
curl "https://yourdomain.com/api/webhook/contentful?secret=your_secret&type=linksMain"- Content Change: You publish/unpublish content in Contentful
- Webhook Trigger: Contentful sends a POST request to your webhook endpoint
- Cache Invalidation: The webhook invalidates specific cache tags
- Fresh Content: Next request fetches updated content from Contentful
The platform includes comprehensive link tracking to help you understand which links are most popular and how users interact with your page.
Setup:
- Create a Google Analytics 4 property at analytics.google.com
- Get your Measurement ID (format:
G-XXXXXXXXXX) - Add it to your
.env.localfile:NEXT_PUBLIC_GA_MEASUREMENT_ID=G-XXXXXXXXXX
What's Tracked:
- ✅ Link clicks with title, URL, and metadata
- ✅ Page views and user sessions
- ✅ User demographics and behavior
- ✅ Custom events for image styles and icons
- ✅ Real-time data in GA4 dashboard
The platform also includes a custom analytics endpoint at /api/analytics/link-click that logs:
- Link title and URL
- Timestamp and user agent
- Referrer information
- IP address (for privacy-compliant analytics)
To enable custom tracking:
- Uncomment the fetch call in
LinkButton.tsx - Set up a database to store click data
- Build a custom dashboard for your analytics
Privacy-Focused Options:
- Plausible Analytics: Privacy-first, GDPR compliant
- Umami: Self-hosted, open-source analytics
- Fathom: Simple, privacy-focused analytics
Implementation:
<!-- Plausible -->
<script defer data-domain="yourdomain.com" src="https://plausible.io/js/script.js"></script>
<!-- Umami -->
<script async src="https://your-umami-instance.com/script.js" data-website-id="your-id"></script>Link Performance:
- Most clicked links
- Click-through rates
- Time of day patterns
- Geographic distribution
User Behavior:
- Session duration
- Bounce rate
- Device types
- Traffic sources
Content Insights:
- Which image styles perform best
- Icon vs. image preferences
- Description impact on clicks
- Modify
src/app/globals.cssfor global styles - Update Tailwind classes in components
- Use the Color Palette system instead of hardcoded colors
- Customize hover effects and transitions
- Adjust spacing and sizing in component files
- Modify the responsive breakpoints
- Add new sections to
LinktreePage.tsx
- Add new social media platforms
- Create custom color palettes
- Add analytics tracking
- Create multiple page layouts
- Extend webhook functionality for new content types
After setting up your basic link page, consider:
- Custom Domain: Point your domain to the deployed app
- Analytics: Add Google Analytics or similar tracking
- SEO: Optimize meta tags and add structured data
- Color Palettes: Create multiple color schemes for different moods
- Advanced Features: Add contact forms, newsletter signups, etc.
- Performance: Monitor cache hit rates and optimize webhook responses
Need help? Check the Next.js documentation or Contentful documentation for more advanced features.