---
title: "Spring Boot"
description: "Generate dynamic OG images and on-demand graphics in Spring Boot with the Imejis.io API. A secure @RestController proxy that keeps your API key server-side and returns a cached image."
url: "https://www.imejis.io/apis/springboot"
published: "2026-07-27"
---

# Spring Boot

## Spring Boot

Generate a unique OG image for every page, or any on-demand graphic, from a single Imejis template. The pattern below uses a Spring `@RestController` 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).

```bash title=".env / application environment"
IMEJIS_API_KEY=your_api_key
IMEJIS_DESIGN_ID=your_design_id
```

### 1. A controller that renders the image

This controller 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.

```java showLineNumbers title="src/main/java/com/example/og/OgController.java"
package com.example.og;

import java.util.Map;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestClient;

@RestController
public class OgController {

    private final RestClient client = RestClient.create();

    @GetMapping("/og")
    public ResponseEntity<byte[]> og(
            @RequestParam(defaultValue = "Untitled") String title) {

        String designId = System.getenv("IMEJIS_DESIGN_ID");
        String apiKey = System.getenv("IMEJIS_API_KEY");

        byte[] image = client.post()
            .uri("https://render.imejis.io/v1/" + designId)
            .header("dma-api-key", apiKey)
            .contentType(MediaType.APPLICATION_JSON)
            .body(Map.of("headline.text", title))
            .retrieve()
            .body(byte[].class);

        return ResponseEntity.ok()
            .contentType(MediaType.IMAGE_JPEG)
            // Renders are deterministic, so cache aggressively at the edge/CDN.
            .header("Cache-Control",
                "public, immutable, no-transform, max-age=31536000")
            .body(image);
    }
}
```

### 2. Point your template at it

Reference the controller from your view or meta tags, passing each page's real data. Social platforms fetch `/og?title=…` from your own domain, no key exposed.

```html showLineNumbers title="src/main/resources/templates/post.html"
<meta
  property="og:image"
  th:attr="content=|https://your-site.com/og?title=${#uris.escapeQueryParam(post.title)}|"
/>
<meta name="twitter:card" content="summary_large_image" />
<meta
  name="twitter:image"
  th:attr="content=|https://your-site.com/og?title=${#uris.escapeQueryParam(post.title)}|"
/>
```

**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.
