Publishing one piece of content and then rewriting it by hand for every platform is where a lot of creator time disappears. AI is good at the rewriting: shortening, changing tone, pulling a hook, writing a caption. It's bad at knowing each platform's hard limits, and at deciding whether a platform is worth posting to at all. This guide splits the work that way. You make the strategic calls, a script produces platform-ready drafts that are checked against real limits, and a scheduler handles the posting.
The adaptation step takes seconds per platform. Reviewing drafts and scheduling them takes longer, and how much longer depends on how many platforms you choose. We haven't measured reach or engagement changes from this workflow and don't quote any. Your own analytics are the only numbers that matter here.

First, decide where not to post
"Ten platforms" is a ceiling, not a target. Each extra platform adds review time, replies to answer, and analytics to watch. Score each candidate before you add it:
| Question | Keep the platform if... |
|---|---|
| Is your audience there? | You've seen real engagement or search traffic from it, or your peers' audience clearly lives there |
| Can you produce its native format? | You can supply what it rewards: vertical video, images, long text, or links |
| Will you reply there? | You can check comments at least a few times a week |
| Can you schedule it properly? | It's supported by an official API or a scheduler you trust |
| Can you measure it? | It reports reach and clicks, or traffic from it shows up in your analytics |
A typical solo setup ends up with the canonical post on your own site, a newsletter, and three to six social platforms. The rest of this guide works the same whether you choose four or ten.

The 10 destinations and their verified limits
Character limits change, so we list only figures we confirmed in official documentation on October 17, 2026. For the others, check the platform's own help center before relying on a number.
| Destination | Hard limits we verified | What to adapt |
|---|---|---|
| Your blog or site | None (you control it) | Canonical, full version. Everything else links back here |
| Newsletter | Set by your email provider | Short summary plus why it matters to subscribers |
| X | 280 characters; every URL counts as 23 (X developer docs) | One sharp claim or result, then the link |
| 3,000 characters per post (LinkedIn Help) | Lesson-first, line breaks, professional context | |
| 2,200 characters, 30 hashtags, 20 @ tags per caption (Instagram Graph API reference) | Visual-first; the first line has to stand alone | |
| Threads | 500 characters per text post (Threads API docs) | Conversational version of the X post |
| Check the Meta Help Center | Community framing, a question to invite comments | |
| YouTube | Title 100 characters, description 5,000 (YouTube Help) | Short-form cut plus a searchable title |
| TikTok | Check TikTok's help center | Vertical video; the caption supports it, it doesn't replace it |
| Check Pinterest's help center | Vertical image, keyword-rich title and description |
Two details trip people up. On X, links are always counted as 23 characters regardless of length, and some characters, including many emoji, count as more than one. On Instagram, hashtags and @ mentions have their own caps, separate from the caption length.
Step 1: Write one master piece built for adaptation
Adaptation is only as good as its source. Before running anything, make sure the master piece (usually the blog post) has:

