Skip to content
Platforms

Bluesky Link Preview Not Showing? Causes and Fixes

By , Founder ·

Sources checked on October 12, 2026 · 20 sources

A post with the Bluesky mark whose link has no preview: under the link is an empty, dashed card with a question mark on its corner.

On Bluesky, the app that creates a post has to attach the link preview: Bluesky’s documentation describes no step that adds one from a URL in your text. Bluesky’s developer documentation, checked October 12, 2026, says “each client fetches and embeds this card metadata, including blob upload if needed”. So a post that shows a bare URL was created without a link card, because the tool does not build one, it could not read the page, or the post already carried an image or a video.

Bluesky’s docs call the preview a “website card embed”. This post calls it a link card. It is an embed inside the post record, one of the “external embeds (like link/webpage cards, which is the preview that shows up when you post a URL)” (Posts in-depth).

The client is whatever creates the post: the Bluesky app, a scheduler, an automation module or a script. That client has to fetch your page and put the card into the record when it creates the post. A post with a card looks like this:

Example from Bluesky's developer documentation, Posts in-depth, section Website card embeds
{
  "$type": "app.bsky.feed.post",
  "text": "post which embeds an external URL as a card",
  "createdAt": "2023-08-07T05:46:14.423045Z",
  "embed": {
    "$type": "app.bsky.embed.external",
    "external": {
      "uri": "https://bsky.app",
      "title": "Bluesky Social",
      "description": "See what's next.",
      "thumb": {
        "$type": "blob",
        "ref": {
          "$link": "bafkreiash5eihfku2jg4skhyh5kes7j5d5fd6xxloaytdywcvb3r3zrzhu"
        },
        "mimeType": "image/png",
        "size": 23527
      }
    }
  }
}

Bluesky documents two special cases: an “enhanced preview card” for articles with a Standard.site record, and an inline player for Bandcamp releases (App integrations). Whether either works on a post created without a card is not documented.

According to Bluesky’s schema for the embed, the embed has these fields:

Field Required? Limit stated by Bluesky
uri Yes Must be a URI
title Yes Length: not documented
description Yes Length: not documented
thumb, the image No An image of at most 1,000,000 bytes. Pixel size and aspect ratio: not documented
associatedRefs No A list of record references: “StrongRefs (uri+cid) of the Atmosphere records that backed this view”. Length: not documented

The list is ordered by what is cheapest to check first. It comes from Bluesky’s documentation, not from support cases.

# Cause How to check Fix What the sources say
1 The tool that created the post did not attach a card Paste the link into a new post in the Bluesky app. A preview there means the Bluesky app could read the page, so the cause is on the tool’s side: it attached no card (read the post record to confirm), or the page blocks the tool’s own fetcher (row 4). The record settles it: the composer’s behaviour is not documented Use a tool that builds the card, or build the embed yourself Each client embeds the card (Bluesky docs)
2 The post already has an image or a video Look at the post: media and no card Choose the card or the media. With media, keep the URL in the text as a clickable link A post has one embed field (post schema). Buffer’s API has the same rule (API guide)
3 The page has no title, description or image tags the tool can read Search the page source for og:title, og:description and og:image (how) Add the tags to the page’s <head> From Bluesky’s example code (Bluesky docs). What the Bluesky app reads: not documented
4 The page refuses the fetcher: a firewall, a bot rule, a login wall or an error status Open the URL in a private window: it must load without a login. Check server or CDN logs for blocked requests Allow the fetcher of the tool you post with. For a scheduler that builds the card, that is the scheduler’s own fetcher (Buffer names its bot), not Bluesky’s. For the Bluesky app, use the log check Documented for Buffer’s bot (help page, bot page). The Bluesky app’s fetcher: not documented
5 The image could not be used Open the og:image URL by itself: it should be an absolute, public URL that returns an image. Check the file size Use an absolute https:// URL. Keep the image under 1,000,000 bytes, or let the tool resize it thumb is optional and capped at 1,000,000 bytes (embed schema), so a card can exist without an image. Bluesky’s example only naively repairs a relative path (Bluesky docs), and Buffer’s API requires a public https:// URL for a thumbnail (API guide)

