OG Image A/B Testing: How to Split-Test Social Share Cards
How to A/B test og:image variations to improve click-through rates from Twitter, LinkedIn, and Slack previews — including cookie-based split testing, server-side variants, and what to measure.
Why OG image testing matters
Your og:image is the first visual element people see when your link is shared on Twitter, LinkedIn, Slack, or Discord. It has a direct impact on click-through rate (CTR) — studies show that posts with compelling visual previews get 3–5× more clicks than posts with generic or absent images.
Yet most teams pick an OG image once and never test it. Unlike page-level A/B testing (where variants are served to users visiting your site), OG image A/B testing is trickier because the image URL is cached by social platforms — sometimes for days. The key insight: you need to vary the URL that different visitors (or crawler fetches) see in the og:image tag, not just the image file behind a single URL.
Server-side A/B with cookies or headers
The most reliable approach for OG image A/B testing is server-side: assign each visitor to a variant when they first land on your page, store it in a cookie, and serve the corresponding og:image URL in the HTML.
// Next.js: app/blog/[slug]/page.tsx
import { cookies } from 'next/headers';
export default async function BlogPost({ params }: { params: { slug: string } }) {
const cookieStore = cookies();
let variant = cookieStore.get('og_variant')?.value;
// Assign variant if not set (server-side, stable per visitor)
if (!variant) {
variant = Math.random() < 0.5 ? 'A' : 'B';
// Note: setting cookies in Server Components requires middleware
// See the middleware approach below
}
const ogImages = {
A: `https://yourdomain.com/og/${params.slug}-v1.png`,
B: `https://yourdomain.com/og/${params.slug}-v2.png`,
};
const ogImage = ogImages[variant as 'A' | 'B'] ?? ogImages.A;
return (
<>
{/* OG tags are set via generateMetadata for Next.js */}
</>
);
}
// Use generateMetadata to set per-request OG tags
export async function generateMetadata({ params }: { params: { slug: string } }) {
const cookieStore = cookies();
const variant = cookieStore.get('og_variant')?.value ?? 'A';
const ogImages = {
A: `https://yourdomain.com/og/${params.slug}-variant-a.png`,
B: `https://yourdomain.com/og/${params.slug}-variant-b.png`,
};
return {
openGraph: {
images: [ogImages[variant as 'A' | 'B']],
},
};
}Edge middleware approach (Vercel / Cloudflare)
Edge middleware runs before your page renders, making it the ideal place to assign and read A/B variant cookies. This ensures the same visitor consistently sees the same OG image variant.
// middleware.ts (Next.js Edge Middleware)
import { NextRequest, NextResponse } from 'next/server';
export function middleware(request: NextRequest) {
const response = NextResponse.next();
// Assign variant if not set
let variant = request.cookies.get('og_variant')?.value;
if (!variant) {
variant = Math.random() < 0.5 ? 'A' : 'B';
response.cookies.set('og_variant', variant, {
maxAge: 60 * 60 * 24 * 30, // 30 days
httpOnly: false,
sameSite: 'lax',
});
}
return response;
}
export const config = {
matcher: ['/blog/:path*'],
};
// Cloudflare Worker equivalent:
// addEventListener('fetch', event => {
// const request = event.request;
// const cookieHeader = request.headers.get('Cookie') || '';
// const match = cookieHeader.match(/og_variant=([AB])/);
// const variant = match ? match[1] : (Math.random() < 0.5 ? 'A' : 'B');
// // Pass variant to your origin as a header
// const modifiedRequest = new Request(request, {
// headers: { ...Object.fromEntries(request.headers), 'X-OG-Variant': variant }
// });
// });Measuring OG CTR in analytics
Measuring OG image A/B test results requires tracking which variant each click came from. The most practical approach is using UTM parameters in the URLs you share, or reading the variant cookie on page load and firing an analytics event.
// Track OG variant on page load (client-side)
useEffect(() => {
const variant = document.cookie
.split('; ')
.find(row => row.startsWith('og_variant='))
?.split('=')[1] ?? 'unknown';
// Google Analytics 4
gtag('event', 'og_variant_view', {
og_variant: variant,
page_path: window.location.pathname,
});
// Plausible
plausible('OG Variant View', { props: { variant } });
}, []);
// Key metrics to track per variant:
// - CTR from social platforms (use UTM params on shared links)
// - Time on page (do better OG images attract more engaged users?)
// - Bounce rate from social referrals
// - Conversion rate (signups, purchases) from social referralsCommon winning patterns
Based on hundreds of OG image tests, these patterns consistently outperform generic screenshots or logo-only images:
- Text on image — A headline or key benefit overlaid on the image performs 40–60% better than images without text. Keep text under 10 words.
- Human faces — Faces (especially making eye contact) increase CTR significantly on LinkedIn and Twitter.
- High contrast — Dark backgrounds with bright text or vice versa stand out more in dark-mode social feeds (Twitter, Discord).
- Brand color anchoring — Consistent use of your brand color in OG images builds recognition over time.
- Numbers and specificity — "13 OG image mistakes" beats "OG image mistakes" almost every time.
- Platform-specific framing — LinkedIn audiences respond to professional/B2B framing; Twitter responds to opinionated takes.
OG A/B testing checklist
- Use different URL paths or query params for each variant — social platforms cache by URL.
- Assign variants server-side or via edge middleware for consistency across page loads.
- Run each test for at least 2 weeks and 100+ social clicks before calling a winner.
- Track the right metrics: social CTR, not just page views.
- Test one variable at a time: text vs no text, face vs no face, color scheme.
- Use OGFixer to preview both variants before launching.
Preview both OG image variants instantly
Paste your URLs into OGFixer to see exactly how each variant looks on Twitter, LinkedIn, Discord, and Slack before your test goes live.