What is the caption limit on each platform?
| Platform | Max characters | If text is too long |
|---|---|---|
| X | 280 | Split into a thread |
| Bluesky | 300 | Split into a thread |
| Threads | 500 | Split into a thread |
| 500 | Not rewritten | |
| Mastodon | 500 | Not rewritten |
| Nostr | 1,000 | Not rewritten |
| Discord | 2,000 | Truncated to 2,000 |
| 2,200 | Not rewritten | |
| TikTok | 2,200 | Not rewritten |
| 3,000 | Not rewritten | |
| Telegram | 4,096 (media captions 1,024) | Media captions truncated to 1,024 |
| YouTube | 5,000 description, 100 title | Not rewritten |
| 40,000 | Not rewritten | |
| Slack | 40,000 | Not rewritten |
| Tumblr | 50,000 | Not rewritten |
| 63,206 | Not rewritten | |
| Hashnode | 100,000 | Not rewritten |
| Dev.to | 400,000 | Not rewritten |
"Not rewritten" means Socifyr leaves your text as it is and the platform decides what to do with it. If the platform refuses the post, the API returns a plain-language reason such as "The caption is too long for LinkedIn. LinkedIn allows up to 3,000 characters. Shorten the caption and retry." Only the platforms marked thread or truncate change your text on the way out. The "Max characters" column comes from the shared constants Socifyr validates against.
What happens when my text is too long?
- Thread (X, Bluesky, Threads). Socifyr splits at paragraph boundaries where possible, then sentences, then words, so each part fits the limit and replies to the previous one. The result is one post with a link to the first part. See X posting limits and costs.
- Truncate (Discord, Telegram media captions). The text is cut at the limit with no warning. A long Discord message arrives clipped at 2,000 characters.
- Not rewritten (everything else). Socifyr sends your text unchanged. If the platform refuses it, that channel fails while the others succeed, so the overall status becomes
partial_failure. Fix the text and call retry.
How do I write one caption for many platforms?
Write for the tightest limit in the set. @socifyr/shared exports getEffectiveCaptionLimit, which returns the minimum caption length across the platforms you pick, so you can check length before sending.
import { getEffectiveCaptionLimit } from '@socifyr/shared'
getEffectiveCaptionLimit(['instagram', 'linkedin', 'threads']) // 500
getEffectiveCaptionLimit(['instagram', 'linkedin']) // 2200
getEffectiveCaptionLimit(['x', 'linkedin', 'bluesky']) // 280When one caption cannot serve everyone, override it per account with platformOptions and keep a shared default:
await socifyr.uploads.photos({
connections: ['instagram-mybrand', 'x-myhandle'],
medias: ['https://cdn.example.com/banner.jpg'],
text: 'Default caption for any account without an override',
platformOptions: {
'instagram-mybrand': { text: 'Long Instagram caption with context and hashtags #design' },
'x-myhandle': { text: 'Short version for X. Link in bio.' },
},
})More patterns in how to cross-post to multiple platforms with one API call.
Which limits are about the title or description rather than the caption?
YouTube has separate fields. The title is limited to 100 characters and the description to 5,000. Pinterest pin titles are capped at 100 characters in the platform options. For TikTok and Instagram video, the post text is the caption and the limit is 2,200. The Socifyr API accepts up to 25,000 characters in text per request, and the limit of each platform then applies on top of that.
Do emoji and links change the count?
Socifyr validates against the plain character count in its shared constants. How a platform counts emoji, mentions or shortened links is the platform's rule and can differ from a simple string length, so leave some headroom on tight limits such as X (280) and Bluesky (300). On X, remember that a link also changes the price of the post; see X posting costs.
How do I check length before I send?
import { getEffectiveCaptionLimit, type SupportedPlatform } from '@socifyr/shared'
function fits(text: string, platforms: SupportedPlatform[]): boolean {
const limit = getEffectiveCaptionLimit(platforms)
return limit === undefined || text.length <= limit
}
fits(caption, ['x', 'linkedin', 'threads']) // true only if it is 280 characters or fewerRun the check in the code that generates the caption. If you let an AI model write it, put the limit in the instruction and verify the result, because models routinely overshoot a character count. When it does not fit, either shorten and retry or split the targets into two posts with different text.
What mistakes come up most often?
- Writing for LinkedIn's 3,000 and then cross-posting to X, which splits it into a long thread nobody wanted.
- Assuming Discord will reject text that is too long. It truncates instead, so the cut is silent.
- Forgetting that Telegram media captions are 1,024, not the 4,096 of a text message.
- Counting only visible characters and ignoring link length on tight platforms.
- Putting everything in the caption when a first comment would carry the hashtags. The shared constants mark X, Bluesky, Instagram, LinkedIn, Facebook, Threads, Reddit and YouTube as supporting first comments.
Frequently asked questions
What is the Instagram caption limit?
What is the character limit for a LinkedIn post through the API?
What is the X character limit?
Which platform has the longest limit?
How do I find the limit for a set of platforms?
getEffectiveCaptionLimit(platforms) from @socifyr/shared. It returns the minimum across the platforms you pass.