Skip to content

Social card image checklist

Open Graph images look simple, but social platforms can be strict, cached, and inconsistent. A valid image file and correct meta tags are not always enough. This guide covers the practical setup that works best when using ScreenshotOne to generate Open Graph social media images.

If you need a broader introduction to social cards and dynamic OG image generation, read Open Graph images.

Use the standard large-card dimensions:

viewport_width=1200
viewport_height=630
device_scale_factor=1

For the image format, prefer JPEG for broad compatibility and faster rendering:

format=jpeg
image_quality=85

PNG is supported by social platforms and ScreenshotOne PNGs are valid. But if your image does not need transparency, JPEG is usually a safer default for Open Graph images because it avoids alpha-channel edge cases, is smaller in many cases, and is fast for crawlers to download.

If you use PNG, make sure your page has a solid background. Do not rely on transparency for a social card.

Use a real image extension

Make sure the og:image URL ends with a normal image extension:

https://example.com/og/product-123.jpg

Avoid extensionless image URLs like:

https://example.com/api/screenshots/product-123

Even if an extensionless URL returns 200 OK with the correct Content-Type, some social crawlers may fail to recognize it reliably. Use .jpg, .jpeg, .png, .gif, or .webp in the URL path.

You can still serve the image from a dynamic route. For example:

https://example.com/api/screenshots/product-123.jpg

ScreenshotOne returns an image from an API URL such as https://api.screenshotone.com/take?.... That URL is valid, but it does not give you a clean filename like product-123.jpg.

To get a crawler-friendly filename, serve the ScreenshotOne result through your own URL.

Prefer storing the image when the share URL is important, public, or likely to be shared repeatedly. It removes timing issues and gives crawlers a normal static asset.

Use a proxy when you want less infrastructure and can rely on CDN caching. For a Cloudflare Worker proxy, cache the final image at the edge so X, Facebook, Telegram, WhatsApp, and iMessage do not trigger a fresh render every time.

Option 1: store the image

The most reliable setup is to generate the ScreenshotOne image, upload it to your storage, and use the stored image URL in your meta tags:

<meta property="og:image" content="https://cdn.example.com/og/product-123.jpg" />
<meta name="twitter:image" content="https://cdn.example.com/og/product-123.jpg" />

For example:

  1. Render the image with ScreenshotOne.
  2. Save the bytes to S3, R2, Google Cloud Storage, your CDN, or your own file storage. If you use S3-compatible storage, see the S3 integration.
  3. Store it under a filename with .jpg or .png.
  4. Return that stable URL from your share page.

In this setup, you usually do not need ScreenshotOne request caching for the public og:image URL because your own storage becomes the cache. You can still use ScreenshotOne caching while generating the image if you want repeated renders of the same template to be faster.

This approach is best when:

  1. The image must be stable once shared.
  2. You want maximum compatibility with social crawlers.
  3. You do not want crawlers to wait while a screenshot is being rendered.
  4. You want a CDN URL with a normal filename.

Option 2: proxy the image

You can also expose a URL with a filename and proxy the request to ScreenshotOne:

https://example.com/og/product-123.jpg

That route can call ScreenshotOne, stream the response back, and set the right headers:

Content-Type: image/jpeg
Cache-Control: public, max-age=2592000

For example, a Cloudflare Worker can receive /og/product-123.jpg, build the ScreenshotOne URL internally, fetch the image, and return it as image/jpeg.

This approach is best when:

  1. You want a simple .jpg URL without managing storage.
  2. You can tolerate the first crawler request doing the render.
  3. You set strong CDN caching at the proxy layer.

If you proxy on demand, make sure the first crawler request gets the final image, not a temporary fallback. If the crawler receives a placeholder first, it may cache that placeholder.

Use correct meta tags

At minimum, include Open Graph tags and the Twitter/X card tag:

<meta property="og:title" content="Your page title" />
<meta property="og:description" content="A short description of the page" />
<meta property="og:image" content="https://example.com/og/product-123.jpg" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:url" content="https://example.com/share/product-123" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Your page title" />
<meta name="twitter:description" content="A short description of the page" />
<meta name="twitter:image" content="https://example.com/og/product-123.jpg" />

