Replacing Buffer and Hootsuite with a Scheduler We Own
Buffer sells a calendar, cross-posting, and analytics. We only ever used those three things, so we built those three things and let the subscription go.
The bill
Social media scheduling tools sell you a lot more than scheduling. Buffer, Hootsuite, Later, and the rest all run the same pitch: a visual content calendar, cross-posting to every platform, an AI caption writer, a "best time to post" recommendation engine, and an analytics dashboard, usually priced per connected channel or per seat, so the bill climbs the moment you add another platform or another person on the team. Everyone pays it without arguing because the alternative looks like a developer project, and most businesses don't have a developer sitting around.
What we actually used
Almost nobody uses the whole product. We didn't. Strip away the upsells and we were using exactly three things: a calendar that held drafts and scheduled dates, a way to push one post out to several platforms without logging into each one by hand, and a number afterward that told us whether a post actually worked. The AI caption writer, the best-time-to-post model, the drag-and-drop visual board, we never touched them. That's the hinge of this whole post: the product and the job we were paying it to do were two different sizes.
How we built it
The calendar is a table in the same Airtable base that runs the rest of the business, not a separate app. Each post is a record with a Status (Draft, Scheduled, Published), a multi-select Channels field, a ScheduledDate, and its own Content. That's the whole visual layer: a filtered Airtable view, nothing custom-built for it.
A Vercel cron function, api/social-cron.js, runs nightly behind a bearer-token check against CRON_SECRET, fail-closed, so a missing secret refuses every caller rather than quietly allowing one. On each run it pulls every record where Status is Scheduled and the date is due, and for every channel still missing a live URL it calls that platform's own API directly, LinkedIn, Facebook, Instagram, YouTube, Bluesky, Threads, TikTok, no third-party scheduler sitting in the middle.
Each channel writes the live post URL back to its own field on the record. A post only flips to Published once every channel it was meant for has a URL. That one rule does two things at once: a platform that fails tonight just retries on its own tomorrow night without touching the channels that already succeeded, and nothing can ever get posted to the same place twice, because the presence of that URL is the only thing the script checks before it posts again.
TikTok and Threads publish in two steps, start a job, then poll until it's ready, and a serverless function only gets 300 seconds to run. So the function tracks its own clock: it stops starting new channels 240 seconds in, and if a video upload is still mid-flight when the run ends, the in-progress job's id gets written straight to the record. The next run, hourly rather than nightly for exactly this reason, resumes that same id instead of starting over. A second nightly phase re-reads each recently published post from its platform to refresh impressions and engagement, and rolls a daily per-account stats row so the trend over time doesn't depend on us remembering to check.
The trade-offs
Two of these are real, and I'd rather say them plainly than pretend this was free.
- There is no visual drag-and-drop calendar. It's a spreadsheet with filters. If someone on the team needs to see the next two weeks as a pretty board, this doesn't give them that, and building one would be a real project on its own.
- A vendor used to quietly handle token expiry for us. Now we watch it ourselves. Our LinkedIn member token has no refresh token, which means it's a manual re-authorization every couple of months, on a calendar we have to remember, not one a SaaS dashboard nags us about.
- Adding a platform means writing real integration code against that platform's API, not flipping a toggle. We went from one network to seven over time, and each one took actual engineering, not a checkbox.
What we would still pay for
If you're a small marketing team, several non-technical people approving and scheduling content every day, and nobody on the team ever wants to see an API key or think about a token expiring, keep paying for the tool. That's a genuine need and a scheduler is built exactly for it. The same goes if you only post to one or two platforms occasionally; the engineering cost of owning this isn't worth it at that scale.
What changed for us isn't really about saving a subscription fee. It's that the queue, the publish history, and the performance numbers all live in the same base as everything else we run, instead of behind a vendor's login. This is the twenty-first subscription we've replaced this way, as part of rebuilding the operating system for a roughly 200-employee business across 16 departments, now running with 25+ AI agents and $0 ongoing software cost. Knowing which subscriptions to kill is the same skill as knowing which ones to keep. This one, for how we post, we didn't need to keep renting.