Перейти к содержимому
Tutorial

Генерируйте изображения Open Graph с помощью одного вызова API, Next.js не требуется.

| 6 min read

Используйте API изображений botoi OG для создания социальных карточек PNG размером 1200x630 из любой платформы. Работает с платформами Astro, Django, Rails, Laravel и headless CMS.

Social media preview cards on various platforms
Photo by dole777 on Unsplash

Ваше сообщение в блоге будет опубликовано в Twitter. Вместо расширенного предварительного просмотра с титульной карточкой ссылка показывает пустой серый ящик. Или, что еще хуже, растянутый значок. Каждая публикация без надлежащего изображения OG — это пропущенный клик.

Популярное решение — Vercel. @vercel/og библиотека. Работает хорошо, но заблокирован Next.js и инфраструктура Vercel. Satori (движок, стоящий за ним) нуждается в среде выполнения Node.js со специальными возможности загрузки шрифтов. Если вы работаете с Astro, Django, Rails, Laravel, Hugo или любым другим framework, вы сами по себе.

Есть более простой подход: отправить один POST-запрос в API и получить готовый PNG размером 1200x630. Нет зависимости от Node.js. Никакой привязки к фреймворку. Нет конвейера рендеринга изображений, который нужно поддерживать.

Один запрос POST, один PNG обратно

The ботои И API изображений принимает тело JSON с вашим заголовком, описанием и предпочтениями темы. Он возвращает необработанные двоичные данные PNG.

curl -X POST https://api.botoi.com/v1/og/generate \\
  -H "Content-Type: application/json" \\
  -d '{
    "title": "How to build a REST API in Go",
    "description": "A step-by-step guide with net/http and no frameworks",
    "theme": "dark"
  }' \\
  --output og-image.png

Вот и все. Ответ представляет собой PNG-файл, который вы можете сохранить, передать или загрузить в CDN:

HTTP/1.1 200 OK
Content-Type: image/png
Content-Length: 48271

(binary PNG data, 1200x630px)

API управляет типографикой, макетом и правильным размером. Вы передаете текст, вы получаете изображение.

Astro-интеграция: создание OG-изображений во время сборки

Генерация статических сайтов Astro делает это особенно чистым. Создайте динамический маршрут API, который извлекает OG-образы во время сборки и обслуживают их как статические. .png файлы.

// src/pages/og/[slug].png.ts
import type { APIRoute, GetStaticPaths } from 'astro';

// Your posts data source (markdown, CMS, database, etc.)
import { getAllPosts } from '@/lib/posts';

export const getStaticPaths: GetStaticPaths = async () => {
  const posts = await getAllPosts();
  return posts.map((post) => ({
    params: { slug: post.slug },
    props: { title: post.title, description: post.description },
  }));
};

export const GET: APIRoute = async ({ props }) => {
  const res = await fetch('https://api.botoi.com/v1/og/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      title: props.title,
      description: props.description,
      theme: 'dark',
    }),
  });

  const imageBuffer = await res.arrayBuffer();

  return new Response(imageBuffer, {
    headers: {
      'Content-Type': 'image/png',
      'Cache-Control': 'public, max-age=31536000, immutable',
    },
  });
};

В течение astro build, этот маршрут генерирует PNG для каждого сообщения. Выходные файлы попадают в твой dist/og/ каталог как статические ресурсы. Никакого создания образов во время выполнения, никаких бессерверных функций функция, нет холодного запуска.

Ссылка на изображения в шапке страницы:

