Symfony
SymfonySymfony
Generate a unique OG image for every page, or any on-demand graphic, from a single Imejis template. The pattern below uses a Symfony controller action as a thin proxy: your API key stays on the server, and the browser (and social crawlers) only ever see your own URL.
Set two environment variables first: IMEJIS_API_KEY (from your dashboard) and IMEJIS_DESIGN_ID (any design's ID).
IMEJIS_API_KEY=your_api_key
IMEJIS_DESIGN_ID=your_design_id1 a controller that renders the image1. A controller that renders the image
This action takes a title query param, POSTs it to Imejis as a component.property override with the dma-api-key header, and returns the finished image bytes. Because the key is sent server-side, it never reaches the client.
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\HttpClient\HttpClientInterface;
class OgController extends AbstractController
{
#[Route('/og', name: 'og', methods: ['GET'])]
public function index(Request $request, HttpClientInterface $client): Response
{
$title = $request->query->get('title', 'Untitled');
$designId = $_ENV['IMEJIS_DESIGN_ID'];
$apiKey = $_ENV['IMEJIS_API_KEY'];
$upstream = $client->request(
'POST',
"https://render.imejis.io/v1/{$designId}",
[
'headers' => ['dma-api-key' => $apiKey],
'json' => ['headline.text' => $title],
]
);
$response = new Response($upstream->getContent());
$response->headers->set('Content-Type', 'image/jpeg');
// Renders are deterministic, so cache aggressively at the edge/CDN.
$response->headers->set(
'Cache-Control',
'public, immutable, no-transform, max-age=31536000'
);
return $response;
}
}2 point your template at it2. Point your template at it
Reference the route from your Twig template or meta tags, passing each page's real data. Social platforms fetch /og?title=… from your own domain, no key exposed.
{% set og_image = 'https://your-site.com/og?title=' ~ post.title|url_encode %}
<meta property="og:image" content="{{ og_image }}" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" content="{{ og_image }}" />Override any field. Each dynamic component exposes keys like headline.text, title.color, or image.image. Send only the ones you want to change. A design's overridable fields are listed in its Share / API panel.