- one core claim or result you could state in a sentence;
- three to five supporting points that each stand alone, since these become carousel slides, thread posts, and video beats;
- one concrete example, number, or demo, something you actually did or measured;
- a clear next step for the reader, such as subscribing, downloading, or reading the full post.
If you can't name the core claim, no amount of rewriting will produce good social posts. Fix the source first.
Step 2: Generate drafts with structured output and validate them
This script takes the master piece and produces one draft per platform as structured data, then checks every draft against hard limits before you see it. It uses a local model through Ollama's structured output support, but any API with schema-constrained output works the same way.
# adapt.py (pip install ollama pydantic)
import re
from pydantic import BaseModel
from ollama import chat
PLATFORMS = {
# name: (max characters, max hashtags, style guidance)
"x": (280, 2, "One sharp claim or result. Link at the end."),
"threads": (500, 0, "Conversational. One idea. Invite replies."),
"linkedin": (3000, 3, "Lesson-first. Short paragraphs. Professional context."),
"instagram": (2200, 10, "First line must stand alone. Visual-first. Save-worthy."),
}
class Draft(BaseModel):
text: str
hashtags: list[str]
URL = re.compile(r"https?://\S+")
def x_length(text: str) -> int:
# Approximation: X counts every URL as 23 characters. Use the official
# twitter-text library if you need exact weighting for emoji and CJK text.
return len(URL.sub("x" * 23, text))
def check(name: str, d: Draft) -> list[str]:
limit, max_tags, _ = PLATFORMS[name]
body = d.text + ("\n\n" + " ".join(d.hashtags) if d.hashtags else "")
# Reserve room for the real link: 23 on X, ~120 for a UTM-tagged URL elsewhere.
body = body.replace("{link}", "x" * (23 if name == "x" else 120))
length = x_length(body) if name == "x" else len(body)
problems = []
if length > limit:
problems.append(f"{length} characters (limit {limit})")
if len(d.hashtags) > max_tags:
problems.append(f"{len(d.hashtags)} hashtags (limit {max_tags})")
if "{link}" not in d.text:
problems.append("missing {link} placeholder")
return problems
def adapt(master: str, name: str, model: str = "gemma3:12b", tries: int = 3) -> Draft:
limit, max_tags, style = PLATFORMS[name]
prompt = (f"Rewrite this for {name}. {style} Stay under {limit} characters including hashtags. "
f"Use at most {max_tags} hashtags. Write {{link}} where the link goes. "
f"Don't add claims, numbers, or results that aren't in the source.\n\nSOURCE:\n{master}")
feedback = ""
for _ in range(tries):
resp = chat(model=model, messages=[{"role": "user", "content": prompt + feedback}],
format=Draft.model_json_schema())
draft = Draft.model_validate_json(resp.message.content)
problems = check(name, draft)
if not problems:
return draft
feedback = "\n\nYour last draft failed these checks: " + "; ".join(problems)
raise ValueError(f"{name}: no valid draft after {tries} tries ({'; '.join(problems)})")
The instruction "don't add claims, numbers, or results that aren't in the source" is the most important line in the prompt. Without it, models happily invent statistics to make a post punchier, and that's the fastest way to lose trust. Reject any draft that adds a fact you can't stand behind.
The validation loop sends specific failures back to the model instead of silently truncating text, which would cut sentences mid-thought. After three failures, it stops and tells you, because that platform's draft needs a human.
Step 3: Tag every link so you can tell what worked
Each platform's draft gets its own tracked link, so your analytics can separate traffic by source. Google Analytics reads the standard utm_source, utm_medium, and utm_campaign parameters, documented in its campaign URL help page:

from urllib.parse import urlencode
def tagged(url: str, platform: str, campaign: str) -> str:
sep = "&" if "?" in url else "?"
return url + sep + urlencode({"utm_source": platform, "utm_medium": "social",
"utm_campaign": campaign})
def finalize(draft: Draft, url: str, platform: str, campaign: str) -> str:
text = draft.text.replace("{link}", tagged(url, platform, campaign))
return text + ("\n\n" + " ".join(draft.hashtags) if draft.hashtags else "")
Keep campaign names consistent, such as the post slug, so one piece's traffic rolls up across every platform. Use lowercase values. Analytics treats LinkedIn and linkedin as different sources. On X, the tagged URL still counts as 23 characters, so long UTM strings cost nothing there.
Worked example: one post, four drafts
Here's what the output should look like. The source is a tutorial on running Whisper locally for transcription. Its core claim: local Whisper transcribes video for free on a mid-range GPU, with no per-minute fees. These drafts were written for this guide to show the target shape. They're not model output we're quoting, and they come with no performance claims.
X (under 280 characters, link counted as 23):
Paying per minute to transcribe your videos? Whisper runs locally on a mid-range NVIDIA card for free. Setup, model choice, and accuracy tips: [link]
Threads (under 500 characters, no hashtags):
Honest question for video creators: what are you using for transcripts right now? I moved mine to Whisper running locally. No upload, no per-minute bill. Wrote up the full setup if you want to try it: [link]
LinkedIn (opening lines of a longer post):
Transcription was a line item in our video budget. It doesn't need to be.
OpenAI's Whisper runs on a local GPU, and the smaller models fit on mid-range cards. Here's the setup, step by step...
Instagram (first line has to work alone; carousel caption):
Free transcripts, no uploads. Swipe for the 4-step local Whisper setup. Full guide at the link in bio.

