Lorsque vous partagez un lien sur Facebook, Twitter, LinkedIn, Discord ou Slack, la carte de prévisualisation riche qui apparaît est alimentée par les balises meta Open Graph (OG) et les balises Twitter Card. Bien les configurer signifie plus de clics et un aspect plus professionnel. Ce guide complet couvre chaque balise, chaque exigence de plateforme et chaque erreur courante.
Générez des balises meta parfaites avec notre outil gratuit →
Balises Open Graph Essentielles
Le protocole Open Graph a été créé par Facebook en 2010 et est maintenant adopté par presque toutes les plateformes sociales.
og:title
Le titre de votre page tel qu'il apparaît dans la carte de partage. Gardez-le sous 60 caractères.
<meta property="og:title" content="How to Build a REST API with Node.js in 2026" />og:description
Un résumé du contenu de la page affiché sous le titre. Visez 120-160 caractères.
<meta property="og:description" content="Step-by-step guide to building a production-ready REST API with Node.js, Express, and TypeScript. Includes auth, validation, and deployment." />og:image
L'image affichée dans la carte de partage. La balise la plus impactante — les publications avec images obtiennent 2-3x plus d'engagement. Doit être une URL absolue.
<meta property="og:image" content="https://example.com/images/rest-api-guide-og.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="REST API with Node.js — Complete Guide" />
<meta property="og:image:type" content="image/png" />og:url
L'URL canonique de la page.
<meta property="og:url" content="https://example.com/blog/rest-api-nodejs" />og:type
Le type de contenu. Valeurs courantes : website, article, product, profile.
<!-- For a general page -->
<meta property="og:type" content="website" />
<!-- For a blog post / article -->
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2026-02-10T08:00:00Z" />
<meta property="article:author" content="https://example.com/about" />
<meta property="article:section" content="Technology" />
<meta property="article:tag" content="Node.js" />
<meta property="article:tag" content="REST API" />Balises Open Graph Supplémentaires
Au-delà des bases, ces balises offrent un contrôle plus fin sur l'affichage de votre contenu :
<!-- Site name — shown above the title on Facebook -->
<meta property="og:site_name" content="DevToolBox" />
<!-- Locale — language_TERRITORY format -->
<meta property="og:locale" content="en_US" />
<meta property="og:locale:alternate" content="fr_FR" />
<meta property="og:locale:alternate" content="de_DE" />
<meta property="og:locale:alternate" content="es_ES" />
<meta property="og:locale:alternate" content="ja_JP" />
<!-- Video (for og:type = video.*) -->
<meta property="og:video" content="https://example.com/video.mp4" />
<meta property="og:video:width" content="1280" />
<meta property="og:video:height" content="720" />
<meta property="og:video:type" content="video/mp4" />
<!-- Audio -->
<meta property="og:audio" content="https://example.com/podcast-ep1.mp3" />
<meta property="og:audio:type" content="audio/mpeg" />Balises Twitter Card
Twitter (maintenant X) prend en charge son propre système de cartes avec quatre types. Twitter se rabat sur les balises OG si les balises Twitter sont absentes.
Types de Twitter Card
| Type de carte | Description | Cas d'utilisation |
|---|---|---|
| summary | Petite image carrée avec titre et description | Articles de blog, pages générales |
| summary_large_image | Grande image au-dessus du titre et de la description | Contenu visuel, articles vedettes |
| player | Lecteur vidéo/audio intégré dans le tweet | Hébergement vidéo, podcasts |
| app | Carte de téléchargement direct d'application | Promotion App Store / Google Play |
<!-- Summary Card (small image) -->
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="@yourusername" />
<meta name="twitter:creator" content="@authorname" />
<meta name="twitter:title" content="How to Build a REST API with Node.js" />
<meta name="twitter:description" content="Complete guide with auth, validation, and deployment." />
<meta name="twitter:image" content="https://example.com/images/rest-api-square.png" />
<meta name="twitter:image:alt" content="REST API Guide illustration" />
<!-- Summary Card with Large Image -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@yourusername" />
<meta name="twitter:title" content="How to Build a REST API with Node.js" />
<meta name="twitter:description" content="Complete guide with auth, validation, and deployment." />
<meta name="twitter:image" content="https://example.com/images/rest-api-wide.png" />
<!-- Player Card (video/audio) -->
<meta name="twitter:card" content="player" />
<meta name="twitter:player" content="https://example.com/embed/video123" />
<meta name="twitter:player:width" content="1280" />
<meta name="twitter:player:height" content="720" />
<!-- App Card -->
<meta name="twitter:card" content="app" />
<meta name="twitter:app:id:iphone" content="123456789" />
<meta name="twitter:app:id:googleplay" content="com.example.app" />
<meta name="twitter:app:name:iphone" content="My App" />
<meta name="twitter:app:name:googleplay" content="My App" />Exigences d'Image par Plateforme
Chaque plateforme a des exigences de taille d'image différentes :
| Plateforme | Taille recommandée | Taille minimum | Taille max fichier | Ratio | Formats |
|---|---|---|---|---|---|
| 1200 x 630 | 600 x 315 | 8 MB | 1.91:1 | JPG, PNG, GIF, WebP | |
| Twitter (summary) | 144 x 144 | 144 x 144 | 5 MB | 1:1 | JPG, PNG, GIF, WebP |
| Twitter (large image) | 1200 x 675 | 300 x 157 | 5 MB | 2:1 / 16:9 | JPG, PNG, GIF, WebP |
| 1200 x 627 | 200 x 200 | 5 MB | 1.91:1 | JPG, PNG | |
| Discord | 1200 x 630 | 256 x 256 | 8 MB | 1.91:1 | JPG, PNG, GIF |
| 1200 x 630 | 300 x 200 | 5 MB | 1.91:1 | JPG, PNG | |
| Slack | 1200 x 630 | 250 x 250 | 5 MB | 1.91:1 | JPG, PNG, GIF |
| Telegram | 1200 x 630 | 200 x 200 | 5 MB | 1.91:1 | JPG, PNG |
| 1000 x 1500 | 600 x 600 | 10 MB | 2:3 | JPG, PNG | |
| iMessage | 1200 x 630 | 300 x 300 | 5 MB | 1.91:1 | JPG, PNG |
Exemple de Balisage HTML Complet
Voici un head HTML prêt pour la production avec toutes les balises OG et Twitter Card :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- Primary Meta Tags -->
<title>How to Build a REST API with Node.js in 2026</title>
<meta name="description" content="Step-by-step guide to building a production-ready REST API with Node.js, Express, and TypeScript." />
<link rel="canonical" href="https://example.com/blog/rest-api-nodejs" />
<!-- Open Graph / Facebook -->
<meta property="og:type" content="article" />
<meta property="og:url" content="https://example.com/blog/rest-api-nodejs" />
<meta property="og:title" content="How to Build a REST API with Node.js in 2026" />
<meta property="og:description" content="Step-by-step guide to building a production-ready REST API with Node.js, Express, and TypeScript." />
<meta property="og:image" content="https://example.com/images/rest-api-og.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="REST API with Node.js guide banner" />
<meta property="og:site_name" content="My Dev Blog" />
<meta property="og:locale" content="en_US" />
<!-- Article-specific OG tags -->
<meta property="article:published_time" content="2026-02-10T08:00:00Z" />
<meta property="article:modified_time" content="2026-02-10T12:00:00Z" />
<meta property="article:author" content="https://example.com/about" />
<meta property="article:section" content="Web Development" />
<meta property="article:tag" content="Node.js" />
<meta property="article:tag" content="REST API" />
<meta property="article:tag" content="TypeScript" />
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@yourusername" />
<meta name="twitter:creator" content="@authorname" />
<meta name="twitter:title" content="How to Build a REST API with Node.js in 2026" />
<meta name="twitter:description" content="Step-by-step guide to building a production-ready REST API." />
<meta name="twitter:image" content="https://example.com/images/rest-api-twitter.png" />
<meta name="twitter:image:alt" content="REST API with Node.js guide banner" />
</head>
<body>
<!-- Page content -->
</body>
</html>Exemples par Framework
Les frameworks modernes fournissent des API intégrées pour gérer les balises meta :
Next.js (App Router — Metadata API)
// app/blog/[slug]/page.tsx
import { Metadata } from 'next';
type Props = { params: { slug: string } };
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.excerpt,
alternates: {
canonical: `https://example.com/blog/${params.slug}`,
},
openGraph: {
type: 'article',
title: post.title,
description: post.excerpt,
url: `https://example.com/blog/${params.slug}`,
siteName: 'My Dev Blog',
locale: 'en_US',
images: [
{
url: post.ogImage, // Must be absolute URL
width: 1200,
height: 630,
alt: post.title,
},
],
publishedTime: post.date,
authors: [post.author],
tags: post.tags,
},
twitter: {
card: 'summary_large_image',
site: '@yourusername',
creator: '@authorname',
title: post.title,
description: post.excerpt,
images: [
{
url: post.twitterImage, // Can differ from OG image
alt: post.title,
},
],
},
};
}
export default function BlogPost({ params }: Props) {
// Page component...
}Nuxt 3 (useSeoMeta)
<!-- pages/blog/[slug].vue -->
<script setup lang="ts">
const route = useRoute();
const { data: post } = await useFetch(`/api/posts/${route.params.slug}`);
useSeoMeta({
title: post.value.title,
description: post.value.excerpt,
ogType: 'article',
ogTitle: post.value.title,
ogDescription: post.value.excerpt,
ogUrl: `https://example.com/blog/${route.params.slug}`,
ogImage: post.value.ogImage,
ogImageWidth: 1200,
ogImageHeight: 630,
ogImageAlt: post.value.title,
ogSiteName: 'My Dev Blog',
ogLocale: 'en_US',
articlePublishedTime: post.value.date,
articleAuthor: post.value.author,
articleTag: post.value.tags,
twitterCard: 'summary_large_image',
twitterSite: '@yourusername',
twitterCreator: '@authorname',
twitterTitle: post.value.title,
twitterDescription: post.value.excerpt,
twitterImage: post.value.twitterImage,
twitterImageAlt: post.value.title,
});
</script>
<template>
<article>
<!-- Page content -->
</article>
</template>HTML Statique
<!-- For static HTML sites, simply add meta tags in <head> -->
<!-- You can automate this with a build tool or templating engine -->
<!-- Example with Eleventy (11ty) Nunjucks template -->
<head>
<title>{{ title }}</title>
<meta name="description" content="{{ description }}" />
<meta property="og:type" content="{% if layout == 'post' %}article{% else %}website{% endif %}" />
<meta property="og:title" content="{{ title }}" />
<meta property="og:description" content="{{ description }}" />
<meta property="og:image" content="{{ site.url }}{{ ogImage }}" />
<meta property="og:url" content="{{ site.url }}{{ page.url }}" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="{{ title }}" />
<meta name="twitter:description" content="{{ description }}" />
<meta name="twitter:image" content="{{ site.url }}{{ ogImage }}" />
</head>
<!-- Example with Hugo -->
<!-- layouts/partials/head.html -->
<meta property="og:title" content="{{ .Title }}" />
<meta property="og:description" content="{{ .Description }}" />
<meta property="og:image" content="{{ .Params.ogImage | absURL }}" />
<meta property="og:url" content="{{ .Permalink }}" />
<meta property="og:type" content="{{ if .IsPage }}article{{ else }}website{{ end }}" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="{{ .Title }}" />
<meta name="twitter:image" content="{{ .Params.ogImage | absURL }}" />Erreurs Courantes & Solutions
Les problèmes les plus fréquents rencontrés par les développeurs avec les balises meta sociales :
| # | Erreur | Problème | Solution |
|---|---|---|---|
| 1 | Relative image URLs | og:image="/images/og.png" — platforms cannot resolve relative paths | Always use absolute URLs: og:image="https://example.com/images/og.png" |
| 2 | Missing image dimensions | Facebook may not display the image on first share without width/height | Always include og:image:width and og:image:height tags |
| 3 | HTTP instead of HTTPS | Many platforms reject or warn about non-HTTPS image URLs | Serve all OG images over HTTPS. Use protocol-relative URLs as last resort |
| 4 | Not handling cache | Platforms cache previews for hours/days; updating tags has no immediate effect | Use platform debug tools to force refresh. Append ?v=2 for cache-busting |
| 5 | Same tags on every page | Every page shows the same preview card — confusing and poor CTR | Generate unique og:title, og:description, og:image per page |
| 6 | Missing twitter:card tag | Twitter will not render any card at all without this tag | Always include <meta name="twitter:card" content="summary_large_image" /> |
| 7 | Image too large (>8MB) | Facebook silently fails; Twitter shows no image | Optimize images: compress to <1MB, use JPEG for photos, PNG for graphics |
| 8 | Wrong image aspect ratio | Image gets cropped awkwardly — text cut off, faces cropped | Use 1200x630 (1.91:1) for OG, 1200x675 (16:9) for Twitter large image |
| 9 | Duplicate og:image tags | Unpredictable behavior — platform may pick the wrong image | Use only one og:image tag per page (or intentionally provide multiple with primary first) |
| 10 | Forgetting og:url | Shares from different URLs (www vs non-www, query params) counted separately | Set og:url to the canonical URL to consolidate share counts |
Outils de Test & Débogage
Validez toujours vos balises meta avant de publier. Chaque plateforme met en cache les aperçus de manière agressive.
| Outil | Plateforme | URL | Notes |
|---|---|---|---|
| Facebook Sharing Debugger | Facebook / Meta | developers.facebook.com/tools/debug/ | Shows all OG tags, image preview, and errors. Click "Scrape Again" to refresh cache. |
| Twitter Card Validator | Twitter / X | cards-dev.twitter.com/validator | Preview your Twitter Card. Validates tag structure. Requires Twitter login. |
| LinkedIn Post Inspector | linkedin.com/post-inspector/ | Validates OG tags for LinkedIn. Click "Inspect" to refresh cached preview. | |
| OpenGraph.xyz | Universal | opengraph.xyz | Preview how your URL appears on Facebook, Twitter, LinkedIn, Discord simultaneously. |
| Metatags.io | Universal | metatags.io | Real-time preview editor. Edit tags and see Facebook/Twitter/Google previews instantly. |
| Social Share Preview (VS Code) | Development | VS Code Extension | Preview OG tags directly in your IDE without deploying. |
| Ngrok / Cloudflare Tunnel | Development | ngrok.com | Expose localhost to test with real platform validators during development. |
Images OG Dynamiques
Générer des images sociales uniques par page augmente considérablement le taux de clics.
Pourquoi les Images OG Dynamiques Comptent
Des sites comme GitHub, Vercel et DEV.to génèrent des images OG par page.
<!-- Instead of this (same image for every page): -->
<meta property="og:image" content="https://example.com/default-og.png" />
<!-- Generate this (unique per page): -->
<meta property="og:image" content="https://example.com/api/og?title=How+to+Build+a+REST+API" />Génération avec @vercel/og
// app/api/og/route.tsx — Next.js Edge Route Handler
import { ImageResponse } from 'next/og';
import { NextRequest } from 'next/server';
export const runtime = 'edge';
export async function GET(req: NextRequest) {
const { searchParams } = new URL(req.url);
const title = searchParams.get('title') || 'Default Title';
const description = searchParams.get('desc') || '';
return new ImageResponse(
(
<div
style={{
width: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
padding: '60px 80px',
background: 'linear-gradient(135deg, #0f172a 0%, #1e293b 100%)',
fontFamily: 'Inter, sans-serif',
}}
>
<div style={{
fontSize: 56,
fontWeight: 800,
color: '#f8fafc',
lineHeight: 1.2,
marginBottom: 20,
}}>
{title}
</div>
{description && (
<div style={{
fontSize: 24,
color: '#94a3b8',
lineHeight: 1.5,
}}>
{description}
</div>
)}
<div style={{
display: 'flex',
alignItems: 'center',
marginTop: 'auto',
fontSize: 20,
color: '#64748b',
}}>
example.com
</div>
</div>
),
{
width: 1200,
height: 630,
}
);
}
// Usage in metadata:
// openGraph: { images: [`/api/og?title=${encodeURIComponent(post.title)}`] }Génération avec Node Canvas
// scripts/generate-og-images.ts — Build-time generation
import { createCanvas, registerFont } from 'canvas';
import fs from 'fs';
import path from 'path';
registerFont('fonts/Inter-Bold.ttf', { family: 'Inter', weight: 'bold' });
interface OGConfig {
title: string;
slug: string;
theme?: string;
}
function generateOGImage(config: OGConfig): Buffer {
const { title, theme = '#0f172a' } = config;
const width = 1200;
const height = 630;
const canvas = createCanvas(width, height);
const ctx = canvas.getContext('2d');
// Background gradient
const gradient = ctx.createLinearGradient(0, 0, width, height);
gradient.addColorStop(0, theme);
gradient.addColorStop(1, '#1e293b');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, width, height);
// Title text
ctx.fillStyle = '#f8fafc';
ctx.font = 'bold 52px Inter';
const words = title.split(' ');
let line = '';
let y = 240;
for (const word of words) {
const test = line + word + ' ';
if (ctx.measureText(test).width > 1040) {
ctx.fillText(line.trim(), 80, y);
line = word + ' ';
y += 70;
} else {
line = test;
}
}
ctx.fillText(line.trim(), 80, y);
// Site name
ctx.fillStyle = '#64748b';
ctx.font = 'bold 24px Inter';
ctx.fillText('example.com', 80, 560);
return canvas.toBuffer('image/png');
}
// Generate for all posts
const posts: OGConfig[] = [
{ title: 'How to Build a REST API with Node.js', slug: 'rest-api-nodejs' },
{ title: 'TypeScript Generics Explained', slug: 'typescript-generics' },
];
for (const post of posts) {
const buffer = generateOGImage(post);
const outPath = path.join('public', 'og', `${post.slug}.png`);
fs.mkdirSync(path.dirname(outPath), { recursive: true });
fs.writeFileSync(outPath, buffer);
console.log(`Generated: ${outPath}`);
}Utilisation des Transformations URL Cloudinary
// Using Cloudinary URL-based image transformations
// No server-side code needed — just construct the URL
function getCloudinaryOGImage(title: string): string {
const cloudName = 'your-cloud-name';
const baseImage = 'og-template.png'; // Upload a background template first
// URL-encode the title
const encodedTitle = encodeURIComponent(title);
// Cloudinary text overlay transformation
return [
`https://res.cloudinary.com/${cloudName}/image/upload`,
// Resize to OG dimensions
'w_1200,h_630,c_fill',
// Add text overlay
`l_text:Inter_52_bold:${encodedTitle}`,
'co_rgb:f8fafc', // Text color
'g_west', // Left-align
'x_80,y_-40', // Position
'w_1040,c_fit', // Max text width
// Base image
baseImage,
].join('/');
}
// Usage:
// <meta property="og:image"
// content={getCloudinaryOGImage('How to Build a REST API with Node.js')} />
// Result URL looks like:
// https://res.cloudinary.com/your-cloud-name/image/upload/
// w_1200,h_630,c_fill/
// l_text:Inter_52_bold:How%20to%20Build%20a%20REST%20API/
// co_rgb:f8fafc,g_west,x_80,y_-40,w_1040,c_fit/
// og-template.pngQuestions Fréquentes
Quelle est la différence entre Open Graph et Twitter Card ?
Open Graph a été créé par Facebook et est la norme universelle utilisée par Facebook, LinkedIn, Discord, Slack, WhatsApp, etc. Twitter Cards est le système propriétaire de Twitter/X. Twitter se rabat sur les balises OG si les balises Twitter sont absentes.
Ai-je besoin des deux types de balises ?
Techniquement non — Twitter lit les balises OG en secours. Mais inclure les deux est la meilleure pratique car twitter:card n'a pas d'équivalent OG et est nécessaire pour que Twitter affiche une carte.
Pourquoi mon image OG n'apparaît pas lors du partage ?
Causes les plus courantes : URL relative au lieu d'absolue, URL d'image retourne 404, fichier trop volumineux, plateforme a mis en cache l'ancienne version, balises og:image:width et og:image:height manquantes.
Quelle est la taille idéale d'image OG ?
La taille recommandée est 1200 x 630 pixels avec un ratio 1.91:1. Cela fonctionne bien sur Facebook, LinkedIn, Discord et la plupart des plateformes.
Comment forcer le rafraîchissement de l'aperçu OG ?
Chaque plateforme a son propre outil : Facebook Sharing Debugger, Twitter Card Validator, LinkedIn Post Inspector.
Puis-je utiliser des images différentes pour Facebook et Twitter ?
Oui. Définissez l'image Facebook avec og:image et l'image Twitter avec twitter:image. Twitter préfère twitter:image quand les deux sont présentes.