Check the post itself#

A post’s record is public: Bluesky’s schema for com.atproto.repo.getRecord says “Get a single record from a repository. Does not require auth.” The request takes a repo (the handle), a collection and an rkey. Bluesky’s cookbook script takes the rkey from the last part of a bsky.app post URL. On bsky.social, the host Bluesky lists as its “Entryway” (API Hosts and Auth), which forwards most requests to the account’s own server (PDS Entryway), the address has this shape:

https://bsky.social/xrpc/com.atproto.repo.getRecord?repo=<handle>&collection=app.bsky.feed.post&rkey=<last part of the post URL>

No embed in the JSON means no card was attached. An embed whose $type is app.bsky.embed.external is the card. Accounts that Bluesky does not host use their own server’s address.

A URL that is not clickable is a separate fault. A clickable link is a “facet” on the text, and the preview is an embed. Bluesky’s rich text docs say “Clients to Bluesky should produce facets using parsers”, so the tool has to add them. A URL sent without a link facet is plain text: the docs say this outright for mentions (“It will be rendered as text in the post instead of a link”, Posts in-depth) and describe links as the same kind of annotation.

In a script, use the SDK’s helper. According to Creating a post, the TypeScript example calls rt.detectFacets(client), the Python example builds links with TextBuilder, and “The Go SDK does not ship a high-level rich-text builder.” If you build facets by hand, the rich text docs say “Facet ranges are indexed using byte offsets into the UTF-8 encoding.”

How to check a page’s Open Graph tags#

Bluesky’s example code reads og:title, og:description and og:image (Posts in-depth). It is example code for a client: which tags the Bluesky app itself reads, and whether it falls back to Twitter card tags or the page title, is not documented. The Open Graph protocol requires og:title, og:type, og:image and og:url, and lists og:description as optional.

View the page’s source and search for og:, or run this from a terminal:

curl -sL https://example.com/your-page | grep -i 'og:'
  • Put the tags in the HTML the server sends: Bluesky’s example does one plain HTTP GET. Whether any fetcher runs JavaScript first is not documented.
  • The og:image value should be a full https:// URL that opens by itself in a private window.

Bluesky documents no preview checker: none appears in its developer docs, its User FAQ or its Support page, which gives an email address and no help articles. For Buffer users, Buffer’s troubleshooting page suggests “the Facebook Sharing Debugger or Buffer’s scraper debugging tool”. Those show what their own fetchers see, not what the Bluesky app sees.

How to fix it, by how you post#

In the Bluesky app#

How the app’s composer offers, adds or removes a card is not documented. If no preview shows there for a link, work through rows 3 to 5 of the checklist.

For row 4, add the link to a post in the app while watching your server or CDN logs, and allow the request that gets blocked at that moment. Bluesky documents no user agent to match in advance.

From a scheduler#

A scheduler is the client for the posts it creates, so find out whether it builds the card: search its documentation for “Bluesky” next to “link preview” or “link card”.

Buffer documents it today: its help center says “For Bluesky, link previews are fully customizable”, and its API guide lists Bluesky among the networks that support its linkAttachment field. The table on the same help page shows a dash under “Link preview” for Bluesky, so that page disagrees with itself. Buffer fetches your page with its own bot, and when a site blocks it, “Buffer will need to be explicitly allowed” (troubleshooting page). The bot page gives its user agent.

Make’s documentation for its Bluesky app, read on October 12, 2026, lists a “Create a post” module and says nothing about link cards or embeds: not documented.

From a script, an automation or an agent#

Build the embed yourself: fetch the page, read its tags, upload the image with com.atproto.repo.uploadBlob, and put an app.bsky.embed.external object in the post’s embed field. Bluesky’s docs give code in Python, TypeScript and Go (Posts in-depth, Creating a post). Add link facets too.

