Skip to content

Writing and Scheduling Posts

A post is written once and sent to one or more channels.

Field Notes
Text Required. Up to 63,206 characters stored; each network has its own, lower limit.
Link URL Optional. Must be an absolute https:// URL with a host, up to 2,048 characters (link.https_required).
Link title Optional, up to 200 characters. Required for LinkedIn when there is a link.
Link description Optional, up to 500 characters.
Link image Optional. The card’s image, read from the page (an absolute https:// URL). Sent with the card where the network shows one.
Image Optional. An item from the Umbraco Media library (media.unknown if the key isn’t a media item), with its framing: a focal point and each network’s own crop. Required for Instagram.
Image alt text Optional, up to 1,000 characters. Describes the image for screen readers.
Channels At least one (channel.none). Each can have its own text.

Text and links are sent exactly as written. Text that looks like an Automate binding (${ … }) is sent as plain text, never evaluated.

You don’t fill in a link separately: the first link in the text is the post’s link. Change it to a different link and the card starts again, with no title or description.

When a chosen network shows link cards, the composer reads the card from the page the link points to: its title, description and image. Open Graph tags come first (og:title, og:description, og:image), then Twitter’s, then the page’s own <title> and description; an image is kept only as an absolute https URL. It fills only what you haven’t written, and Edit changes the title and description. How each network shows the link is in Network limits:

  • LinkedIn and Facebook show the card the post sends.
  • Bluesky shows the card the post sends, with the page’s image.
  • Mastodon and X read the page themselves and build their own card.
  • Instagram doesn’t get the link.

A post shows its image or its link card, not both: choosing an image replaces the card on every network.

To read cards from somewhere else, replace ILinkPreviewService (see Replacing services).

Add an image opens the Media library. Once it is chosen:

  • Alt text describes it for screen readers. It is sent to every network that takes it (see Network limits).
  • Click the image to open Umbraco’s crop editor. Set the focal point, the part of the image that matters, and adjust any network’s crop. There is one crop per chosen network, in the shape that network is sent:
Network Sent as
X, Bluesky, Mastodon 1200 × 675
LinkedIn 1200 × 627
Facebook 1200 × 630
Instagram 1080 × 1350, always as a JPEG

A network with its own crop gets that crop. The others are cut to their shape around the focal point (the centre without one). The previews show each network’s cut, made by the site’s image processor, exactly as it will be sent. Files the image processor can’t handle, such as SVG, are sent as they are.

Any channel can have its own text instead of the post’s main text, for example a shorter version for X. A channel without its own text uses the main text. Each channel’s text is checked against its own network’s limit.

The link, image and alt text belong to the whole post. How each network uses them is in Network limits.

Choice What happens Permission
Draft Saved, not scheduled. It doesn’t go out until it is scheduled. Write
Add to queue Takes the next free slot in the posting schedule. Refused with schedule.no_free_slot if there is none in the next 28 days. Write + Schedule
Specific time Goes out at that time (UTC). A time in the past is refused (schedule.past). Write + Schedule
Publish now Saved as due now: it goes out at the next check (every 30 seconds by default). Write + Schedule

In the composer these are Umbraco workspace actions in the footer bar: Save draft; Add to queue, with Schedule for a time… and Publish now in its menu; or Schedule, keeping the post’s time, when it has one. Someone without Schedule gets Save draft only.

A post only goes out where publishing is switched on. Elsewhere it waits.

In the composer, a post without text, or a Specific time without a time, is marked on the field the way Umbraco marks any required field, and nothing is sent.

When a post is saved, Social checks it against every channel it goes to and refuses it, with every problem it found, if:

  • the text is empty, or a field is too long;
  • the link isn’t an absolute https URL;
  • a channel’s text is over its network’s limit (text.too_long:<network>);
  • a network’s rules aren’t met (image.required:instagram, link.title_required:linkedin, link.image_conflict:linkedin);
  • a channel is unknown, removed, or paused by the free edition’s allowance (channel.unknown, channel.paused).

You can run the same checks without saving to show live counts while writing: IPostService.CheckAsync, or POST …/posts/check in the management API. It returns each channel’s count, its limit and its errors. Every code is listed in Error codes.

A post can be edited at any time, with these rules:

  • While it is being sent (any channel is Publishing), it can’t be edited or deleted (post.in_flight). Try again in a moment.
  • While any channel’s outcome is Unknown, it can’t be edited (post.outcome_unknown). Resolve that channel first: check the account, then retry it or mark it as published. This stops an edit from sending a post a second time.
  • Channels where it is already published keep the text they went out with, whatever you change. They aren’t sent again.
  • Channels where it failed are sent again at the new time, as a new attempt.
  • You can add channels to a post, or remove channels where it hasn’t been published.
  • On the free edition, a post sealed by the history window can’t be edited (post.sealed).

Delete a saved post from the composer’s footer bar (Delete, then confirm). Deleting a post removes it from Social. It doesn’t remove anything from the networks: delete a live post on the network itself.

A post can’t be deleted while it is being sent (post.in_flight).