<!-- In your BaseLayout.astro or page head -->
<meta property="og:image" content={\`https://yoursite.com/og/\${slug}.png\`} />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" content={\`https://yoursite.com/og/\${slug}.png\`} />

Каждая страница получает уникальную социальную карту, созданную один раз во время сборки и навсегда кэшируемую CDN.

Интеграция Django и Rails

Платформы, отображаемые на сервере, могут генерировать OG-изображения по запросу и кэшировать результат.

Джанго

# views.py
import requests
from django.http import HttpResponse
from django.views.decorators.cache import cache_page


@cache_page(60 * 60 * 24)  # Cache for 24 hours
def og_image(request, slug):
    post = get_object_or_404(Post, slug=slug)

    response = requests.post(
        'https://api.botoi.com/v1/og/generate',
        json={
            'title': post.title,
            'description': post.description,
            'theme': 'dark',
        },
        timeout=5,
    )

    return HttpResponse(
        response.content,
        content_type='image/png',
    )
# urls.py
urlpatterns = [
    path('og/<slug:slug>.png', views.og_image, name='og_image'),
]

The @cache_page декоратор хранит сгенерированное изображение в течение 24 часов. После первого запросу, Django обслуживает кэшированный PNG напрямую, не обращаясь повторно к API.

Рельсы

# app/controllers/og_images_controller.rb
class OgImagesController < ApplicationController
  def show
    post = Post.find_by!(slug: params[:slug])

    response = HTTP.post(
      'https://api.botoi.com/v1/og/generate',
      json: {
        title: post.title,
        description: post.description,
        theme: 'dark'
      }
    )

    expires_in 24.hours, public: true
    send_data response.body.to_s, type: 'image/png', disposition: 'inline'
  end
end
# config/routes.rb
get 'og/:slug.png', to: 'og_images#show'

Оба примера следуют одной и той же схеме: найдите сообщение по слагу, POST заголовку и описанию. в API и верните PNG с кеширующими заголовками. Фреймворк занимается кэшированием; API обрабатывает генерация изображения.

Безголовая интеграция с CMS: создание при публикации

Если ваш контент хранится в безголовой CMS, такой как Strapi, Contentful или Sanity, вы можете создать OG изображения всякий раз, когда редактор публикует или обновляет сообщение. Подключите вебхук, который срабатывает на контенте изменения.

Общий обработчик веб-перехватчика

// Webhook handler (any Node.js server or serverless function)
import { writeFileSync } from 'fs';

export async function handleCmsPublish(payload) {
  const { title, description, slug } = payload.entry;

  const res = await fetch('https://api.botoi.com/v1/og/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ title, description, theme: 'light' }),
  });

  const buffer = Buffer.from(await res.arrayBuffer());

  // Save to your public/static directory or upload to S3/R2
  writeFileSync(\`./public/og/\${slug}.png\`, buffer);

  console.log(\`Generated OG image for: \${slug}\`);
}

Крючок жизненного цикла Strapi

// Strapi lifecycle hook: src/api/post/content-types/post/lifecycles.js
module.exports = {
  async afterUpdate(event) {
    const { result } = event;

    const res = await fetch('https://api.botoi.com/v1/og/generate', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        title: result.title,
        description: result.description,
        theme: 'dark',
      }),
    });

    // Upload to your CDN or save locally
    const buffer = Buffer.from(await res.arrayBuffer());
    await strapi.plugins.upload.services.upload.upload({
      data: { path: \`og/\${result.slug}.png\` },
      files: { buffer, name: \`\${result.slug}.png\`, type: 'image/png' },
    });
  },
};

Этот подход полезен для команд, где редакторы контента публикуют контент через CMS, а разработчики этого не делают. хочу запускать конвейер сборки для каждого изменения текста. ОГ-изображение автоматически восстанавливается, когда изменение названия или описания публикации.

Бонус: извлекайте метаданные OG из любого URL-адреса.

Botoi API также предоставляет /v1/url-metadata, что делает обратное: по заданному URL-адресу извлекается страницу и извлекает ее теги Open Graph. Это полезно для создания предварительного просмотра ссылок, социальных карточек. валидаторы или инструменты SEO-аудита.

curl -X POST https://api.botoi.com/v1/url-metadata \\
  -H "Content-Type: application/json" \\
  -d '{"url": "https://github.com/astro-community/astro-embed"}'

Ответ:

{
  "success": true,
  "data": {
    "url": "https://github.com/astro-community/astro-embed",
    "status": 200,
    "title": "GitHub - astro-community/astro-embed",
    "description": "Components to embed third-party media in Astro projects",
    "og": {
      "title": "astro-embed",
      "description": "Components to embed third-party media in Astro projects",
      "image": "https://opengraph.githubassets.com/...",
      "type": "object",
      "url": "https://github.com/astro-community/astro-embed",
      "site_name": "GitHub"
    }
  }
}

Используйте это для создания компонентов предварительного просмотра ссылок в вашем приложении:

async function getLinkPreview(url: string) {
  const res = await fetch('https://api.botoi.com/v1/url-metadata', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ url }),
  });

  const { data } = await res.json();

  return {
    title: data.og?.title ?? data.title,
    description: data.og?.description ?? data.description,
    image: data.og?.image,
    siteName: data.og?.site_name,
  };
}

Объедините обе конечные точки: используйте /v1/url-metadata чтобы проверить, как ваши страницы отображаются в социальных сетях платформы и /v1/og/generate создавать изображения, которые заставят их выглядеть хорошо.

Почему бы не запустить Сатори самому?

Ты можешь. Satori имеет открытый исходный код и производит качественную продукцию. Но запустить его самостоятельно означает:

  • Установка и комплектация пользовательских шрифтов (Сатори не использует системные шрифты)
  • Настройка среды выполнения Node.js или функции Edge для рендеринга изображений
  • Написание шаблонов JSX-to-SVG и преобразование SVG в PNG с помощью resvg
  • Обработка ограничений памяти на бессерверных платформах при рендеринге больших изображений
  • Поддержание конвейера по мере развития API Satori.

Вызов API заменяет все это одним HTTP-запросом. Если ваши потребности в изображении OG простой (заголовок + описание + брендинг), подход API экономит часы настройки и текущее обслуживание.

FAQ

Каков размер сгенерированных изображений OG?
Каждое изображение имеет размер 1200x630 пикселей — стандартный размер изображения Open Graph, рекомендованный Facebook, Twitter/X, LinkedIn и Slack. На выходе получается файл PNG.
Нужен ли мне ключ API?
Нет. Уровень бесплатного пользования допускает 5 запросов в минуту без ключа API. Для конвейеров сборки или сайтов с высоким трафиком, которые генерируют изображения при каждом просмотре страницы, возьмите ключ со страницы документации API botoi, чтобы разблокировать более высокие ограничения скорости.
Могу ли я настроить шрифты, цвета или макет?
Параметр темы принимает значения «светлый» или «темный» для управления общей цветовой схемой. API автоматически обрабатывает типографику и макет в зависимости от длины заголовка и описания. Для полностью индивидуального дизайна сгенерируйте базовое изображение с помощью API и выполните его постобработку с использованием собственной логики наложения.
Насколько быстро генерируется изображение?
API работает на рабочих серверах Cloudflare на периферии. Большинство запросов возвращают готовый PNG менее чем за 500 мс. Если вы кэшируете результат (рекомендуется для статических сайтов), генерация происходит только один раз для каждой уникальной комбинации заголовка, описания и темы.
Что делает конечная точка /v1/url-metadata?
POST URL-адрес /v1/url-metadata, и API извлекает эту страницу, анализирует ее HTML и возвращает структурированные метаданные Open Graph: og:title, og:description, og:image, og:type и теги Twitter Card. Используйте его, чтобы просмотреть, как будет выглядеть любой URL-адрес при публикации в социальных сетях, или добавить метаданные в свои собственные предварительные просмотры ссылок.

Начните разработку с botoi

150+ API-эндпоинтов для поиска, обработки текста, генерации изображений и утилит для разработчиков. Бесплатный тариф, без банковской карты.