Panduan Memulai — Buat Gambar OG Pertama Anda
Panduan memulai FastOG ini membantu Anda menayangkan gambar Open Graph dinamis pertama dalam hitungan menit. Pendaftaran gratis — lalu pilih paket Dynamic API untuk kuota render. Anda membuat kunci API dan rahasia HMAC sesuai kebutuhan di dasbor. Setiap render bersih — tanpa tanda air di paket mana pun, termasuk penguji gratis. Coba Penguji Gambar OG Gratis untuk melihat alur kerja secara langsung, lalu tandatangani URL Anda sendiri dengan langkah-langkah di bawah ini.
Cara kerjanya — Arsitektur
FastOG dibangun untuk gambar OG sesuai permintaan: situs web Anda menandatangani URL saat waktu render halaman, crawler mengambilnya, FastOG merender PNG sekali, dan Cloudflare menyimpannya dalam cache sehingga setiap pengambilan berikutnya bersifat instan dan gratis.
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
Tiga aturan yang membuatnya "langsung berfungsi"
- Tandatangani kontennya, bukan waktunya. Tanda tangan mencakup setiap parameter (judul, template, …). Parameter yang identik selalu menghasilkan URL yang identik — itulah yang membuat cache edge berfungsi: konten yang sama → URL yang sama → cache hit selamanya.
- Gambar bersifat permanen setelah render pertama. Tanda tangan hanya menggerbang render pertama. Setelah gambar dirender, edge FastOG menyimpannya selama satu tahun dengan kunci pada parameter konten — permintaan berikutnya dengan parameter yang sama dilayani dari edge dan tidak pernah mengenai renderer (tidak dihitung ke kuota Anda). Tanda tangan yang salah pada konten yang sudah di-cache tetap mengembalikan PNG yang di-cache (respons melaporkan tier mana yang menjawab:
X-FastOG-Worker-Cache: HITatauR2); hanya cache miss yang mendapat 401. - Satu-satunya mode kegagalan. URL yang dirusak (seseorang mengubah
title/template) mendapat 401 di FastOG saat cache miss — sehingga tidak akan pernah bisa digunakan untuk menghabiskan kuota Anda. URL yang sah tidak pernah kedaluwarsa: URL tetap valid sampai Anda memutar rahasia HMAC kunci.
1. Dapatkan Kunci API dan Rahasia HMAC Anda
-
Buka Dasbor FastOG → Kunci API
-
Klik "Buat Kunci API Baru"
-
Beri nama (misalnya, "Situs Produksi")
-
Salin kedua nilai (hanya ditampilkan sekali!):
- Kunci API:
sk_...(32 karakter setelah awalan) - Rahasia HMAC: string heksadesimal 64 karakter
- Kunci API:
-
Simpan keduanya di lingkungan Anda:
# 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. Implementasikan Fungsi Penandatanganan URL
Untuk tutorial lengkap dengan berbagai framework dan pola, lihat:
- Next.js App Router
- Next.js Pages Router
- React
- SvelteKit
- Vue / Nuxt
- Astro
- Express
- Vanilla Node.js
- JavaScript
- PHP / Laravel
- Python
- Ruby / Rails
Node.js / Next.js
// 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)
// 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)
# 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. Penggunaan di Blog/Situs Web Anda
Next.js App Router
// 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
{{-- 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>
Template 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. Uji Implementasi Anda
# 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>"
Hasil yang diharapkan:
- ✅ Tanda tangan valid → Mengembalikan gambar OG
- ❌ Parameter yang diubah (misalnya
titlediubah) →{"code": "invalid_signature"} - ❌ Tanda tangan tidak valid →
{"code": "invalid_signature"}
5. Daftar Periksa Keamanan
- [ ] Rahasia HMAC disimpan dalam variabel lingkungan (bukan di dalam kode)
- [ ] Menggunakan HTTPS untuk semua permintaan
- [ ] Rahasia tidak pernah terekspos dalam JavaScript sisi klien
- [ ] Memantau upaya tanda tangan yang gagal
6. Menangani Kesalahan
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;
}
}
Langkah Berikutnya
- Implementasikan penandatanganan (signing) di backend situs web Anda (lihat tutorial)
- Uji dengan API FastOG
- Pantau log untuk percobaan tanda tangan yang gagal
- Siapkan peringatan (alerting) untuk kegagalan berulang
Untuk dokumentasi lengkap, lihat Panduan Tanda Tangan HMAC.