Half an hour ago a Chrome extension we depend on for cross-platform posting stopped responding. Instagram publishes started returning empty. TikTok stopped. X stopped. Six platforms in one workflow and five of them went dark inside the same minute.
The sixth platform was Bluesky. Bluesky kept publishing. It kept publishing because the path to it does not go through a browser at all. It goes straight at the AT Protocol over HTTPS, with an app password and a JSON body, the way you would call any other JSON API. The decision to do it that way was made months ago and at the time it felt like extra work. Today it is the only thing keeping our content pipeline alive while the bridge is being repaired.
This post is about that decision and what it cost us when we made it, what it saves us when the bridge breaks, and how to think about the same tradeoff if you are building anything that has to talk to multiple social platforms at once.
Two paths into Bluesky
You have two reasonable ways to publish to Bluesky from automation.
The first is what we call the bridge path. You drive a real Chrome instance with a real logged-in profile, navigate to bsky.app, and let the page do the work. A small extension on your end exposes a few RPCs that say "go here, type this, click that." From the outside it looks identical to a person posting. The big advantage is that you do not have to know anything about how Bluesky actually works on the wire. The page handles auth, the page handles rate limits, the page handles every weird edge of the format. You just point and click.
The second is the API path. Bluesky publishes its protocol openly and gives you an app password endpoint that returns a session token, plus a com.atproto.repo.createRecord endpoint that takes the post body as JSON. You skip the browser entirely. You sign in once, you get back an access token and a refresh token, and from then on every post is one HTTP POST with a small JSON body. There are about forty lines of code from "no client" to "post landed."
Both paths are legal under the platform terms. Both paths actually work. They differ only in failure mode.
What the bridge path costs you when it breaks
The bridge path has one structural weakness. It runs in a process that does not belong to you. The Chrome process can crash. The extension can be unloaded. The page DOM can change and break your selectors. The user account can be flagged for "automation-like behavior" because every action looks slightly off-rhythm from a human typing. The OS can suspend Chrome to reclaim memory. Your script can race the user when both of you click in the same window at the same time. None of these are theoretical. We have hit every single one over the last six months.
When the bridge breaks, your error message reads "browser unavailable" or "bridge returned None or empty" or "extension command timed out after 35 seconds." None of those messages tell you what is actually wrong. The diagnosis is always the same routine: open the extension page, check the service worker, reload, navigate by hand, see if it sticks. By the time you have done that, the next scheduled tick has fired and is failing the same way.
That is what was in our publish log between 16:13 and 16:21 UTC today. Forty-three failed publishes inside eight minutes. All of them on bridge-dependent platforms. None of them telling us anything we did not already know.
What the API path costs you when you build it
The API path costs you a one-time read of the protocol docs and the willingness to write code in an unfamiliar shape. You have to learn what a did:plc is. You have to learn that posts are records and records have collections. You have to learn that the access token has a short life and the refresh token is what carries continuity. You have to learn that text on Bluesky has facets, which is how a https://example.com in your post body becomes a clickable link in the rendered post.
That is real work. None of it is what you actually want to be doing. You want to post. You do not want to learn a new identity model, a new record format, and a new facet schema just to put a sentence on a feed.
But here is the thing. You learn it once. You write the client once. The client is short. Ours is under three hundred lines of Python, including the JSON schemas for the three record types we touch. Then you never look at it again. It does not break when Chrome crashes. It does not break when an extension reloads. It does not break when the bsky.app DOM changes. It breaks only if Bluesky changes the protocol, and when they do they version it and announce it weeks ahead.
That tradeoff, "real work once, no maintenance later," is the same tradeoff every senior engineer learns to take by default. The reason the bridge path is so common in social automation is that nobody wants to do the real-work-once part for ten platforms. So they build a single bridge, they automate it once, and they live with the fragility forever.
When to pick which path
The pattern we are settling into looks like this.
For platforms that publish a real API and document it well, take the API path. Bluesky does. So does DEV.to. So does Mastodon. So does Hashnode. The work is bounded, the result is permanent, and the only times you touch it again are when the platform versions the API.
For platforms that have no real API, or whose real API is gated behind enterprise contracts, take the bridge path and accept the maintenance cost. Instagram is the obvious one. TikTok is the obvious one. X is the obvious one. You do not have a choice.
For everything in the middle, take the API path first. The middle includes services that have an API but where the API requires going through the developer dashboard for rate-limit increases. Do it once and front-load the friction.
The mistake is putting everything on the bridge because the bridge is where the velocity is on day one. Day one is not where you live.
What today taught us
Today, between 16:13 and 16:21 UTC, our content pipeline lost five of six platforms because of one extension. The platform that did not go down was the one we had bothered to wire correctly. While the bridge was being repaired, that one platform kept publishing real posts to a real audience.
Half an hour of one platform up is, in our case, more reach than four hours of all six up later in the day. Volume is replaceable. Continuity is not.
If you are building automation for any platform that publishes a real API, build the API client first. The hour you spend learning the protocol will return you the hour someone else spends restarting Chrome. And the hour after that. And the hour after that.
If you run your own publishing pipeline across more than one platform and want a worked reference for the API-first pattern (auth flow, record format, retry shape, idempotency keys), the kit we use day to day is on Gumroad here: https://a3eecosystem.com/r/4oo6qrwa
Comments and corrections welcome. If your client handles facets differently or if you have hit an edge case we have not, I would like to read it.
Top comments (0)