← All engineering notes

ByteCap · Platform engineering

Building cross platform video publishing.

How I connected one video workflow to six social platforms, got through provider approvals, kept account access secure, and built the scheduling worker behind it.

View live product Read product announcement
Your publishing workspaceProduct workflow
One video. More places.

Choose where your next video goes.

Ready
YouTube
TikTok
Instagram
Facebook
LinkedIn
X
Post caption

A fresh perspective. A new conversation.

Here's the moment worth sharing.

Customize copy and settings for each platform
Publish now or pick a time
Your week, planned.

Scheduled once. Published from the worker.

MON9:00 AM
The episode highlightYouTube · TikTok · Instagram
WED12:30 PM
An idea worth a closer lookLinkedIn · X
FRI4:00 PM
Weekly behind the scenesInstagram · Facebook
Publishing pathDurable workflow
01ConnectOAuth · scoped access
02ComposeCopy · platform settings
03ValidateOwnership · limits
04ScheduleTimezone · durable state
05ClaimWorker · concurrency
06PublishPlatform adapters
07ReportResults · recovery

I built the publishing experience in ByteCap and the worker that fulfills scheduled posts. The guiding idea was simple. Give creators one workflow while still respecting the security, policy, and technical differences between each platform.

01

The problem after the edit

When a video was finished, the work still was not done. The user had to export it, open several social apps, upload the same file again and again, rewrite the post for each audience, and remember when every version was supposed to go live.

I wanted publishing to be the last part of the editor, not another product the user had to manage. They should be able to connect an account once, choose where the video goes, change the post for each platform, and publish now or add it to a calendar. The UI looked simple, but every destination had its own login flow, upload process, metadata, limits, and idea of what a successful post looked like.

02

Earning access to the platforms

The first hard part was not the upload code. Before ByteCap could publish anything, I had to get the app approved by each provider.

I went through the review process for Google and YouTube, TikTok, Meta for Instagram and Facebook, LinkedIn, and X. They all asked for different things. I had to provide product details, privacy documents, redirect URLs, reasons for each permission, test accounts, and recordings of the full connection and publishing flow.

That work ended up improving the product. Every permission had to match something the user could actually see and use. The consent screens needed to make sense, and disconnecting an account had to work properly. Approval is not the end of it either. Scopes, API versions, and platform rules keep changing, so I built the integrations with that maintenance in mind.

GoogleMetaTikTokLinkedInX
One product. A separate approval for every provider.

03

Connect once without handling passwords

I used OAuth for every connection, so the creator signs in and approves access on the provider’s own screen. Their social password never goes through ByteCap. The server only gets the scoped access needed for the features they approved.

The connection flow checks that the user is signed in, limits repeated attempts, and validates the callback with short lived state. TikTok and X also use PKCE. Callback data lives in HTTP only cookies or temporary Redis records, while publishing tokens stay on the server and never get sent to the browser.

Token refresh and expiry work differently on every platform, so I handle each one separately. A user can disconnect at any time. ByteCap removes the saved connection and revokes access when the provider supports it. Connect once should be convenient, but it should never mean giving up control of the account.

Your social accountPassword stays here
Approved access
BByteCapReady to publish
Connect once. Disconnect whenever you want.

04

One composer, six different contracts

The frontend gives the user one publishing flow, but the backend still respects how different the platforms are.

YouTube needs a title, description, tags, category, audience setting, and visibility. TikTok has privacy controls, comments, duets, stitches, and content disclosures. LinkedIn works better with longer professional copy. Instagram and Facebook use Meta’s container and Page flows. X has its own text limits and media upload rules.

I kept those differences inside platform settings and separate service adapters. The shared fields make the normal flow quick, while overrides let the user write something that fits each network. I also validate the post before it reaches the queue. It is much better to catch a bad X caption or missing YouTube title while the user can still fix it than when a worker is trying to publish later.

05

Scheduling is a backend system

The calendar is only the part the user sees. Scheduling still has to work when the browser is closed, the user is asleep, or a worker restarts during the day.

When someone schedules a post, the API verifies the user, checks project ownership, confirms the exported video exists, validates the time and timezone, applies the platform limits, and saves everything the worker will need later.

The worker loads due posts in small batches. It moves each post from pending to processing with an atomic update, which stops two workers from publishing the same video. It then loads the claimed post and checks the user’s publishing access again. If a processing job gets stuck for too long, it becomes a visible failure instead of sitting there forever.

Saved jobs
WorkerClaims each job once
Publish
Your schedule keeps running after the browser closes.

06

Making failures honest

Publishing to several platforms is not one operation. YouTube can succeed while TikTok rejects the same job. Showing one green status for that would be misleading.

I save a result for every destination and let the other platforms continue when one fails. The UI can show the posts that went live next to the exact platform error that needs attention. Uploads also have timeouts, but retries need care because a request might still finish after the worker stops waiting. Retrying too quickly can create duplicate public posts.

The worker refreshes expired access when it can, backs off from upload limits, and spaces out TikTok jobs when spam rules are triggered. It only retries automatically when the failure is known to be safe. For this system, reliability means showing what really happened instead of retrying everything and hoping for the best.

YouTubePublished
TikTokNeeds attention
LinkedInPublished
One failed destination doesn’t stop the others.

07

Keeping user data private by design

Social connections are powerful credentials, so I tried to keep their exposure as small as possible. The browser only needs connection state and basic profile labels. The actual publishing access is loaded and used by authenticated server routes and workers. Scheduled posts belong to the signed in user, and ByteCap checks the user and project path before an exported video can be queued.

I only requested the scopes needed for connection, profile display, publishing, and the analytics the product actually shows. OAuth state can only be used once and expires quickly. The routes are rate limited, token refresh happens on the server, and every connected account has a clear disconnect action.

Privacy is not just a line on the consent screen. The same boundaries have to show up in the callback, database query, API route, queue record, worker, logs, and disconnect flow.

08

What made the integrations difficult

The upload process was different everywhere. TikTok needs chunk calculations and status polling after the bytes are sent. Instagram creates a media container, waits for it to process, and then publishes it. LinkedIn registers an upload before sending the video and creating the post. YouTube uses resumable uploads and has a much larger metadata model. X separates the media upload from the post and even counts text differently.

That is why I did not build one giant publish everywhere function. Each adapter owns the details for its provider, including refresh behavior, validation, and useful errors. The scheduler only handles orchestration and durable state. When a provider changes its API, I can update that integration without risking the rest of the publishing pipeline.

09

What I learned building it

Cross platform publishing looks like an API integration feature, but most of the hard work is around trust and reliable background jobs.

The approval process forced the product, permissions, and privacy story to match. The platform settings forced the data model to keep the differences that actually matter. Scheduling brought in ownership, timezones, concurrency, stuck jobs, rate limits, and partial failures.

The user only has to do the annoying part once by connecting their accounts. They still control the copy, settings, and schedule for each video. From there, the system has to remember the plan, talk to every API correctly, and be honest when one of the platforms does not cooperate.

View cross platform publishing