Bluesky Website Card Image Generator: Create the Image and Set Up the Preview
Create a thumbnail for Bluesky link previews, add the Open Graph metadata your page needs, and understand how clients build website cards.

A Bluesky website card image is the thumbnail shown alongside a shared link. It is only one part of the card: the webpage also needs metadata for its title, description, image, and URL. To make one, create and host a representative image, add Open Graph tags to the page’s HTML head, then make sure the Bluesky client posting the link can fetch the page and image.
There is no official universal pixel size or aspect ratio for Bluesky website-card images in the sources covered here. Design for legibility at thumbnail scale and check how the card appears in the client you care about. Do not confuse general image upload limits with a prescribed website-card size.
1. What a Bluesky website card contains
Bluesky documentation describes a website card as a rendered preview of a link. Its external embed contains the URL, title, description, and thumbnail blob. The webpage supplies metadata; the client that creates the post can read that metadata, fetch the image, upload the image bytes to Bluesky, and include the resulting blob in the post record. The thumbnail is therefore part of the post’s embed, rather than simply a live image reference that every viewer must fetch from your site.

Bluesky’s documentation summarizes the behavior this way: “On Bluesky, each client fetches and embeds this card metadata, including blob upload if needed.” See the official website card embed guide and its source example.
That has practical consequences: your page must be publicly reachable by the client, and the metadata needs to be available in the page response it reads. A card generator that only exports an image does not automatically configure your website’s metadata. Conversely, adding metadata does not create a suitable thumbnail for you.
2. Create an image that works as a thumbnail
Start with an image that represents the specific page: a product image for a product page, a chart or diagram for a technical article, or a deliberate editorial graphic for a blog post. Avoid putting essential details close to the edges. At small preview sizes, tiny text and fine lines are hard to read; treat the image as a visual cue rather than a place to repeat the full page title.
The Open Graph protocol permits image width and height metadata, but the reviewed Bluesky sources do not define a canonical website-card width, height, ratio, or crop behavior. A familiar size such as 1200 × 630 pixels may be a practical design choice for a general social image, but it is not a Bluesky requirement. Test your real card in the target client instead of assuming every client crops or scales it the same way.
Export a web-friendly image format your site can serve reliably, such as JPEG, PNG, or WebP where appropriate. Keep the file reasonably small so it loads promptly, but preserve enough detail for the intended composition. Do not assume the limit for regular image embeds is automatically the limit for every external-card workflow: the current image embed schema concerns images attached directly to a post.
You can create the artwork in an image editor or use a social graphic template and resize it for your chosen composition. For example, Adobe Express offers social graphic templates, and Canva offers editable social graphic templates. These are image-creation options, not verified Bluesky-specific card generators: you still need to publish the resulting image and add Open Graph tags to your page.
3. Add Open Graph metadata to the page
Put the tags in the document’s <head>. Use absolute, publicly fetchable URLs for og:url and og:image. The Open Graph protocol defines og:title, og:type, og:image, and og:url as its basic properties; og:description is optional but useful for a link preview. Image width, height, type, and alternative text can provide additional image information. The standard says that a page specifying og:image should also specify og:image:alt. See the Open Graph protocol.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Deploying a Small API | Example Docs</title>
<meta property="og:title" content="Deploying a Small API">
<meta property="og:type" content="article">
<meta property="og:url" content="https://example.com/guides/deploy-api">
<meta property="og:description" content="A practical guide to packaging and deploying a small API.">
<meta property="og:image" content="https://example.com/images/deploy-api-card.webp">
<meta property="og:image:alt" content="A server rack beside a deployment path diagram">
<meta property="og:image:type" content="image/webp">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
</head>
<body>
<h1>Deploying a Small API</h1>
</body>
</html>
The dimensions in this example describe the actual exported file; they do not declare a Bluesky-prescribed size. Set og:image:type to the image’s real media type. Keep the title and description accurate to the page, and write useful alt text that describes the image rather than repeating decorative copy.
Framework and CMS notes
In a static site, add the tags to the shared page template and fill values from that page’s data. In a server-rendered app, generate them in the server response for each route. In a CMS, use its social-sharing or metadata fields and confirm they render in the HTML head. A client-side component that inserts tags after page load may not help a client that reads only the initial HTML response.
Each distinct page should have a distinct canonical URL and suitable metadata. If the page changes its image, title, or description, update the rendered tags and verify the new HTML. Do not place multiple competing og:image values unless you intentionally understand how consumers choose between them; the simplest setup has one intended card image.
4. Check the image and metadata from outside your browser
A normal browser session can hide problems because you may be logged in, have cached assets, or see JavaScript-rendered content unavailable to a link-fetching client. Check the public URL and inspect the raw response. Confirm the image returns successfully without an authentication cookie and that it is an actual image rather than an HTML error page.
# Fetch the page response headers
curl -I https://example.com/guides/deploy-api
# Fetch the image headers
curl -I https://example.com/images/deploy-api-card.webp
# Inspect the page HTML for the Open Graph tags
curl -L https://example.com/guides/deploy-api
Look for a successful response, a suitable content type, and a valid TLS certificate. The image URL should not redirect into a login page or expire quickly. If your metadata is generated dynamically, inspect the response body from the command line to ensure the tags are already present.
Then create a new Bluesky post containing the URL in the client you are targeting and inspect the composed preview before publishing. Client behavior can differ, so verify the result in that client rather than treating a preview from another platform as proof.
5. How clients turn the page into an embed
- Read the page. The client obtains the linked page’s title, description, and image metadata.
- Fetch the image. The client retrieves the image bytes from the address in
og:image. - Upload a blob when needed. The official example uploads the bytes using
com.atproto.repo.uploadBlob. - Embed the metadata. The post record contains an external embed with the URL, text fields, and thumbnail blob.
- Render the card. A client displays that embed as the link preview.
Bluesky explains that storing the card content in the post record helps it display consistently and reduces repeated automated requests to the linked website, though it requires additional work from the client that creates the post. This is why a page owner should make its metadata available before someone shares the link.
Do not assume changing your website image rewrites an already-created post’s embedded thumbnail. The record contains the blob chosen when the client created that post. The reviewed official materials establish the embedded-blob workflow but do not document all client-specific update or refresh behavior; create a fresh test post when validating a changed image.
6. Direct image limits versus website-card guidance
Bluesky’s current app.bsky.embed.images lexicon allows up to four images in a regular image embed, with each image blob capped at 2,000,000 bytes and an alt field required. Those are rules for images attached to a post, not a specification for the ideal artwork dimensions or aspect ratio of an external website card. See the current image embed schema.
On April 7, 2026, AT Protocol developer Bryan Newbold announced a planned increase in general image limits from 1 MB to 2 MB and from 2000 × 2000 to 4000 × 4000 pixels. The current schema confirms the 2,000,000-byte image-embed maximum. The announcement’s pixel dimensions describe general client and CDN image limits, not a recommended website-card canvas. See the dated developer announcement.
Keep the two questions separate: “Will a directly attached image meet the image-embed schema?” and “Does this page expose a useful link-card image?” The schema can answer the first. It does not establish one universally optimal answer to the second.
7. Troubleshooting common card problems
| Symptom | Likely cause | What to check or fix |
|---|---|---|
| No image appears | og:image is absent, relative, private, or returns an error. |
Use an absolute HTTPS URL. Fetch it without browser cookies and check the status, redirects, and content type. |
| Wrong title or description | Tags are missing, stale, duplicated, or generated for a different route. | Inspect the response HTML for the exact page URL. Fix the template or CMS fields, then create a new test post. |
| Image works in your browser but not in the card | The browser is authenticated or has cached the asset; the client cannot access it. | Test in a private session and with curl. Remove login requirements, expiring signatures, or hotlink restrictions from the image URL. |
| Card shows old artwork | The client may have embedded an earlier image blob when the post was created. | Update the metadata and test using a newly composed post. Do not infer that an existing post will refresh its embed. |
| Tags are present only after JavaScript runs | The client may read the initial HTML without running the app’s scripts. | Render Open Graph tags in the server response or static HTML, then inspect that response directly. |
| Thumbnail crop looks different than expected | The available sources do not establish a universal crop mode across clients. | Keep important content away from edges and check the target client’s rendered preview. Adjust the composition if necessary. |
| Image is blank or malformed | The URL may serve an error document, unsupported bytes, or a broken export. | Download the asset and open it as an image. Verify its encoding and declared media type match. |
| Preview is missing behind a bot check | Your host may challenge automated requests used by the client to read the page. | Allow public access to the page metadata and image, or use a capture tool to inspect what an automated fetch can see. Avoid exposing private content. |
8. Performance, reliability, and cost considerations
Serve the card image from a stable public URL with a sensible file size. A large asset takes longer to fetch and can make post composition less reliable on constrained connections. If you regenerate artwork, keep the URL and metadata synchronized; versioned filenames can help ensure a changed image is not mistaken for an old cached asset by infrastructure outside your control.

