Replacing make.com with self-hosted n8n — and teaching cricnepal to wish players happy birthday
For a while, cricnepal‘s social posting ran on make.com. Three scenarios, quietly firing webhooks: publish an article → tweet it, score an over → post the summary, hit a milestone → celebrate. It worked. It also sat behind someone else’s dashboard, on someone else’s pricing, with logic I couldn’t version or grep.
So I moved the whole thing onto self-hosted n8n at automate.cricnepal.com. Here’s how it went, what broke, and the small feature that turned out to be the most fun: a daily bot that wishes Nepal cricketers a happy birthday.
Why bother moving
make.com isn’t bad. But cricnepal already runs its own boxes, and every external SaaS in the critical path is one more login, one more bill, one more black box. n8n is open source, self-hostable, and the workflows are just JSON I can export, diff, and back up. For a site that’s mostly mine to maintain, owning the glue felt right.
The migration itself was almost anticlimactic — and that’s the point of doing it well. Every social target in WordPress was already a webhook URL stored as an option. Repointing make.com → n8n was changing a string, not shipping code. The PHP that builds the payload and fires the request never moved.
The stack, briefly
WordPress → outbound webhook → n8n → Facebook (Graph API)
└─→ X (Buffer GraphQL)
n8n receives the webhook, shapes the caption, and fans out to Facebook and X. Facebook goes direct via the Meta Graph API. X goes through Buffer — more on that below.
The birthday bot
The fun part. Cricket fans love an anniversary, and cricnepal has a database of hundreds of Nepal players with dates of birth. So: every morning at 9am Nepal time, find whoever’s celebrating and post a little tribute.
The constraint made it interesting. The obvious version writes stat-packed copy — “1,948 ODI runs, turns 25 today.” But cricnepal’s match data isn’t 100% complete for every domestic player, and the fastest way to lose trust is to confidently post a wrong number. An LLM left to free-wheel would happily invent records.
So the bot is deliberately humble. A small token-gated WordPress endpoint returns only safe bio fields — name, age, playing role, photo, profile link — for Nepal players whose birthday is today. No stats. n8n fills one of four rotating templates so it doesn’t read like a robot saying the same sentence daily:
🎂 Happy 24th birthday to Kushal Bhurtel! 🇳🇵 The top-order batter celebrates today — wishing the Nepal star a brilliant year ahead! 🏏
One nice trick: only about 18% of player records have a featured photo. Instead of posting faceless text, the bot shares the player’s profile page as a link — so Facebook pulls that page’s og:image and every post gets a visual, photo on file or not.
Where it fought back
No migration is clean. A few things cost me real time, so here they are for the next person:
Cloudflare doesn’t like robots. automate.cricnepal.com sits behind a managed challenge. A browser sails through; curl and server-to-server calls get a 403. Cue twenty confused minutes wondering why my test webhook “didn’t exist” — it existed fine, my client just wasn’t a browser. Lesson: test webhooks from the browser, or after publishing, not from a terminal.
TLS to your own origin. From inside the box, the WordPress hostname resolves to a loopback origin serving a Cloudflare Origin certificate — perfectly valid at the edge, but not in Node’s trust store. The fix is a one-toggle “ignore SSL issues” on the internal HTTP call, but the error message (“unable to verify the first certificate”) sends you hunting in the wrong place first.
Buffer changed its API. I wanted X posting to relay through Buffer (free tier, avoids X’s stingy write limits). Buffer’s classic REST API is closed to new apps now — you can’t even get a client id. The new GraphQL API works on the free plan with a personal key, but it’s a different shape: one channel per call, createPost mutation, shareNow mode. Worth knowing before you copy a 2019 tutorial.
The silent JSON gremlin. Importing an n8n workflow from JSON quietly dropped the Facebook node’s query parameters — so it tried to post an empty message and Facebook rejected it. The node looked fine; the values just weren’t there. And a credential rename once landed my text in the HTTP header name field instead of the title, producing the wonderfully cryptic “Header name must be a valid HTTP token.” Both five-minute fixes once you know; both a while to spot.
Where it landed
Six workflows now run in n8n. Publishing an article posts to Facebook and X. Live-match over-summaries and milestones still fire from the scorer. And every morning, if a Nepal cricketer has a birthday, the site says so — on Facebook and X, with a face and a warm line, and not a single invented statistic.
The bigger win isn’t any one workflow. It’s that the glue holding cricnepal’s social presence together is now mine — exportable, diffable, on my own box, and documented well enough that future-me can fix it at 9am when a birthday post throws.
If you’re running a small site on make.com or Zapier and you already own a server, self-hosted n8n is worth the afternoon. Just test your webhooks from a browser. 🇳🇵🏏
Built on WordPress (headless), n8n, the Meta Graph API, and Buffer’s GraphQL API. cricnepal is Nepal’s cricket home — scores, stats, and now, birthday wishes.