Bluesky’s cookbook has a script that does this, create_bsky_post.py (README), with an --embed-url option (script). It was not run for this post. Bluesky’s docs add: “For a real application, reach for one of the SDKs listed at atproto.com/sdks rather than writing the raw requests by hand.”

An AI agent that posts through a tool or an API is in the same position: the tool it calls has to attach the card. If your posts come from a feed, see auto-posting an RSS feed to Bluesky.

Planning posts ahead of time? See how far ahead each network lets you schedule.

Frequently asked questions#

Why do my links show as plain text on Bluesky when I post from a tool?#

The tool sent the URL without a link facet: see Links show as text on Bluesky.

The app and your tool are separate clients, and each has to attach its own card (Bluesky docs): see how to fix it, by how you post.

Does Bluesky use og:image, or Twitter card tags?#

Which tags the Bluesky app reads is not documented: see the tag check. Other tools decide for themselves: Buffer says its scraper checks Open Graph and Twitter Card image tags (troubleshooting page). Set the Open Graph tags.

Bluesky documents no user agent or IP range for the app’s fetcher: its developer docs, User FAQ and Support page name none. For a post written in the app, use the log check. A scheduler that builds the card fetches your page itself, so its fetcher is the one to allow. Buffer documents its bot’s user agent (bot page).

Can a Bluesky post have both an image and a link preview?#

No. A post has one embed field (post schema), so you choose the card or the media, as in row 2 of the checklist. A quote post can sit next to a card (record with media schema).

Sources 20

ShowHide

