Social Metadata Guide
Purpose
Provide a concise, copy/paste-safe reference for configuring social sharing metadata (Open Graph + Twitter Cards) and validating previews. Covers defaults in layout.tsx, project-specific metadata in [slug]/page.tsx, and how to validate cards before sharing.
Quick Start (Defaults)
- Set canonical site URL: Ensure
NEXT_PUBLIC_SITE_URLis set to your production domain (e.g.,https://portfolio.example.com). - Site-wide defaults:
src/app/layout.tsxdefines Open Graph + Twitter defaults used by all pages. - Per-project metadata:
src/app/projects/[slug]/page.tsxusesgenerateMetadatato set project-specific title/description and URLs. - Validate previews: Use the validators below before posting links.
Open Graph (OG) Metadata
- Why it matters: Facebook, LinkedIn, and most platforms render rich previews using OG tags.
- Minimum fields:
og:title,og:description,og:type,og:url,og:site_name. - Image guidance: 1200x630 px, HTTPS URL, descriptive
alttext.
Site-wide defaults (layout)
- Title/description set once in
src/app/layout.tsx. openGraph.type:websiteopenGraph.url: usesNEXT_PUBLIC_SITE_URLwhen provided; falls back to/.openGraph.siteName:Portfolio(can be branded as needed).
Project-specific metadata
- Implemented via
generateMetadatainsrc/app/projects/[slug]/page.tsx. - Title/description sourced from the project registry entry.
- URL construction uses
SITE_URL(fromNEXT_PUBLIC_SITE_URL) to build absolute paths:https://yourdomain.com/projects/<slug>. - If a project is missing, a graceful fallback is returned to avoid broken previews.
Twitter Cards
- Card type:
summary_large_imagefor project pages (best visual impact). - Fields used:
twitter.title,twitter.description,twitter.card. - Inherit title/description from the project registry to keep OG and Twitter in sync.
Validation Workflow
- Set prod URL: Confirm
NEXT_PUBLIC_SITE_URLmatches the deployed domain. - Deploy preview: Use Vercel preview URL or production after merge.
- Validate:
- Troubleshoot common issues:
- Stale cache → click "Scrape Again" in Facebook debugger or re-run Twitter validator.
- Missing images → ensure absolute HTTPS URLs and 1200x630 size.
- Truncated text → keep descriptions ~150–160 characters.
Privacy-Safe Analytics (Context)
- App uses Vercel Web Analytics (no cookies, no PII, GDPR-friendly).
- No extra env vars required; the
<Analytics />component is rendered inlayout.tsx. - Purpose: understand which pages/projects are viewed without tracking individuals.
Copy/Paste Examples
Project metadata (simplified excerpt)
// src/app/projects/[slug]/page.tsx (excerpt)
export async function generateMetadata({
params,
}: {
params: Promise<{ slug: string }>;
}): Promise<Metadata> {
const { slug } = await params;
const project = getProjectBySlug(slug);
const projectUrl = SITE_URL
? `${SITE_URL}/projects/${slug}`
: `/projects/${slug}`;
if (!project) {
return {
title: 'Project Not Found',
description: 'The requested project could not be found.',
};
}
return {
title: project.title,
description: project.summary,
openGraph: {
title: project.title,
description: project.summary,
type: 'website',
url: projectUrl,
siteName: 'Portfolio',
},
twitter: {
card: 'summary_large_image',
title: project.title,
description: project.summary,
},
};
}
Site-wide metadata defaults (simplified excerpt)
// src/app/layout.tsx (excerpt)
export const metadata: Metadata = {
title: {
default: 'Portfolio',
template: '%s | Portfolio',
},
description:
'Enterprise-grade portfolio with verified projects and evidence.',
metadataBase: SITE_URL ? new URL(SITE_URL) : undefined,
openGraph: {
type: 'website',
locale: 'en_US',
url: SITE_URL || '/',
siteName: 'Portfolio',
title: 'Portfolio',
description:
'Enterprise-grade portfolio with verified projects and evidence.',
},
twitter: {
card: 'summary_large_image',
title: 'Portfolio',
description:
'Enterprise-grade portfolio with verified projects and evidence.',
},
};
Troubleshooting Cheatsheet
- Preview not updating: Re-run validators; scrape again on Facebook; ensure caches bust with a new deploy.
- Image missing: Use absolute HTTPS URL; verify 1200x630; check that the image is reachable without auth.
- Wrong URL: Set
NEXT_PUBLIC_SITE_URLto the canonical domain; redeploy so metadataBase updates. - Mixed content warnings: Ensure all assets (images, links) are HTTPS.
References
- Open Graph reference: ogp.me/
- Twitter Card docs: developer.twitter.com/en/docs/twitter-for-websites/cards/overview/abouts-cards
- Next.js Metadata: nextjs.org/docs/app/api-reference/functions/generate-metadata
- Social preview validators: Twitter Card Validator, Facebook Sharing Debugger