Notice what changes and what doesn't. The claim stays the same everywhere: free, local, mid-range GPU. Length, tone, and the call to action change per platform. Nothing new is invented. Instagram doesn't make caption links clickable, so that draft points to the bio instead of using {link}. Add a per-platform exception like that to the script's check() once you know which platforms need it.
Step 4: Review in one pass
Read all drafts side by side. A quick review checklist:
- Does each draft make the same core claim as the source, with no new "facts"?
- Does the first line work on its own? On most feeds, it's all anyone sees.
- Is the tone right for the platform, and does it still sound like you?
- Are hashtags relevant and few? Stuffing them in rarely helps readability.
- Does the link go to the right page, with the right UTM source?
Edit directly. The script's job is to get you to a nearly finished draft, not to publish unattended.
Step 5: Schedule through official channels
You have three reasonable options:
| Option | Good for | Watch out for |
|---|---|---|
| Native schedulers (LinkedIn, YouTube, Meta Business Suite) | One or two platforms, no extra cost | Logging into each platform separately |
| A scheduling service such as Buffer | Several platforms from one queue | Per-channel pricing and plan limits |
| Your own code against official APIs | High volume, custom workflows | App review, rate limits, and maintenance |
For a sense of scale, Buffer's pricing page as of October 17, 2026 lists a free plan covering 3 channels with 10 scheduled posts per channel, and an Essentials plan at $5 per channel per month billed yearly ($60 per year) with unlimited scheduled posts. Check current terms before you choose, since scheduler pricing changes often.
If you build against APIs yourself, read each platform's limits first. For example, Meta's content publishing documentation caps Instagram accounts at 100 API-published posts in a rolling 24-hour window, with a carousel counting as one post. Most platforms also require an app review or a business account before you can post through the API.
Avoid scripts that log into consumer accounts and click through the web interface to post. They break whenever the site changes, and many platforms' terms prohibit automated access outside their official APIs.
Step 6: Stagger, then measure
Posting everything at the same minute isn't required. A common pattern is to publish the canonical post first, then the newsletter, then social posts spread over the next few days, with short-form video cuts in the following week. Repurposing guides such as Repurpose Content AI: Turn 1 Blog Post Into 30+ Pieces go deeper on the formats.
After two to four weeks, compare platforms using the UTM data and each platform's own analytics. Look at clicks to your site and replies or comments, not just impressions. Drop the platform that's weakest relative to the effort it takes. Distribution gets easier when the list gets shorter.
Common mistakes
Identical text everywhere. Platforms differ in length, tone, and format. The point of adaptation is that each version reads like it belongs where it's posted.
Letting the model invent numbers. "Grew 4x in a month" from a source that never said that is a credibility problem. Keep the no-new-claims rule and enforce it in review.
Truncating instead of rewriting. Cutting text at the character limit produces broken sentences. Send failures back for a rewrite, as the script does.
Posting and leaving. Distribution invites replies. If you can't answer comments on a platform, you probably shouldn't post there yet.
Untagged links. Without UTM parameters, all social traffic blurs together, and you can't tell which platform earned its place.
FAQ
Can AI post to all of these automatically? Technically, through official APIs or a scheduler. Practically, keep a human review step. Unreviewed AI posts are how invented claims and tone-deaf replies reach your audience.
Which model should I use for adaptation? Any instruction-following model with structured output. Short rewrites are easy work, so a mid-size local model is usually enough. Quality comes from the source piece and the review, not model size.
Should I use different images per platform? Yes, sized to each platform's preferred aspect ratio. A vertical image for Pinterest and Stories, square or 4:5 for the Instagram feed, and 16:9 for YouTube thumbnails cover most needs.
How does this fit with content planning? Distribution is the last step. Plan the calendar first, produce in batch days, then adapt and schedule each piece as described here. For a single workflow that ties those steps together, see Building a Cross-Platform Content System With AI.



