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.
Recommended image settings
Use the standard large-card dimensions:
viewport_width=1200viewport_height=630device_scale_factor=1For the image format, prefer JPEG for broad compatibility and faster rendering:
format=jpegimage_quality=85PNG 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.jpgAvoid extensionless image URLs like:
https://example.com/api/screenshots/product-123Even 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.jpgScreenshotOne 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:
- Render the image with ScreenshotOne.
- 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.
- Store it under a filename with
.jpgor.png. - 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:
- The image must be stable once shared.
- You want maximum compatibility with social crawlers.
- You do not want crawlers to wait while a screenshot is being rendered.
- 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.jpgThat route can call ScreenshotOne, stream the response back, and set the right headers:
Content-Type: image/jpegCache-Control: public, max-age=2592000For 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:
- You want a simple
.jpgURL without managing storage. - You can tolerate the first crawler request doing the render.
- 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:
- The crawler requests the share page.
- Your application starts generating the ScreenshotOne image in the background.
- Your application returns a fallback image or no image while generation is still running.
- The crawler caches that first response.
Instead, use one of these patterns:
- Generate the image before publishing or sharing the URL.
- Return the final cached image from the first crawler request.
- 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=truecache_ttl=25920002592000 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.jpgor:
https://example.com/og/product-123.jpg?v=2Changing 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=falseblock_cookie_banners=falseblock_banners_by_heuristics=falseblock_chats=falseThis 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 OKContent-Type: image/jpegCache-Control: public, max-age=2592000Avoid 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:
- The
og:imageandtwitter:imageURLs are absolute HTTPS URLs. - The image URL ends in
.jpg,.jpeg,.png,.gif, or.webp. - The image URL returns
200 OKwithout authentication. - The response has the correct
Content-Type. - The image is already generated before the crawler requests the page.
- The image is close to
1200x630. - The image is small enough to download quickly.
- You are not relying on transparent PNG rendering.
- 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=falseServe 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:
- Generate
1200x630images. - Prefer
format=jpeg. - Serve the result from your own
.jpgURL, either from storage or a proxy. - Use absolute HTTPS URLs in your meta tags.
- Make sure crawlers receive the final image on the first request.
- Enable caching at ScreenshotOne, your CDN, or your storage layer.
- Disable unnecessary blocking options for your own OG templates.
- Bust crawler caches by changing the image URL when needed.