Temat

Szybki start — wygeneruj swoją pierwszą grafikę OG

Ten szybki start z FastOG pozwoli Ci uruchomić pierwszą dynamiczną grafikę Open Graph w kilka minut. Rejestracja jest darmowa — następnie wybierz plan Dynamic API, aby uzyskać limit renderowania. Klucz API oraz sekret HMAC tworzysz na żądanie w panelu. Każde renderowanie jest czyste — bez znaku wodnego na żadnym planie, w tym w darmowym testerze. Wypróbuj darmowy tester grafik OG, aby zobaczyć działanie potoku, a następnie podpisuj własne adresy URL, korzystając z poniższych kroków.

Jak to działa — architektura

FastOG jest zbudowany z myślą o obrazach OG na żądanie: Twoja strona podpisuje URL w momencie renderowania strony, crawler go pobiera, FastOG renderuje PNG raz, a Cloudflare go cache’uje, dzięki czemu każde kolejne pobranie jest natychmiastowe i darmowe.

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

Trzy zasady, dzięki którym to „po prostu działa”

  1. Podpisujesz treść, nie czas. Podpis obejmuje każdy parametr (tytuł, szablon, …). Identyczne parametry zawsze generują identyczny URL — to właśnie sprawia, że cache na brzegu sieci działa: ta sama treść → ten sam URL → trafienie w cache na zawsze.
  2. Obraz jest trwały po pierwszym renderowaniu. Podpis blokuje tylko pierwsze renderowanie. Gdy obraz zostanie wyrenderowany, brzeg FastOG przechowuje go przez rok, kluczując po parametrach treści — późniejsze żądania z tymi samymi parametrami są obsługiwane z brzegu i nigdy nie trafiają do renderera (nie liczą się do Twojego limitu). Nieprawidłowy podpis przy zcache’owanej treści nadal zwraca zcache’owany PNG (odpowiedź raportuje, która warstwa odpowiedziała: X-FastOG-Worker-Cache: HIT lub R2); tylko chybienie cache’u kończy się kodem 401.
  3. Jedyny scenariusz awarii. Sfałszowany URL (ktoś zmienia title/template) dostaje 401 od FastOG przy chybieniu cache’u — więc nigdy nie może zostać użyty do wyczerpania Twojego limitu. Legalne URL-e nigdy nie wygasają: pozostają ważne, dopóki nie obrócisz sekretu HMAC klucza.

1. Uzyskaj swój klucz API i sekret HMAC

  1. Przejdź do FastOG Dashboard → API Keys

  2. Kliknij „Create New API Key”

  3. Nadaj mu nazwę (np. „Production Website”)

  4. Skopiuj obie wartości (są pokazywane tylko raz!):

    • API Key: sk_... (32 znaki po prefiksie)
    • HMAC Secret: 64-znakowy ciąg szesnastkowy
  5. Zapisz je w swoich zmiennych środowiskowych:

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. Implementacja funkcji podpisywania URL

Pełne samouczki dla wielu frameworków i wzorców znajdziesz tutaj:

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. Użycie na Twoim blogu/stronie internetowej

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>

Szablon 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. Przetestuj swoją implementację

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>"

Oczekiwany rezultat:

  • ✅ Prawidłowy podpis → Zwraca obraz OG
  • ❌ Zmodyfikowany parametr (np. title) → {"code": "invalid_signature"}
  • ❌ Nieprawidłowy podpis → {"code": "invalid_signature"}

5. Lista kontrolna bezpieczeństwa

  • [ ] Sekret HMAC przechowywany w zmiennych środowiskowych (nie w kodzie)
  • [ ] Używanie protokołu HTTPS dla wszystkich żądań
  • [ ] Sekret nigdy nieujawniany w JavaScripcie po stronie klienta
  • [ ] Monitorowanie nieudanych prób podpisu

6. Obsługa błędów

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;
    }
}

Kolejne kroki

  1. Zaimplementuj podpisywanie w backendzie swojej strony (zobacz samouczki)
  2. Przetestuj z API FastOG
  3. Monitoruj logi pod kątem nieudanych prób podpisu
  4. Skonfiguruj alerty dla powtarzających się błędów

Pełną dokumentację znajdziesz w Przewodniku po podpisach HMAC.

Pełna dokumentacja API

Wypróbuj za darmo — bez rejestracji

Podglądaj i testuj dynamiczne obrazy OG w kilka sekund.

Otwórz darmowy tester obrazów OG

A BeCaSimulations site