Social Publish
Publish a caption, with media or as text alone, to one or more connected social channels. Media is optional on Threads, Bluesky and Mastodon; Instagram, YouTube, LinkedIn and TikTok refuse a post without it. Posts go out at the time you set; posting cadence (min interval, max/day) and caption variation are checked and reported as warnings.
Social Publish
Node type: action:social_publish
Category: Integrations
Description
Publish a caption, with media or as text alone, to one or more connected social channels. Media is optional on Threads, Bluesky and Mastodon; Instagram, YouTube, LinkedIn and TikTok refuse a post without it. Posts go out at the time you set; posting cadence (min interval, max/day) and caption variation are checked and reported as warnings.
Canvas ports
These appear as port handles on the left side of the node.
| ID | Label | Details |
|---|---|---|
media |
Media | UNKNOWN (required) |
caption |
Caption | TEXT (required) |
Sidebar config
These render as form fields in the right-side config panel when the node is selected.
No sidebar config fields.
Outputs
| ID | Label | Type |
|---|---|---|
status |
Status | TEXT |
posts |
Posts | ARRAY |
firstError |
First Error | TEXT |
Platform options
Pick accounts in the config panel, then set options per platform. Each platform only shows the options it actually supports.
| Platform | Options |
|---|---|
| First comment, alt text for images | |
| First comment (plus the Instagram options below) | |
| YouTube | Title, visibility, go-public time, tags, thumbnail |
| Threads, Bluesky, Mastodon | Alt text for images |
| TikTok | Who can watch, interactions, AI label, cover frame, commercial content, inbox mode |
YouTube visibility: a new node starts at Private, so nobody sees the upload until you pick Unlisted or Public. A node saved before this setting existed keeps posting Public until you change it. Setting a go-public time keeps the video private and lets YouTube publish it at that time; if that time has already passed when the video uploads, it goes public straight away. YouTube may keep uploads from Wireflow private until Google finishes reviewing Wireflow's use of its API; when it does, the result says so. The title falls back to the first line of the caption. Custom thumbnails need a verified YouTube channel.
YouTube tags: type them as a comma separated list, like ai, video, shorts.
Saved config and the API also take a list of strings, like ["ai", "video"].
Anything else, such as a number or an object, is refused before anything is
posted. YouTube keeps 500 characters of tags in total (commas count, and a tag
with a space counts two more), so Wireflow keeps the first tags that fit and
drops the rest.
The first comment and the thumbnail are added after the post is live. If either fails, the post still counts as published, is not re-posted, and the result shows a warning saying what did not happen.
Instagram first comment: posted only when the connected account granted
Wireflow the comment permission. Wireflow does not ask for it while the Meta
app is in review, so most connections do not have it; the post then goes out
without the comment and the result warns "first comment not posted: this
Instagram connection lacks the comment permission". When it is posted, the
comment's id comes back as firstCommentId. Instagram has no API to pin a
comment, so pinning stays a tap in the app. If the comment request times out
the result says the comment "may or may not have posted": check the post
before commenting by hand. The comment is also skipped, with a warning, when
Instagram did not hand back the post's id directly and it had to be matched
afterwards, so it can never land on the wrong post.
Instagram first comment limits: at most 2,200 characters, 5 @mentions and 1 link. A longer or more link-heavy automated comment on a brand-new Instagram post reads as spam, so it is refused before anything is posted. An email address or a dotted handle such as @brand.co is not counted as a link. LinkedIn first comments have no such limit here.
A first comment on any other platform (X, Threads, YouTube, and so on) is refused before anything is posted rather than silently dropped.
Account ids and per-platform keys
An agent or script sets these in the node's config.
config.accounts is a list of account ids such as native:cm1abc23. List them with GET /api/v1/social/accounts using an API key that has social:read (the MCP list_social_accounts tool returns the same list, but needs the opt-in social:publish permission). An account a person has just connected shows up there on the next call. Details: Social Accounts.
config.perPlatformOverrides is keyed by platform, then by option, for example { "youtube": { "title": "How it was made", "privacy": "unlisted" } }. These are the keys each platform reads:
| Platform | Keys |
|---|---|
linkedin |
caption, firstComment, altText |
instagram |
caption, firstComment, aiLabel |
youtube |
caption, title, privacy, scheduledPublishAt, tags, thumbnailUrl |
threads |
caption, altText |
bluesky |
caption, altText |
mastodon |
caption, altText |
tiktok |
caption, privacyLevel, isAigc, coverTimestampMs, disableComment, disableDuet, disableStitch, brandOrganic, brandContent, uploadToInbox |
What each one takes:
caption: the post text for that platform, used instead of the node's caption. A Threads post's text is its caption. There is no separatetextkey.title(YouTube): up to 100 characters. Without it the title is the first line of the caption.privacy(YouTube):private,unlistedorpublic. Leave it out of a hand-written config and the video posts public. The node panel and the agent door fill inprivatefor you; nothing does that for config you write yourself, so set it.scheduledPublishAt(YouTube): an ISO 8601 time. The video stays private until then. A time that has already passed means public now.tags(YouTube): comma separated, such as"ai, video", or a list of strings, such as["ai", "video"]. Anything else is refused. YouTube keeps 500 characters of tags in total; the first tags that fit are kept.thumbnailUrl(YouTube): a public https URL. Needs a verified channel.firstComment(LinkedIn, Instagram): text posted as a comment right after the post goes live. Instagram caps it at 2,200 characters, 5 @mentions and 1 link.altText(LinkedIn, Threads, Bluesky, Mastodon): one image description, used for every image.aiLabel(Instagram):trueorfalse. On unless you sendfalse.privacyLevel(TikTok):PUBLIC_TO_EVERYONE,MUTUAL_FOLLOW_FRIENDS,FOLLOWER_OF_CREATORorSELF_ONLY. Until TikTok audits Wireflow's app onlySELF_ONLYis accepted (it is the default) and anything else is refused. After the audit there is no default, so set it.isAigc(TikTok):trueorfalse. On unless you sendfalse.coverTimestampMs(TikTok): the cover frame, in whole milliseconds into the video, 0 to 600000. Unset lets TikTok pick the first frame.disableComment,disableDuet,disableStitch(TikTok):trueorfalse. All three aretrue(off) unless you sendfalse, as TikTok requires.brandOrganic,brandContent(TikTok):trueorfalse, defaultfalse.brandOrganiclabels the video "Promotional content".brandContentlabels it "Paid partnership" and it cannot be private.uploadToInbox(TikTok):truesends the video to the creator's TikTok inbox to finish in the app, and the result reads "Sent to TikTok inbox", never "Published". Defaultfalse.
Two more groups of keys are read from config but are not accepted by the agent door: Instagram's shareToFeed, coverUrl, thumbOffsetMs, collaborators, trialReel and trialGraduation (the Instagram options described further down), and Mastodon's privacy, which takes public, unlisted or private and means unlisted when unset. The node panel has no field for Mastodon's.
Text-only posts
With NOTHING wired to Media, the caption posts on its own to Threads, Bluesky and Mastodon. Instagram, YouTube and LinkedIn need an image or a video, and TikTok a video, so a text-only post that includes one of them is refused before anything is posted, and the error names the account.
A wired Media port is different. If the node feeding it fails, Social Publish is skipped, exactly as before. If it finishes but hands over nothing that can be posted, the post is refused. Either way the caption never goes out alone.
Captions are checked before anything is posted, never truncated:
- Threads: at most 500 characters, and Meta counts each emoji as its UTF-8 bytes (2 to 4), so emoji use up the limit faster. At most 5 links.
- Bluesky: at most 300 characters.
- Mastodon: the limit is set per server and is checked when the post goes out.
Shorten the caption, or set a shorter one for that platform under per-platform variations.
Source key
Set Source key to the id of the post this one copies, such as an X post or
draft id. Each account gets at most one post per key: running the node again
with the same key returns the post already there, marked duplicate,
instead of posting it twice. A cancelled post does not count, and neither does
one that provably never went out (it could not be queued, or every attempt
failed before posting). A post that failed in a way that may have published it
anyway (a timeout while posting) still counts: on Threads, Wireflow checks the
account's recent posts and posts again only when the earlier one is provably
not there; otherwise the node says so and posts nothing. Connected accounts
only.
Each entry in posts carries the platform's post id (postId) and
liveUrl; a Threads post also carries its own permalink.
When is a post "published"
- LinkedIn video: only after LinkedIn finishes processing the video. If it cannot, nothing is posted and the node reports why.
- YouTube: after the upload, the node waits up to two minutes for YouTube to finish processing. If YouTube rejects the video, the node fails. If it is simply slow, the post is reported published, because the video exists.
- TikTok: when TikTok reports it complete. A private post (every post until TikTok audits Wireflow's app) reads "Posted privately, flip to public in TikTok", never plain Published; inbox mode reads "Sent to TikTok inbox". See TikTok below.
Scheduled posts
A scheduled post that hits a temporary error (a platform outage, a rate limit) is retried with a growing wait, up to five attempts. A post more than 24 hours past its time is not sent at all. The scheduler never sends one post twice: if a run is interrupted mid-publish, the post is marked failed with a note to check the account before posting again.
Ban-safety limits
Every connected account gets at most 3 feed posts in any 24 hours, at least 3
hours apart. The limits belong to the account on the platform, not to the node:
every board, every Wireflow login connected to the same account, and the MCP
publish_post tool share one budget. They are judged on when each post goes
out (after jitter), so you can queue a week of posts in one sitting. Instagram
Trial Reels run on their own budget (5 in 24 hours, 15 minutes apart) that
feed posts never count toward.
The node's Ban-safety knobs (min interval, max posts / 24h) set the limits for this node, and are used both when the post is scheduled and when it is sent. 0 means the default; 0 does not turn the limits off. If a post cannot go at its time, scheduling refuses it and says the earliest legal time.
A post deleted on Instagram stops counting once Instagram confirms it is gone. A scheduled post that would break the limits when it actually fires (after an outage, for example) is moved to the next allowed time, and the post's warnings say why. A run that starts a few seconds after the post's time is judged at the post's own time, so a set spaced at the minimum goes out on time.
Posting from an agent
The Wireflow MCP server can post without a node: list_social_accounts,
publish_post, get_post_status and cancel_post. They need the social:publish
permission, which is off by default and only the account owner can tick on the
authorization screen. publish_post takes an idempotencyKey: an agent
that retries with the same key gets the original post back instead of a second
one. It queues the post and returns right away; get_post_status reports
when it is live, and cancel_post stops a post that is still scheduled. The
same ban-safety limits apply as in the node. Omit mediaUrls for a text-only
post (same platforms as the node), and pass sourceKey so one source post
reaches each account once.
Instagram-specific options (cover, collaborators, Trial Reel, share-to-feed)
are node-UI only for now; passing them to publish_post is refused. The first
comment and the AI label are the exceptions: publish_post takes
firstComment and aiLabel (true or false) for Instagram.
Connecting an account
Open the node and use the Connect buttons under Accounts. Each one opens the platform's consent screen in a new tab; approve it, come back, and press Refresh. Tokens are stored encrypted and refreshed for you.
Bluesky connects with an app password instead: the button opens a small form
in the node. An agent can start any connection with the MCP
connect_social_account tool, which returns a link for the account owner (or
connects Bluesky with an app password they give it).
Instagram is in preview: until Meta approves the app, the Connect Instagram button is shown only to Wireflow staff and to accounts approved for preview access. A team admin role alone does not show it.
Instagram needs a Business or Creator account. Personal accounts cannot publish through the API.
What gets posted depends on what you wire into Media:
| Media | Posts as |
|---|---|
| One video | A Reel |
| One image | A feed post |
| 2 to 10 files | A carousel (images, videos, or both) |
Images are made to fit Instagram's rules before upload: JPEG, at most 8MB, 320 to 1440 wide, and between 4:5 and 1.91:1. An image outside that range gets white bars rather than a crop, so a 9:16 still posts as 4:5 with bars left and right. Reels must be MP4 or MOV. More than 10 files is refused rather than trimmed.
Selecting an Instagram account shows these options:
- Label as AI-generated. On by default, so every Instagram post goes out
with the "AI info" label (Instagram limits reach for AI-person profiles that
skip it). Turn it off only for real footage. Once a post is sent, the result
shows
aiLabelastrue,false,disabled(the operator kill switch withheld it), orfallback(Instagram refused the label for that media type, so the post went out without it and the result carries a warning: add the label in the app). - Also show Reel in the main feed. On by default. Off keeps the Reel in the Reels tab only.
- Trial Reel. Shows the Reel to non-followers first. Choose whether it is shared with followers when you decide in the app, or automatically if it performs well. Only works on a single video, and cannot have collaborators.
- Cover. A cover image URL, or a frame of the video in milliseconds. The frame wins when both are set.
- Collaborators. Up to 3 usernames. They accept the invite in the app.
Instagram allows 100 API posts per account in any 24 hours, shared with every other tool connected to that account. When it is used up the node fails with a message saying so and posts nothing.
The node waits for Instagram to finish processing each video before publishing
(up to 4 minutes for the whole post) and returns the post's permalink in posts.
Full setup, including the Meta app settings: Publishing to Instagram.
TikTok
TikTok is in preview: the Connect TikTok button is shown only to Wireflow staff while TikTok reviews Wireflow's TikTok app.
Wireflow posts through TikTok's own Content Posting API. Press Connect TikTok, approve on TikTok's consent screen, and come back. Wireflow asks for three permissions: your basic profile, posting videos, and uploading videos to your TikTok inbox. Tokens are stored encrypted and refreshed for you.
Until TikTok audits Wireflow's app, every TikTok post is private. TikTok only accepts "Only me" posts from an app it has not audited yet, and may require the TikTok account itself to be set to private while testing. The post goes out private and the result says so; open it in the TikTok app and change Who can watch to make it public.
Selecting a TikTok account shows the account you are posting to (TikTok's nickname for it) and these options:
- Who can watch. Only me until the audit. After it, you must pick one of the options TikTok offers for your account; there is no default.
- Allow comments, duets, stitches. Off until you turn them on, as TikTok requires. An interaction you turned off for the whole account in TikTok is greyed out.
- Label as AI-generated. On by default, so TikTok shows its "Creator labeled as AI-generated" tag.
- Cover frame. Milliseconds into the video. Unset uses the first frame.
- Disclose commercial content. Off by default. "Your brand" labels the video "Promotional content"; "Branded content" labels it "Paid partnership" and cannot be private.
- Send to my TikTok inbox instead of posting. The video lands in your TikTok inbox and you finish it in the app, for example to add a trending sound. The caption and settings do not travel with it, and the result reads "Sent to TikTok inbox", never "Published".
Each post is one video (MP4, MOV or WebM, up to 10 minutes). The caption is the TikTok caption, up to 2,200 characters.
A TikTok post counts as published when TikTok reports it complete. A public post links the video by TikTok's post id; if TikTok has not released the id within the 8 minute wait (it can lag behind moderation), the post still counts as published, links your profile and says so. TikTok gives no id for a private post, so a private post reads "Posted privately, flip to public in TikTok", links your profile, and never counts as a public post. These are failures, never "published": TikTok failing the video (too long, wrong format), TikTok dropping a direct post into your inbox, and no answer within 8 minutes (the post may still appear, so check the account before posting again).
A TikTok private post or inbox upload counts as posted for a sourceKey: flip the post public in TikTok rather than posting it again. If you deleted the post or discarded the draft, post again with a new sourceKey.
Comments, duets and stitches start off on every TikTok post, as TikTok requires. Tick Allow comments (and duets, stitches) in the node, or pass "disableComment": false from an agent, to turn them on for that post.
Scheduled TikTok posts go out at their exact time, like every other platform. TikTok allows about 15 posts a day per account across all apps.
Approve every post. TikTok's rules say the creator must see each post (the video, the caption and its settings) and agree to it before it goes out. In Wireflow that approval is the node: you see the video and caption you wired in, pick the options, and run or schedule it yourself. Do not build flows that post videos to TikTok that nobody has looked at. By posting, you agree to TikTok's Music Usage Confirmation (and its Branded Content Policy for branded content).
An agent can start the connection with the MCP connect_social_account tool,
or GET /api/social/connect/tiktok with a Wireflow API key that holds
social:publish: both return a link the account owner opens while signed in
to Wireflow. GET /api/social/tiktok/creator-info?accountId=... returns the
same account options the node shows.
Auto-generated from the Wireflow node registry.