Each page was read on the date beside it. The quoted sentence is the one this post relies on.

  1. Bluesky developer docs: "Posts in-depth" bsky.network

    “On Bluesky, each client fetches and embeds this card metadata, including blob upload if needed. Embedding the card content in the record ensures that it appears consistently to everyone and reduces waves of automated traffic being sent to the referenced website, but it does require some extra work by the client. [...] Comments in the example code: parse out the "og:title" and "og:description" HTML meta tags [...] if there is an "og:image" HTML meta tag, fetch and upload that image [...] naively turn a "relative" URL (just a path) into a full URL, if needed”

    Checked

  2. Bluesky developer docs: "Creating a post" bsky.network

    “Use the RichText API to detect links and mentions. [...] The Go SDK does not ship a high-level rich-text builder.”

    Checked

  3. Bluesky developer docs: "Links, mentions, and rich text" bsky.network

    “Clients to Bluesky should produce facets using parsers.”

    Checked

  4. Bluesky lexicon schema: app.bsky.embed.external github.com

    “"required": ["uri", "title", "description"] [...] "thumb": { "type": "blob", "accept": ["image/*"], "maxSize": 1000000 }, "associatedRefs": { "type": "array", "items": { "type": "ref", "ref": "com.atproto.repo.strongRef" }, "description": "StrongRefs (uri+cid) of the Atmosphere records that backed this view." }”

    Checked

  5. Bluesky lexicon schema: app.bsky.feed.post github.com

    “"embed": { "type": "union", "refs": [ "app.bsky.embed.images", "app.bsky.embed.video", "app.bsky.embed.gallery", "app.bsky.embed.external", "app.bsky.embed.record", [...] ] }”

    Checked

  6. Bluesky lexicon schema: app.bsky.embed.recordWithMedia github.com

    “A representation of a record embedded in a Bluesky record (eg, a post), alongside other compatible embeds. For example, a quote post and image, or a quote post and external URL card.”

    Checked

  7. Bluesky lexicon schema: com.atproto.repo.getRecord github.com

    “Get a single record from a repository. Does not require auth.”

    Checked

  8. Bluesky developer docs: "API Hosts and Auth", the table "Bluesky Services" bsky.network

    “This table summarizes the hostnames for Bluesky-operated atproto network services. [...] Table row: Entryway | https://bsky.social | n/a”

    Checked

  9. Bluesky cookbook: python-bsky-post, README github.com

    “Script demonstrating how to create posts using the Bluesky API, covering most of the features and embed options.”

    Checked

  10. Bluesky cookbook: create_bsky_post.py github.com

    “elif uri.startswith("https://bsky.app/"): repo, collection, rkey = uri.split("/")[4:7] [...] parser.add_argument("--embed-url")”

    Checked

  11. The Open Graph protocol ogp.me

    “The four required properties for every page are: og:title [...] og:type [...] og:image [...] og:url [...] The following properties are optional for any object and are generally recommended: [...] og:description - A one to two sentence description of your object.”

    Checked

  12. Buffer Help Center: "Attaching images, videos, and other media to your posts" support.buffer.com

    “Buffer fetches the information from the website using Buffer's Link Preview Bot. [...] For Bluesky, link previews are fully customizable [...]”

    Checked

  13. Buffer API guide: "Hosting Media" developers.buffer.com

    “A good media URL is: Public - loads without authentication [...] HTTPS - served over https:// [...] A link card is not an asset. To attach one, use metadata.{service}.linkAttachment, which is supported on Bluesky, Facebook, LinkedIn, Substack, and Threads: [...] The thumbnail.url is fetched by Buffer the same way asset URLs are, so it has to meet every point in the list above. [...] linkAttachment is mutually exclusive with a non-empty assets array. Passing both is rejected, so a post is either a link card or a media post, never both. [...] A thumbnail that can't be fetched fails the whole mutation.”

    Checked

  14. Buffer Help Center: "Troubleshooting issues with suggested media and link details" support.buffer.com

    “Open Graph images first: The scraper checks for Open Graph tags (like og:image, og:image:secure_url, og:image:url) and Twitter Card images (twitter:image, twitter:image:src) in the HTML. [...] To check what metadata is available for your link, we suggest using the Facebook Sharing Debugger or Buffer's scraper debugging tool. [...] In some instances, Buffer's scraper can be prevented from accessing the information for the site to generate a link attachment. This can be due to the site's security configurations or the robots.txt. In both instances, Buffer will need to be explicitly allowed.”

    Checked

  15. Buffer: Buffer Link Preview Bot scraper.buffer.com

    “Identifies itself clearly as BufferLinkPreviewBot [...] Honors robots.txt directives”

    Checked

  16. Bluesky: "Bluesky User FAQ" (the page says nothing about link previews) bsky.social

    “Welcome to the Bluesky app! This is a user guide that answers some common questions.”

    Checked

  17. Bluesky: "Support" (the page says nothing about link previews) bsky.social

    “If you need help, email us at support@bsky.app with a description of your issue and information about how we can help you.”

    Checked

  18. Make Apps Documentation: "Bluesky" apps.make.com

    “With the Bluesky app in Make, you can manage the users, posts, monitor the messages, media, likes, and lists in your Bluesky account. [...] Listed under Posts: Create a post”

    Checked

  19. Bluesky developer docs: "PDS Entryway" bsky.network

    “The Entryway also acts as a single interface to the accounts Bluesky hosts. Most requests that can be sent to a PDS on behalf of a user can be sent to the Entryway instead, and it forwards them to the account's actual PDS.”

    Checked

  20. Bluesky developer docs: "App integrations" bsky.network

    “When someone posts a link to an article that has a corresponding site.standard.document record, Bluesky resolves that record and renders an enhanced preview card with the publication name, author, and a Subscribe button that writes a Standard.site subscription on the reader's behalf. [...] Bandcamp integration is a one-off, not a standard: links to Bandcamp releases render as an inline player embed in the post rather than a plain link card.”

    Checked

Get your weekends back. Let AI handle your social.

Join the waitlist and lock in 30% off for life.

  • Founding price for life
  • No credit card
  • Unsubscribe anytime