DEV Community

Cover image for Building "Publish to 15+ Platforms" — What I Learned the Hard Way
twRty Connect
twRty Connect

Posted on

Building "Publish to 15+ Platforms" — What I Learned the Hard Way

Everyone underestimates this problem until they build it.

"Publish everywhere in one click." Six words. Sounds like a weekend feature. Add some API calls, loop through platforms, done.

We're the team at twRty Software Services — makers of twRty Blogboat, an AI writing studio that does exactly this. We want to share what building that feature actually cost in time, debugging, and rethinking assumptions.

Not to complain. But because if you're building anything in the creator tools space, these patterns will find you eventually.


The architecture looked simple on paper

The mental model going in: user writes a post → we call each platform's API → post appears everywhere. Clean, linear, obvious.

The reality: every platform has a completely different content model, a different auth system, different rate limits, and a different definition of what "published" means.

Medium uses a proprietary JSON format. Dev.to uses Markdown with front matter. WordPress wants Gutenberg blocks or raw HTML depending on the setup. Ghost uses Lexical JSON. Hashnode has a GraphQL API. LinkedIn — which has no blog API at all — needs a separate content strategy for long-form posts.

They all accept "blog content." They do it six completely different ways.

The first approach — convert everything from a shared Markdown source — broke in quiet, frustrating ways on almost every platform. Medium dropped code formatting. WordPress mangled heading hierarchy. The failures weren't loud errors. They were just wrong output that looked almost right until a real reader noticed.


The auth layer was its own project

Each platform has a different authentication model:

  • Dev.to: API keys
  • WordPress: Application passwords or OAuth depending on setup
  • Ghost: Admin API key + JWT signing per request
  • LinkedIn: OAuth 2.0 with a strict scope approval process
  • Hashnode: Personal access tokens
  • Medium: Integration tokens (now deprecated for new apps; migrated to OAuth)

Managing six credential formats securely — across web, iOS, and Android — was genuinely complex. Early on, the straightforward path was to store credentials server-side. We didn't take it.

Every credential in Blogboat is stored in the user's device keychain. We never see tokens, API keys, or passwords. They're never uploaded. This made the architecture harder and the UX more involved — reconnecting on new devices, explaining why we can't "just save it" — but it was the only design we were comfortable shipping.

Privacy isn't a feature you bolt on. It has to be the constraint you build around.


Silent failures nearly shipped

The bug that changed how we thought about the publish flow: a publish attempt would succeed on three platforms and fail silently on two others. No error thrown. No indication to the user. The post appeared to go out everywhere. It hadn't.

The fix wasn't just better error handling. It was rethinking the entire publish flow as a set of independent, trackable jobs — not a single atomic operation.

Each platform publish is now its own unit: its own status, its own retry logic, its own visible state. The user can see exactly what succeeded, what's pending, and what needs attention. "Medium ✓ / Dev.to ✓ / WordPress — retry?" is useful. "Something went wrong" is not.


Rate limits break bursts

When a user has 10+ platforms connected and hits publish, that's 10+ near-simultaneous API calls. Some platforms handle this fine. Some throttle hard on bursts.

The solution was queue-based publishing with configurable delays between calls and exponential backoff on rate-limit responses. None of this was in the original plan. All of it is now non-negotiable infrastructure.


What actually made it reliable

Looking back, three decisions made the biggest difference:

Adapter-per-platform, not a universal publisher. Each platform gets its own implementation behind a clean interface. More code. Much more maintainable. When LinkedIn changes something, you fix the LinkedIn adapter — nothing else breaks.

Always store the canonical source. The original content lives untouched. Transformations for each platform are computed at publish time and can be regenerated. If a platform's format changes, you re-run the transform — you don't lose the post.

Make every failure visible and recoverable. Users are remarkably tolerant of partial failures when they can see what happened and take action. They're not tolerant of silent ones.


The broader lesson

"Publish everywhere" sounds like a distribution feature. It's actually a distributed systems problem dressed up in a content creation interface.

The interesting part isn't the AI writing — that's a well-trodden space. The hard part is making reliable, cross-platform publishing feel effortless to a user who just wants their words to reach people.

We're not done. The platform list keeps growing. But the foundation is solid, and that took longer to get right than anything else in the product.


We're the team behind twRty Blogboat — AI writing + one-click publishing to 15+ platforms, built by twRty Software Services. Free to start on web, iOS, and Android. Happy to discuss any of these architecture decisions in the comments.


Watch the full app walkthrough:


Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.