How to Use CaptureKit to Generate Open Graph Social Preview Images
Build a branded HTML card, capture it with CaptureKit, publish the image, and connect it to your page with Open Graph metadata.
To generate an Open Graph social preview image with CaptureKit, first render the card you want as a webpage, then ask CaptureKit to capture that page and publish the returned image at a public URL. Add that final URL to the page’s og:image metadata. CaptureKit captures a rendered webpage; it does not take arbitrary title and description fields and design a card for you. [CaptureKit API reference] [CaptureKit Open Graph use case]
This guide covers a backend-driven workflow, runnable API examples, the Open Graph tags to publish, rendering and hosting decisions, troubleshooting, and a ScreenshotNeo alternative.
1. Understand the workflow
- Create an HTML template that lays out the title, excerpt, branding, and any artwork for a social card.
- Make that template available at a URL CaptureKit can reach. It can be a route generated for each article or a temporary page created by a publishing job.
- Call CaptureKit’s
GET /v1/captureendpoint from your backend, passing the template URL and the desired output settings. Authenticate with thex-api-keyheader. - Save the returned image or use the documented optional S3-compatible storage settings. Publish it at a URL social crawlers can fetch without authentication.
- Set that public image URL in the destination page’s Open Graph metadata.
- Run the job when the content is published or updated, and store the resulting image URL with the content record.
Keep generation and metadata publication connected: the capture creates an image, while the page being shared advertises where that image lives. The Open Graph protocol requires og:title, og:type, og:image, and og:url as its basic properties. [Open Graph protocol]
2. Build the card page
Design a page specifically for the target canvas. Include only information that belongs on the card, such as a title, a short excerpt, author or category, brand mark, and a background or featured visual. Use CSS to set a fixed layout and ensure that long titles wrap cleanly. CaptureKit’s use-case guide recommends HTML templates with dynamic content. [CaptureKit Open Graph use case]
A simple template might be served at https://example.com/social-card/my-article. It should render the final card directly, rather than relying on a user to open a browser and interact with it. The capture service must be able to request the URL. Avoid embedding secrets or private content in the URL or rendered page, because the capture service will fetch it.
Choose a canvas and format
The CaptureKit reference documents a default viewport of 1280 by 1024 pixels and a default scale factor of 1. Set the width and height explicitly so the capture matches your card’s CSS. The example below uses 1200 by 630 pixels as an implementation choice; the reviewed sources do not prescribe one universal size for every social platform. Check the needs of the platforms where you share the page. [CaptureKit API reference] [CaptureKit Open Graph use case]
| Setting | When to consider it |
|---|---|
format |
Choose PNG, JPEG/JPG, WebP, or PDF as supported by the API. PNG is the documented default; use an image format suitable for the final artwork and consumers. |
viewport_width, viewport_height |
Set to the dimensions used by your template. Explicit dimensions prevent the 1280 by 1024 default from unexpectedly cropping or spacing your card. |
scale_factor |
Adjust output scale when you need a different pixel density; the documented default is 1. |
image_quality |
Set quality for JPEG or WebP when balancing visual fidelity and file size. |
delay, wait_until, wait_for_selector |
Use rendering readiness controls when assets or client-side content need time to appear. Pick a condition appropriate to the page instead of adding an arbitrary long delay. |
| Cache controls | Use them if they fit your update workflow. Ensure a changed title or design can produce a fresh card rather than reusing stale output. |
These controls are documented by CaptureKit, but behavior can depend on the page and its rendering. Verify the resulting file and layout after changing settings. [CaptureKit API reference]
3. Capture the page with CaptureKit
Keep the API key in a server-side environment variable or secret store. Do not place it in browser JavaScript or a mobile app: CaptureKit warns that client-side requests expose the key. [CaptureKit security guidance]
cURL
curl --get 'https://api.capturekit.dev/v1/capture' \
--header "x-api-key: ${CAPTUREKIT_API_KEY}" \
--data-urlencode 'url=https://example.com/social-card/my-article' \
--data-urlencode 'format=png' \
--data-urlencode 'viewport_width=1200' \
--data-urlencode 'viewport_height=630' \
--output 'my-article.png'
Set CAPTUREKIT_API_KEY in the shell or trusted job environment before running the command. The URL and dimensions are examples; replace them with your reachable template route and chosen canvas.
Python
import os
import requests
api_key = os.environ["CAPTUREKIT_API_KEY"]
params = {
"url": "https://example.com/social-card/my-article",
"format": "png",
"viewport_width": 1200,
"viewport_height": 630,
}
response = requests.get(
"https://api.capturekit.dev/v1/capture",
headers={"x-api-key": api_key},
params=params,
timeout=90,
)
response.raise_for_status()
with open("my-article.png", "wb") as image_file:
image_file.write(response.content)
Install the dependency with python -m pip install requests. The request uses a timeout and raises an error for unsuccessful HTTP responses before writing the response body.
Node.js
const apiKey = process.env.CAPTUREKIT_API_KEY;
if (!apiKey) throw new Error("Set CAPTUREKIT_API_KEY first");
const params = new URLSearchParams({
url: "https://example.com/social-card/my-article",
format: "png",
viewport_width: "1200",
viewport_height: "630",
});
const response = await fetch(
`https://api.capturekit.dev/v1/capture?${params}`,
{
headers: { "x-api-key": apiKey },
signal: AbortSignal.timeout(90_000),
},
);
if (!response.ok) {
throw new Error(`CaptureKit returned HTTP ${response.status}: ${await response.text()}`);
}
const image = Buffer.from(await response.arrayBuffer());
await import("node:fs/promises").then(({ writeFile }) =>
writeFile("my-article.png", image),
);
This example uses the built-in fetch API and top-level await in an ES module. Keep the key in the server environment and do not ship this code to a browser bundle.
Authentication and request details
The current endpoint reference specifies the API key in the x-api-key request header, the page URL as a required input, and one credit per capture call. Follow that reference rather than copying older migration examples that show a query parameter. Encode query values with your HTTP client, as the examples do. [CaptureKit API reference] [CaptureKit migration announcement]
Supported outputs listed in the reference include PNG, JPEG/JPG, WebP, and PDF. For a social image, request an image format and ensure your stored file and public URL use a matching content type and extension. JPEG or WebP quality is configurable through image_quality. [CaptureKit API reference] [CaptureKit storage options]
4. Store and publish the image
The capture response contains the generated asset. Save it in your own storage or configure the documented optional S3-compatible storage settings. Then serve it at a stable, public URL, for example https://cdn.example.com/og/my-article.png. Social platforms need to fetch the image from the URL in the page metadata; avoid requiring an interactive login or private authorization for that asset. The reviewed CaptureKit documentation describes storage options, but does not specify every downstream crawler’s requirements. [CaptureKit storage options] [Open Graph protocol]
For a publishing pipeline, save the final image URL alongside the content record. Regenerate the asset when the card’s title, design, or featured image changes. If you use caching, make sure your cache policy allows the updated card to appear when the underlying content changes.
5. Add Open Graph metadata to the destination page
Put the tags in the shared page’s document head. Replace the example values with the canonical page URL and the final publicly reachable image URL.
<meta property="og:title" content="A useful article title">
<meta property="og:type" content="article">
<meta property="og:url" content="https://example.com/articles/my-article">
<meta property="og:image" content="https://cdn.example.com/og/my-article.png">
<meta property="og:image:alt" content="A branded preview card for the article">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:type" content="image/png">
The Open Graph protocol identifies the first four properties as required basic metadata and defines image properties for dimensions, MIME type, secure URL, and alternative text. Add image dimensions and type when they are known, and write concise, useful alternative text. [Open Graph protocol]
6. Automate generation after publishing
Trigger the capture when a post, product, event, news item, or landing page becomes available. A typical job is:
- Render or update the social-card route from the content record.
- Request the capture from a server-side worker.
- Save and publish the returned image.
- Update the destination page’s
og:imageto the final image URL. - Record the job outcome and image URL so retries do not create unnecessary duplicate work.
CaptureKit’s use-case material describes automatic social image generation for new content and lists blogs, ecommerce products, events, news articles, and landing pages as applications. It also mentions Zapier and Make integrations; verify the specific integration path you plan to use before depending on it. [CaptureKit Open Graph use case] [CaptureKit integrations]
7. Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| Authentication fails | The key is missing, invalid, or sent in the wrong place. | Send the key as x-api-key in the header and verify the secret in the server environment. Do not use an old query-parameter example without confirming it matches the current endpoint reference. |
| The capture is blank or incomplete | The template route is inaccessible to the capture service, or content and assets have not finished rendering. | Check that the route is reachable without a browser session or private network access. Use a suitable documented delay, wait_until, or wait_for_selector setting when rendering needs readiness time. |
| The image is cropped or laid out incorrectly | The API default viewport is 1280 by 1024, or the page’s CSS does not match the intended canvas. | Set viewport width and height explicitly, then tune the template’s fixed layout and inspect long-title wrapping. |
| Text, fonts, or images are missing | External assets may not be available to the renderer or may load after capture. | Confirm asset URLs are reachable from the rendered page and select an appropriate readiness condition. The docs expose waits, but do not guarantee identical behavior for every framework or asset. |
| The output looks soft or is larger than needed | The chosen scale, format, or quality does not fit the artwork and delivery requirements. | Review scale_factor; use image_quality for JPEG/WebP where appropriate, and compare the saved output at its intended display size. |
| The social preview shows an old image | The destination page may still emit an old image URL, or a social consumer may have cached prior metadata or image content. | Inspect the page’s current og:image and fetch that URL directly. Publish a new versioned image URL when replacing an asset. Platform cache durations are not specified in the reviewed sources, so do not assume a refresh is immediate. |
| The capture works locally but not in production | The template URL may depend on local access, session cookies, or environment-specific assets. | Test the production route from an unauthenticated context and avoid exposing sensitive data in the rendered page or URL. |
CaptureKit documents /v1/usage as a way to confirm authentication and usage, and its dashboard provides logs. Use these when diagnosing request or credit questions. [CaptureKit usage documentation] [CaptureKit logs documentation]
8. Reliability, performance, and cost
- Credits: the endpoint reference lists one credit per capture call. The pricing page reviewed for this guide lists 100 free credits, then plans at $7/month for 1,000 credits, $29/month for 10,000, and $89/month for 50,000. Pricing can change, so confirm the current terms before publishing or budgeting. [CaptureKit API reference] [CaptureKit pricing]
- Retries: treat transient failures as job failures to retry with a limit and backoff in your own worker. Store completion state and the generated URL so a repeated publish event does not blindly regenerate a card. The reviewed docs do not establish a specific retry or idempotency guarantee.
- Rendering time: rendering readiness settings affect how long a capture waits. Prefer a meaningful selector or readiness condition for a dynamic template over an unnecessarily long fixed delay, and keep a request timeout in your client.
- Cache freshness: reuse a generated card while its content and design remain unchanged. Regenerate on relevant edits, and use versioned public image URLs if consumers may retain an older asset.
- Format and delivery: PNG is the documented default; JPEG/WebP quality can be adjusted. Select based on the artwork and delivery constraints, then verify the returned file and public response.
9. Or skip the browser setup
If you want a one-call screenshot API instead of maintaining a page-capture integration, ScreenshotNeo accepts a URL and returns an image or PDF. Build and host the social-card HTML page as described above, then call its API with that page URL. See the ScreenshotNeo API documentation for options.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/social-card/my-article -o shot.webp
Python
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://example.com/social-card/my-article"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com/social-card/my-article' }); const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo removes cookie banners, popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for free.
10. Frequently asked questions
Does CaptureKit create the card from a title and description?
No. The documented endpoint captures a webpage URL. Render the design and dynamic content in HTML first, then capture that page. [CaptureKit API reference]
Can I generate an image without making it public?
You can save the returned asset in your own storage, but the image URL advertised to social platforms needs to be fetchable by their crawlers. Do not put private material in a page or image URL sent to a capture service or social consumer.
Is 1200 by 630 the required size?
No. It is the example canvas used in this guide. CaptureKit supports viewport dimensions, while its use-case guidance says to optimize for the target platforms; it does not prescribe one universal size. [CaptureKit API reference] [CaptureKit Open Graph use case]
Will changing the image URL immediately refresh every social preview?
Not necessarily. The page must emit the intended metadata and the image URL must serve the intended file, but platform-specific caching and refresh timing are outside the reviewed documentation.
How can I confirm authentication and usage?
CaptureKit documents a /v1/usage endpoint and dashboard logs for checking usage and diagnosing requests. [CaptureKit usage documentation]


