Sujet

Démarrage rapide — Générez votre première image OG

Ce démarrage rapide FastOG met en ligne votre première image Open Graph dynamique en quelques minutes. L’inscription est gratuite — choisissez ensuite un forfait Dynamic API pour le quota de rendu. Vous créez votre clé API et votre secret HMAC à la demande dans le tableau de bord. Chaque rendu est propre — aucun filigrane, quel que soit le forfait, testeur gratuit inclus. Essayez le testeur d’images OG gratuit pour voir le pipeline en action, puis signez vos propres URL avec les étapes ci-dessous.

Fonctionnement — Architecture

FastOG est conçu pour les images OG à la demande : votre site signe une URL au moment du rendu de la page, le crawler la récupère, FastOG génère le PNG une seule fois, et Cloudflare le met en cache afin que chaque requête ultérieure soit instantanée et gratuite.

sequenceDiagram
    participant You as You share a link
    participant Crawler as Social crawler
    participant Site as Your website
    participant FastOG as FastOG API
    participant Edge as Edge cache

    You->>Crawler: share a link to your post
    Crawler->>Site: GET the page without JavaScript
    Site->>Site: sign the og:image URL at render time
    Site-->>Crawler: HTML with signed og:image URL
    Crawler->>Edge: fetch the og:image URL
    Edge->>FastOG: cache miss, first time
    FastOG->>FastOG: verify the HMAC covers the exact params
    FastOG-->>Edge: render PNG, counts 1 toward monthly quota, cached for 1 year
    Edge-->>Crawler: PNG
    Crawler-->>You: image shown in the post preview
    Note over Edge, Crawler: identical params and URL mean a cache hit with no render

Les trois règles qui font que « ça fonctionne tout simplement »

  1. Signez le contenu, pas l'horloge. La signature couvre chaque paramètre (titre, template, …). Des paramètres identiques produisent toujours la même URL — c'est ce qui fait fonctionner le cache périphérique : même contenu → même URL → hit de cache à vie.
  2. L'image est permanente après le premier rendu. La signature ne contrôle que le premier rendu. Une fois l'image générée, la périphérie de FastOG la conserve pendant un an, indexée sur les paramètres de contenu — les requêtes ultérieures avec les mêmes paramètres sont servies depuis la périphérie et n'atteignent jamais le moteur de rendu (elles ne comptent pas dans votre quota). Une signature invalide sur un contenu en cache renvoie quand même le PNG mis en cache (la réponse indique quel niveau a répondu : X-FastOG-Worker-Cache: HIT ou R2) ; seul un miss de cache renvoie une erreur 401.
  3. Le seul mode d'échec. Une URL falsifiée (quelqu'un modifie title/template) reçoit une 401 de FastOG en cas de miss de cache — elle ne peut donc jamais être utilisée pour consommer votre quota. Les URL légitimes n'expirent jamais : elles restent valides jusqu'à ce que vous fassiez pivoter le secret HMAC de la clé.

1. Obtenez votre clé API et votre secret HMAC

  1. Accédez à Tableau de bord FastOG → Clés API

  2. Cliquez sur « Créer une nouvelle clé API »

  3. Donnez-lui un nom (par exemple, « Site de production »)

  4. Copiez les deux valeurs (affichées une seule fois !) :

    • Clé API : sk_... (32 caractères après le préfixe)
    • Secret HMAC : chaîne hexadécimale de 64 caractères
  5. Stockez-les dans votre environnement :

env
# Your website backend .env
FASTOG_API_KEY=sk_your_full_api_key
FASTOG_HMAC_SECRET=a1b2c3d4e5f6...  # 64 chars
FASTOG_API_URL=https://fastog.com/api/v1/og

2. Implémenter la fonction de signature d’URL

Pour des tutoriels complets couvrant plusieurs frameworks et schémas, consultez :

Node.js / Next.js

javascript
// lib/fastog-signer.js
import crypto from "crypto";

