Meta Tags That Actually Convert Clicks
My pages were finally indexed (robots.txt fixed) and discoverable (sitemap submitted). I was ranking positions 8-15 for dozens of keywords.
But my click-through rate was dismal: 2.1%.
Looking at my search results in incognito mode, I understood why. My titles were generic (“About Us | Company”), descriptions were truncated mid-sentence, and when shared on social media, the preview looked broken—no image, weird formatting, random text snippets.
After systematically fixing meta tags and Open Graph configuration, my CTR jumped to 4.3%. Same rankings, double the traffic. That’s an extra 500+ visitors per month without changing a single line of content.
Here’s exactly what I did.
The Anatomy of a Great Meta Tag
When someone sees your site in search results or social media, they see three things:
- Title (blue link they click)
- Description (gray text below)
- Image (when shared on social media)
Each one has specific rules for maximum impact:
Title Tags: The 60-Character Rule
Bad title (my original):
About Us | Your Company
Why it’s bad:
- Generic, could be anyone’s about page
- Doesn’t communicate unique value
- Boring, no reason to click
Good title:
Premium Next.js Development | 10+ Years Experience | Your Company
Why it works:
- Specific service (Next.js Development)
- Social proof (10+ years)
- Still includes brand name
- 59 characters (Google won’t truncate)
Formula:
[Specific Value] | [Differentiator] | [Brand]
Description Tags: The 155-Character Story
Bad description (my original):
Learn about our company, our mission, our values, and what makes us different from competitors in the industry.
Why it’s bad:
- Vague (“learn about,” “different”)
- No specific benefits
- No call to action
Good description:
Expert Next.js developers who've built 50+ production apps. Free consultation, 2-week turnaround, and ongoing support. Get a quote today.
Why it works:
- Concrete numbers (50+ apps, 2-week turnaround)
- Specific benefits (free consultation, support)
- Clear CTA (get a quote)
- 138 characters (won’t truncate)
Formula:
[Specific credential] + [Key benefits] + [Call to action]
Step 1: Create SEO Helper Module
Create app/src/components/common/seo/metadata.ts:
import { Metadata } from 'next'
type ValidLocale = 'en' | 'de'
interface SeoProps {
title: string
description: string
ogImage?: string
lang: ValidLocale
url?: string
alternateLocales?: ValidLocale[]
}
export const defaultSEOConfig = {
en: {
title: 'Your Company - Premium Next.js Development',
description: 'Expert Next.js developers with 50+ production apps delivered.',
},
de: {
title: 'Ihr Unternehmen - Premium Next.js-Entwicklung',
description: 'Experten für Next.js-Entwicklung mit 50+ ausgelieferten Apps.',
}
}
export function generateSEOMetadata({
title,
description,
ogImage = '/images/og-default.png',
lang,
url,
alternateLocales = ['en', 'de'],
}: SeoProps): Metadata {
const SITE_URL = process.env.SITE_URL ?? 'https://yoursite.com'
const SITE_NAME = 'Your Company'
// Ensure title includes site name
const fullTitle = title.includes(SITE_NAME)
? title
: `${title} | ${SITE_NAME}`
// Build absolute URLs
const canonicalUrl = url
? `${SITE_URL}${url}`
: `${SITE_URL}/${lang}`
const ogImageUrl = ogImage.startsWith('http')
? ogImage
: `${SITE_URL}${ogImage}`
// Build language alternates
const languages: Record<string, string> = {}
alternateLocales.forEach(locale => {
if (url) {
const altUrl = url.replace(`/${lang}/`, `/${locale}/`)
languages[locale] = `${SITE_URL}${altUrl}`
} else {
languages[locale] = `${SITE_URL}/${locale}`
}
})
return {
metadataBase: new URL(SITE_URL),
title: fullTitle,
description,
alternates: {
canonical: canonicalUrl,
languages: languages,
},
openGraph: {
type: 'website',
title: fullTitle,
description,
images: [
{
url: ogImageUrl,
width: 1200,
height: 630,
alt: title
}
],
url: canonicalUrl,
siteName: SITE_NAME,
locale: lang === 'en' ? 'en_US' : 'de_DE',
},
twitter: {
card: 'summary_large_image',
title: fullTitle,
description,
images: [ogImageUrl],
},
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
},
}
}
Step 2: Use in Your Pages
In any page (e.g., app/[lang]/about/page.tsx):
import { generateSEOMetadata } from '@/components/common/seo/metadata'
import { getTranslations } from 'next-intl/server'
export async function generateMetadata({
params
}: {
params: Promise<{ lang: string }>
}) {
const { lang } = await params
const t = await getTranslations({ locale: lang })
return generateSEOMetadata({
title: 'Expert Next.js Development | 10+ Years Experience',
description: 'We build production-ready Next.js apps with 50+ projects delivered. Free consultation, 2-week turnaround, ongoing support.',
lang: lang as 'en' | 'de',
url: `/${lang}/about`,
ogImage: '/images/about-og.png',
})
}
export default async function AboutPage() {
return <main>{/* Your content */}</main>
}
Step 3: Create Compelling Open Graph Images
Open Graph images appear when your links are shared on social media. This matters more than you think.
I A/B tested different OG images. Results:
- Generic logo on white background: 1.2% CTR on social shares
- Professional photo with text overlay: 3.8% CTR on social shares
OG image requirements:
- Dimensions: 1200×630px (1.91:1 ratio)
- File size: < 5MB (aim for < 300KB)
- Format: JPG or PNG
- Safe zone: Keep text/logos within center 1000×500px
What makes a good OG image:
- Clear, high-contrast text
- Professional photo or illustration
- Your logo (small, in corner)
- Specific to the page content
Tools to create them:
- Figma (free)
- Canva (free templates)
- og-image.vercel.app (automatic generation)
What Gets Generated
This creates comprehensive meta tags in your HTML:
<!-- Basic meta tags -->
<title>Expert Next.js Development | 10+ Years Experience | Your Company</title>
<meta name="description" content="We build production-ready Next.js apps..." />
<link rel="canonical" href="https://yoursite.com/en/about" />
<link rel="alternate" hreflang="en" href="https://yoursite.com/en/about" />
<link rel="alternate" hreflang="de" href="https://yoursite.com/de/about" />
<!-- Open Graph (Facebook, LinkedIn) -->
<meta property="og:type" content="website" />
<meta property="og:title" content="Expert Next.js Development..." />
<meta property="og:description" content="We build production-ready..." />
<meta property="og:image" content="https://yoursite.com/images/about-og.png" />
<meta property="og:url" content="https://yoursite.com/en/about" />
<meta property="og:site_name" content="Your Company" />
<meta property="og:locale" content="en_US" />
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Expert Next.js Development..." />
<meta name="twitter:description" content="We build production-ready..." />
<meta name="twitter:image" content="https://yoursite.com/images/about-og.png" />
Step 4: Test Your Meta Tags
Before deploying, test how they look:
Search Results Preview
- Metatags.io - Shows Google, Twitter, Facebook previews
- Check title length (should stay under 60 characters)
- Check description length (should stay under 155 characters)
Social Media Preview
- Facebook Sharing Debugger
- Twitter Card Validator
- LinkedIn Post Inspector
- OpenGraph.xyz - All platforms
Common Issues
Title shows “undefined” or brand name only
- Forgot to pass title to
generateSEOMetadata - Check your translation keys
Description truncated mid-sentence
- Keep it under 155 characters
- Put key info in first 120 characters
OG image not showing
- Use absolute URLs, not relative
- Check image is publicly accessible
- File size under 5MB
- Dimensions exactly 1200×630px
The 2x CTR Results
After implementing these meta tags:
Month 1:
- CTR: 2.1% → 2.8% (+33%)
- Same rankings, 33% more traffic
Month 2:
- CTR: 2.8% → 3.6% (+29%)
- Google started showing rich snippets (next post!)
Month 3:
- CTR: 3.6% → 4.3% (+19%)
- Compound effect with improved rankings
Total impact:
- From 2.1% to 4.3% CTR (+105%)
- From ~200 clicks/month to ~410 clicks/month
- Same impressions, double the traffic
Writing Tips That Actually Work
For titles:
- Lead with benefit, not brand
- Use numbers (10+ years, 50+ projects)
- Include primary keyword
-
Test with pipe ( ) vs dash (-)
For descriptions:
- First sentence = main benefit
- Second sentence = proof/credentials
- End with CTA
- Use active voice
For Open Graph:
- Different image per page (not just logo)
- Include text overlay with page title
- High contrast, professional look
- Test on actual social platforms
What’s Next?
Meta tags get people to click. But to really stand out in search results, you need rich snippets—those enhanced results with star ratings, FAQs, images, and structured data.
In the next post, I’ll show you how to implement 5 types of schema markup that transformed my plain search results into rich, eye-catching snippets. This took my already-good CTR and pushed it even higher.
Full SEO Series for Next.js:
- The Robots.txt Mistake That Cost Me Visitors
- Building Dynamic Multilingual Sitemaps in Next.js
- Meta Tags That Actually Convert Clicks (you are here)