Platforms
Bluesky
Post text, images, video, link cards and quote posts to Bluesky, connected with an app password.
Overview
The bluesky platform posts to Bluesky with an app password (no OAuth app needed). You can post:
- Text posts with automatic link, mention and hashtag detection
- Up to 4 images, or 1 video
- A link preview card (automatic for the first link, or a URL you choose)
- Quote posts (alone or combined with images, video or a link card)
- Languages, extra hidden tags, content warnings, reply controls and quote controls
Connect the account
Bluesky uses app passwords instead of OAuth.
- In the Bluesky app, go to Settings → Privacy and security → App passwords and create one.
- Connect it in one of two ways:
- Dashboard: open Integrations, choose Bluesky, and enter your handle and the app password.
- API: call
POST /v1/accounts/bluesky.
curl -X POST https://social-publish-api.onrender.com/v1/accounts/bluesky \
-H "x-access-key: $RELAYCAST_API_KEY" \
-H "content-type: application/json" \
-d '{ "identifier": "yourname.bsky.social", "appPassword": "abcd-efgh-ijkl-mnop" }'The credentials are checked against Bluesky before they are saved, and stored encrypted. Connecting the same Bluesky account again updates its app password in place, so its account ID doesn't change.
Accounts are signed in through bsky.social. If you revoke the app password in Bluesky, the next publish fails and the account is marked reconnect_required.
Post types & media rules
| Rule | Limit |
|---|---|
| Text | 300 characters (graphemes) |
| Images | Up to 4, 2 MB each |
| Video | 1, up to 300 MB |
| Images and video | Can't be combined |
| Alt text | media[].altText is sent for images |
| Link card | Only when the post has no images or video; the page's thumbnail is used if it is under 1 MB |
| Extra tags | Up to 8, 64 characters each |
| Languages | Up to 3 BCP-47 codes (for example en, pt-BR) |
Hashtags, @mentions and links written in the text are detected and linked automatically.
Options
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
linkCard | boolean | No | true | Link preview card. When the post has no images or video, attach a preview card for the first link in the text (or the URL below). Fails quietly to a plain post if the page can't be read. |
linkUrl | string (URL) | No | Card URL. Defaults to the first link in the post text. Only when linkCard is true. | |
linkTitle | string | No | Card title. Overrides the page's og:title / linkCard is true. | |
linkDescription | string | No | Card description. Overrides the page's og:description / meta description. Only when linkCard is true. | |
tags | string[] | No | Extra tags. Up to 8 hashtags stored on the post but not shown in the text (searchable). Hashtags written in the text are detected automatically. | |
langs | string[] | No | Languages. Up to 3 BCP-47 language codes for the post text. Used for feeds and translation. | |
contentWarning | none \ | sexual \ | nudity \ | porn \ |
quoteUrl | string (URL) | No | Quote post. A Bluesky post to quote. Can be combined with images, video or a link card. | |
replyControl | everyone \ | nobody \ | limited | No |
replyAllow | string[] | No | [] | Allow replies from Only when replyControl is limited. |
disableQuotes | boolean | No | false | Disable quote posts. Prevents other people from quoting this post. |
quoteUrl accepts a https://bsky.app/profile/<handle>/post/<id> URL or an at:// post URI. With replyControl: "limited", pick at least one group in replyAllow. |
Examples
Post with a link card and reply limits
curl -X POST https://social-publish-api.onrender.com/v1/posts \
-H "x-access-key: $RELAYCAST_API_KEY" \
-H "content-type: application/json" \
-d '{
"content": "We wrote up how our scheduler works: https://example.com/blog/scheduler #engineering",
"targets": [{
"accountId": "7c6b5a49-3827-4e1d-8c0b-9a8f7e6d5c4b",
"options": {
"linkCard": true,
"langs": ["en"],
"replyControl": "limited",
"replyAllow": ["followers", "mentioned"],
"disableQuotes": false
}
}],
"publishNow": true
}'const res = await fetch("https://social-publish-api.onrender.com/v1/posts", {
method: "POST",
headers: {
"x-access-key": process.env.RELAYCAST_API_KEY!,
"content-type": "application/json",
},
body: JSON.stringify({
content: "We wrote up how our scheduler works: https://example.com/blog/scheduler #engineering",
targets: [
{
accountId: "7c6b5a49-3827-4e1d-8c0b-9a8f7e6d5c4b",
options: {
linkCard: true,
langs: ["en"],
replyControl: "limited",
replyAllow: ["followers", "mentioned"],
disableQuotes: false,
},
},
],
publishNow: true,
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://social-publish-api.onrender.com/v1/posts",
headers={"x-access-key": os.environ["RELAYCAST_API_KEY"]},
json={
"content": "We wrote up how our scheduler works: https://example.com/blog/scheduler #engineering",
"targets": [{
"accountId": "7c6b5a49-3827-4e1d-8c0b-9a8f7e6d5c4b",
"options": {
"linkCard": True,
"langs": ["en"],
"replyControl": "limited",
"replyAllow": ["followers", "mentioned"],
"disableQuotes": False,
},
}],
"publishNow": True,
},
)
data = res.json()["data"]Images with alt text and a quote
{
"content": "Before and after the redesign",
"media": [
{ "url": "https://cdn.example.com/before.jpg", "type": "image", "altText": "Old settings page" },
{ "url": "https://cdn.example.com/after.jpg", "type": "image", "altText": "New settings page" }
],
"targets": [{
"accountId": "7c6b5a49-3827-4e1d-8c0b-9a8f7e6d5c4b",
"options": {
"quoteUrl": "https://bsky.app/profile/example.bsky.social/post/3l7abcxyz2k2a",
"tags": ["design", "ux"]
}
}],
"scheduledFor": "2026-11-10T09:00:00Z"
}Analytics & comments
Analytics show likes, replies (comments), reposts + quotes (shares) and bookmarks (saves). Bluesky does not report views, impressions or clicks.
Replies and messaging are not supported for Bluesky.
Limitations & common errors
| Error | Cause |
|---|---|
invalid_credentials (connect) | Bluesky rejected the handle or app password. |
Bluesky allows 300 characters (this post has …) | Text is too long. |
Bluesky posts can have images or one video, not both | Mixed media. |
Bluesky allows up to 4 images | Too many images. |
Bluesky allows up to 8 tags / up to 3 languages | Too many tags or langs. |
Pick at least one group who can reply … | replyControl: "limited" with an empty replyAllow. |
| Target fails: image too large | Bluesky images are limited to 2 MB each. |
Account becomes reconnect_required | The app password was revoked or the account was deactivated. |
A link card that can't be built (the page can't be fetched or has no metadata) quietly falls back to a plain post.
This page is also available as Markdown.