// RFC-3986 encode (encodeURIComponent leaves !'()* unencoded).
const enc = (s) =>
    encodeURIComponent(s).replace(
        /[!'()*]/g,
        (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase(),
    );

export function generateOgImageUrl(params) {
    const baseUrl = process.env.FASTOG_API_URL;
    const apiKey = process.env.FASTOG_API_KEY;
    const hmacSecret = process.env.FASTOG_HMAC_SECRET;

    const all = { ...params, key: apiKey };

    // Canonical: every param (except s), sorted, RFC-3986 encoded, joined with "&".
    const pairs = [];
    for (const [k, v] of Object.entries(all)) {
        for (const vv of Array.isArray(v) ? v : [v])
            pairs.push(`${enc(k)}=${enc(vv)}`);
    }
    pairs.sort();
    const canonical = pairs.join("&");

    // Content-signed: message = path + canonical query. No timestamp.
    const signature = crypto
        .createHmac("sha256", hmacSecret)
        .update(`GET/api/v1/og\n${canonical}`)
        .digest("hex");

    const url = new URL(baseUrl);
    for (const [k, v] of Object.entries(all)) {
        for (const vv of Array.isArray(v) ? v : [v])
            url.searchParams.append(k, vv);
    }
    url.searchParams.set("s", signature);
    return url.toString();
}

PHP (Laravel)

php
// app/Services/QuickogSigner.php
function generateOgImageUrl(array $params): string
{
    $baseUrl = config('services.fastog.api_url', 'https://fastog.com/api/v1/og');
    $apiKey = config('services.fastog.api_key');
    $hmacSecret = config('services.fastog.hmac_secret');

    $all = array_merge($params, ['key' => $apiKey]);

    // Canonical: every param except s, keys sorted (array values sorted too),
    // RFC-3986 encoded, joined with '&'. Content-signed — no timestamp.
    $pairs = [];
    foreach ($all as $k => $v) {
        $values = is_array($v) ? $v : [$v];
        sort($values, SORT_STRING);
        foreach ($values as $vv) {
            $pairs[] = rawurlencode((string) $k) . '=' . rawurlencode((string) $vv);
        }
    }
    sort($pairs, SORT_STRING);
    $canonical = implode('&', $pairs);

    $signature = hash_hmac('sha256', 'GET/api/v1/og' . "\n" . $canonical, $hmacSecret);

    return $baseUrl . '?' . http_build_query(array_merge($all, ['s' => $signature]));
}

Python (Django/FastAPI)

python
# utils/fastog.py
import hmac
import hashlib
import os
from urllib.parse import quote, urlencode

def _enc(s):
    return quote(str(s), safe='-._~')  # RFC-3986: only unreserved chars

def generate_og_image_url(params: dict) -> str:
    base_url = os.environ['FASTOG_API_URL']
    api_key = os.environ['FASTOG_API_KEY']
    hmac_secret = os.environ['FASTOG_HMAC_SECRET']

    all_params = {**params, 'key': api_key}

    # Canonical: every param except s, sorted, RFC-3986 encoded, joined with '&'.
    pairs = []
    for k, v in all_params.items():
        for vv in sorted(v if isinstance(v, list) else [v]):
            pairs.append(f"{_enc(k)}={_enc(vv)}")
    canonical = '&'.join(sorted(pairs))

    # Content-signed: message = path + canonical query. No timestamp.
    signature = hmac.new(
        hmac_secret.encode(),
        f"GET/api/v1/og\n{canonical}".encode(),
        hashlib.sha256,
    ).hexdigest()

    return f"{base_url}?{urlencode({**all_params, 's': signature})}"

3. Utilisation dans votre blog ou site web

Next.js App Router

tsx
// app/blog/[slug]/page.tsx
import { generateOgImageUrl } from "@/lib/fastog-signer";

export async function generateMetadata({ params }) {
    const post = await getPost(params.slug);

    const ogImageUrl = generateOgImageUrl({
        template: "blog",
        title: post.title,
        subtitle: post.excerpt,
        author: post.author.name,
    });

    return {
        title: post.title,
        description: post.excerpt,
        openGraph: {
            images: [ogImageUrl],
        },
    };
}

Laravel Blade

blade
{{-- resources/views/blog/show.blade.php --}}
@php
    $ogImageUrl = generateOgImageUrl([
        'template' => 'blog',
        'title' => $post->title,
        'subtitle' => $post->excerpt,
        'author' => $post->author->name,
    ]);
@endphp

<head>
    <meta property="og:image" content="{{ $ogImageUrl }}" />
    <meta property="og:title" content="{{ $post->title }}" />
    <meta property="og:description" content="{{ $post->excerpt }}" />
</head>

Modèle Django

django
{# blog/post_detail.html #}
{% load fastog_tags %}

<head>
    <meta property="og:image" content="{% generate_og_image_url post %}" />
    <meta property="og:title" content="{{ post.title }}" />
    <meta property="og:description" content="{{ post.excerpt }}" />
</head>

4. Testez votre implémentation

bash
# Generate a test URL
node -e "
const { generateOgImageUrl } = require('./lib/fastog-signer');
console.log(generateOgImageUrl({ title: 'Test', template: 'default' }));
"

# Test with curl
curl "https://fastog.com/api/v1/og?title=Test&key=sk_quick_123abc&s=<sig>"

Résultat attendu :

  • ✅ Signature valide → Renvoie l’image OG
  • ❌ Paramètre modifié (par ex. title changé) → {"code": "invalid_signature"}
  • ❌ Signature invalide → {"code": "invalid_signature"}

5. Liste de contrôle de sécurité

  • [ ] Secret HMAC stocké dans des variables d’environnement (pas dans le code)
  • [ ] Utilisation de HTTPS pour toutes les requêtes
  • [ ] Secret jamais exposé dans le JavaScript côté client
  • [ ] Surveillance des tentatives de signature échouées

6. Gérer les erreurs

javascript
if (response.status === 401) {
    const error = await response.json();

    switch (error.code) {
        case "missing_signature":
            // URL is missing `key` or `s` — re-generate it with your signer.
            break;
        case "invalid_signature":
            // A param changed after signing, or the secret doesn't match.
            // Re-sign the URL after any content change; verify the secret on both sides.
            break;
    }
}

Prochaines étapes

  1. Implémentez la signature dans le backend de votre site web (voir les tutoriels)
  2. Testez avec l’API FastOG
  3. Surveillez les journaux pour détecter les tentatives de signature échouées
  4. Configurez des alertes en cas d’échecs répétés

Pour la documentation complète, consultez le Guide de signature HMAC.

Référence complète de l’API

Essayez gratuitement — aucune inscription requise

Prévisualisez et testez des images OG dynamiques en quelques secondes.

Ouvrir le testeur d'images OG gratuit

A BeCaSimulations site