Use absolute HTTPS URLs for both the page URL and the image URL.

Cache generated images

Social crawlers often request the page and image once, cache the result, and do not retry immediately when your image becomes available later.

If your share page generates the screenshot on demand, avoid this flow:

  1. The crawler requests the share page.
  2. Your application starts generating the ScreenshotOne image in the background.
  3. Your application returns a fallback image or no image while generation is still running.
  4. The crawler caches that first response.

Instead, use one of these patterns:

  1. Generate the image before publishing or sharing the URL.
  2. Return the final cached image from the first crawler request.
  3. Use a stable fallback image that is valid and acceptable if generation is still pending.

If you serve images directly from ScreenshotOne or from an on-demand proxy, enable caching:

cache=true
cache_ttl=2592000

2592000 seconds is 30 days. Use a cache TTL that matches how often your OG image changes.

If you store the generated image in your own storage and serve that stored file as og:image, your storage or CDN cache is usually the primary cache. In that case, ScreenshotOne caching is optional.

If you update an image and need a social platform to fetch it again, change the image URL:

https://example.com/og/product-123-v2.jpg

or:

https://example.com/og/product-123.jpg?v=2

Changing the page URL can also help, but changing the image URL is the most direct cache-busting signal.

Disable unnecessary blocking options

If you render your own HTML page for an OG image, you probably do not need ad, cookie banner, or chat blocking. Disable those options explicitly:

block_ads=false
block_cookie_banners=false
block_banners_by_heuristics=false
block_chats=false

This can make rendering faster and reduce the chance that useful page assets are blocked by mistake.

Serve the image plainly

The image URL should return the image bytes directly:

HTTP/1.1 200 OK
Content-Type: image/jpeg
Cache-Control: public, max-age=2592000

Avoid redirects if possible. If you must redirect, keep the chain short and make sure crawler user agents can follow it.

Also make sure the image URL does not require cookies, authorization headers, JavaScript, or browser-only session state.

Debugging checklist

When a social preview does not show the image, check these items first:

  1. The og:image and twitter:image URLs are absolute HTTPS URLs.
  2. The image URL ends in .jpg, .jpeg, .png, .gif, or .webp.
  3. The image URL returns 200 OK without authentication.
  4. The response has the correct Content-Type.
  5. The image is already generated before the crawler requests the page.
  6. The image is close to 1200x630.
  7. The image is small enough to download quickly.
  8. You are not relying on transparent PNG rendering.
  9. You changed the image URL after fixing a cached bad preview.

You can test with OpenGraph Debugger, Facebook’s sharing debugger, and X’s card validator. Validators are useful, but the real composer preview may still behave differently because each platform has its own caching and rendering behavior.

For X specifically, try pasting the URL into the composer and pressing Enter. In some cases, official validators report success while the live composer preview is delayed, cached, or rendered differently, especially on mobile.

Example ScreenshotOne URL

An example API request for generating a social share image:

https://api.screenshotone.com/take
?access_key=YOUR_ACCESS_KEY
&url=https://example.com/og-template/product-123
&viewport_width=1200
&viewport_height=630
&device_scale_factor=1
&format=jpeg
&image_quality=85
&cache=true
&cache_ttl=2592000
&block_ads=false
&block_cookie_banners=false
&block_banners_by_heuristics=false
&block_chats=false

Serve the resulting image from a URL with a .jpg extension:

<meta property="og:image" content="https://example.com/og/product-123.jpg" />
<meta name="twitter:image" content="https://example.com/og/product-123.jpg" />

That .jpg URL should be your storage URL or your proxy URL. It does not need to be the raw ScreenshotOne API URL.

Summary

For reliable Open Graph images with ScreenshotOne:

  1. Generate 1200x630 images.
  2. Prefer format=jpeg.
  3. Serve the result from your own .jpg URL, either from storage or a proxy.
  4. Use absolute HTTPS URLs in your meta tags.
  5. Make sure crawlers receive the final image on the first request.
  6. Enable caching at ScreenshotOne, your CDN, or your storage layer.
  7. Disable unnecessary blocking options for your own OG templates.
  8. Bust crawler caches by changing the image URL when needed.