The symptom: a URL that is just gray text
You post a link on Bluesky and instead of a clickable, highlighted URL you get plain, unclickable text. People cannot tap it. This trips up users posting through certain tools, automation platforms, and anyone calling the API directly. The good news: it is not a bug in your account or a Bluesky outage. It is a design choice, and once you understand it, the fix is straightforward.
Why Bluesky does not auto-link URLs
Most platforms scan your text and turn anything that looks like a URL into a link automatically. Bluesky deliberately does not. Instead it uses rich text facets: a separate list of annotations that say which byte range of the text is a link and where it points. The post text stays plain, and the facets describe what is special about parts of it. Bluesky's developers chose this because it is more precise and avoids guessing wrong, but it means links only work if facets are attached.
So when a link is not clickable, the post simply has no facet pointing at it. The text is there; the annotation that makes it a link is missing.
If you are posting in the official app
Good news: the official Bluesky app and website build facets for you automatically. Type or paste a full URL including the https prefix and the app detects it and makes it clickable. If a link is not working in the official app, the usual culprits are a missing https prefix, or pasting a URL that has been visually shortened or wrapped so the app cannot parse it cleanly. Paste the full, raw URL and it should light up.
If you are using a third-party tool
This is where most broken links come from. Some scheduling tools, integrations, and no-code platforms send only the post text and forget to generate the facets array. The post publishes, the URL appears, but it is dead. If a tool consistently produces unclickable links, it is not building facets correctly, and that is a sign the tool was not designed Bluesky-first. A native Bluesky scheduler should make every link clickable without you thinking about it.
If you are calling the API yourself
Calling createRecord with just text will never produce a clickable link. You must include a facets array. The critical detail that breaks most first attempts: facets index by UTF-8 byte offsets, not character positions. byteStart and byteEnd must be byte indexes into the UTF-8 encoding of your string. Put an emoji before your link and naive character counting will be off by several bytes, sending the link to the wrong place.
- Do not hand-calculate byte offsets. Use a library: the RichText helper in @atproto/api (detectFacets) for TypeScript, or equivalent helpers in the Python, Go, and Dart SDKs.
- These libraries walk the string in UTF-8 and emit correct facets for links, mentions, and tags in one pass.
- Remember the full URL counts toward the 300-character limit since Bluesky does not shorten links.
A quick mental model
Think of the text as the paint and facets as the labels saying which parts are special. The official app paints and labels for you. Good third-party tools do too. Bad tools paint but forget to label, which is why your link is just gray text. If you are coding, you are the labeler, so use a library so the byte math is right.
The shortcut
If you would rather never think about facets again, use a tool that is Bluesky-native by design. ONYX builds clickable link facets automatically for every scheduled post, alongside alt text and real thread chaining, for a flat $7/month with a free tier. Links that just work, without the byte arithmetic.