Bluesky
Using hosted SimplePost? See connection requirements. The credential setup below is for your own SDK, local CLI, or self-hosted integration.
Bluesky supports two credential paths in SimplePost:
- App password — the simplest for personal or server-owned posting.
- OAuth tokens — better for user-facing apps and Scheduler-connected accounts.
Content support
Current hosted app and core source
| Capability | SimplePost support |
|---|---|
| Text / caption (characters) | 300 text |
| Media | 4 items max; 4 images max; 1 video max; No mixed images/video |
| Image size | 2 MB maximum |
| Video size | 300 MB maximum |
| Video duration | 600 seconds maximum |
- Up to 4 images or 1 MP4 video (300 MB, 10 minutes). Video uploads require a verified Bluesky email and available account quota.
- Links and hashtags are clickable. Resolvable @handle mentions are clickable; unavailable mentions remain plain text.
- Text posts can include a card for the first HTTP(S) link when metadata is available. Explicit images, video and quotes take priority; metadata failure keeps the text link.
These validation limits also match published SDK 1.5.0.
Provider permissions and quotas still apply. SimplePost storage can impose a lower upload limit. MB/GB use decimal bytes; MiB/GiB use binary bytes.
Video uploads require a verified Bluesky email and available account quota. Use MP4 (.mp4 or .m4v); SimplePost does not transcode MOV or WebM. OAuth and app-password connections both support video. Processing must finish before a post is created.
Links, hashtags and mentions
SimplePost creates clickable links and hashtags in posts and thread replies. An @handle mention links to the account when its handle resolves; unavailable or excess lookups leave the mention as plain text. Your original text is preserved, including emoji and non-Latin characters before a link.
Use SDK 1.5.0 or later for these features in a direct SDK or self-hosted integration. Earlier packages publish text without these rich-text facets. Hosted web, API, MCP and hosted-account CLI posts use the deployed SDK; see release scope.
Automatic link cards
A text post containing an HTTP(S) link can include a card for the first eligible link, with a title, description and optional thumbnail. Explicit images, video and quote posts take priority. Metadata failure leaves the clickable text link; thumbnail failure can leave a card without an image.
SimplePost fetches card metadata when publishing. The draft preview shows your text and explicit media and may not show the final card. Not every website permits metadata retrieval. Fetches use public network destinations, limited redirects, response sizes and deadlines.
For the hosted workflow, see schedule Bluesky posts and threads, or prepare a draft in the free Bluesky preview.
App password setup
- Open Bluesky settings.
- Create an app password.
- Store the app password with the Bluesky handle or DID.
This is the fastest setup for SDK, CLI, and the self-hosted REST server.
OAuth setup
Bluesky OAuth is decentralized and uses a public client metadata document instead of a traditional developer dashboard. For a local CLI OAuth account, host your own metadata document, set its URL as SIMPLE_POST_BLUESKY_CLIENT_ID, then run simplepost account add bluesky. See Bluesky OAuth app setup. For personal local posting, an app password is simpler.
OAuth refresh is DPoP-bound and tokens rotate — see token rotation.
Environment variables
BLUESKY_ACCESS_TOKEN=
BLUESKY_REFRESH_TOKEN=
BLUESKY_DID=
BLUESKY_PDS_URL=
Env-only setup activates when BLUESKY_ACCESS_TOKEN, BLUESKY_DID, and BLUESKY_PDS_URL are all set. BLUESKY_REFRESH_TOKEN is optional for short-lived posting.
For app-password posting, pass credentials directly through SDK options instead:
await post({
content: { text: "Hello Bluesky" },
platforms: ["bluesky"],
options: {
bluesky: {
credentials: {
identifier: "yourbrand.bsky.social",
appPassword: "xxxx-xxxx-xxxx-xxxx",
},
},
},
});
For OAuth tokens, DPoP keys are required. Scheduler stores DPoP keys automatically. If you use the SDK directly, pass the DPoP public and private JWKs in options.bluesky.credentials.
REST server account
Add one of these entries under accounts in the self-hosted REST server's accounts.json.
App password:
{
"id": "bsky-main",
"platform": "bluesky",
"credentials": {
"identifier": "yourbrand.bsky.social",
"appPassword": "xxxx-xxxx-xxxx-xxxx"
}
}
OAuth:
{
"id": "bsky-main",
"platform": "bluesky",
"username": "yourbrand.bsky.social",
"platformAccountId": "did:plc:...",
"credentials": {
"accessToken": "...",
"refreshToken": "...",
"did": "did:plc:...",
"pdsUrl": "https://bsky.social"
}
}