Metadata is part of the page’s public interface. Keep tags in the server-rendered or static head, use absolute URLs, and avoid temporary image links. For pages behind authentication, consider whether sharing should expose the page’s title and image publicly before adding public metadata.
For local debugging, you can capture how the page renders and inspect the image visually. A browser screenshot is useful for seeing layout, but it does not prove that a Bluesky client can fetch the Open Graph tags or image: check the raw response separately. A screenshot API is a rendering aid, not a substitute for correct metadata.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One GET request captures a page as an image or PDF. Its cookie and consent handling removes 60+ known consent platforms, newsletter popups, and chat widgets before the screenshot; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. AI agents can use its MCP server tools to take screenshots, inspect page information, and capture PDFs.
This is useful for producing or checking a visual of a page, though it does not generate Open Graph metadata or guarantee how a Bluesky client will render a card. The API accepts other screenshot services’ parameter names too, which can make switching easier. See the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/guides/deploy-api -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com/guides/deploy-api"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com/guides/deploy-api'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const bytes = new Uint8Array(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', bytes));
ScreenshotNeo includes full-page capture with lazy images loaded, element capture, device presets and custom viewports, dark mode, custom CSS and JavaScript, selector or network-idle waits, request blocking, cookies and headers, resizing, caching, async jobs, bulk capture, and more. Free includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots. Sign up for 1,000 free screenshots a month, with no card required.
9. Frequently asked questions
Is a Bluesky website card image the same as an image attached to a post?
No. A website card is an external embed preview for a link. A regular image embed attaches one or more images directly to a post and has its own schema.
Does an image editor create the card automatically?
An editor can create the artwork. You still need to host it and configure the webpage metadata so a client can find the image and text.
Do I need to upload the thumbnail to Bluesky myself?
For the documented client workflow, the client fetches the image and uploads it as a blob when needed while constructing the post embed. A site owner setting up a page generally focuses on making the image and metadata reachable.
Will every Bluesky client show the exact same crop?
The consulted official sources do not promise a universal crop or identical presentation. Check the actual client and compose a legible image that tolerates scaling.
Does adding Open Graph metadata guarantee a card?
It gives clients the standard page information to use, but the client must be able to fetch the page and image and support website card embeds. Validate with the client and URL you plan to use.


