Modular serverless microservice for rotating region-aware hashtags, logging GitHub events, and powering public dashboards. Ideal for civic technologists, journalists, and remixers.
This project fetches real-time trending hashtags from Trends24 and serves them via region-specific API endpoints. It includes scheduled cron tasks, GitHub webhook logging, and geo-aware routing — all deployed seamlessly on Vercel.
Vercel triggers /api/cron daily at 10:00 UTC (1PM Nairobi)
๐ก GitHub Webhook
Verifies HMAC signature and logs events to /api/diagnostics
๐ Geo Routing
Kenya visitors rerouted to /kenya-trends using IP headers
๐งช Diagnostics API
/api/diagnostics returns delivery logs, verification status, and timestamps
๐ก️ Crash Protection
All handlers use try/catch blocks for resilience
๐ Testing Script
test.sh validates endpoint response and logs headers
๐ Quick Start Guide
git clone https://github.com/pmmutiti/hashtag-rotator-service.git
cd hashtag-rotator-service
This project includes a preconfigured vercel.json file for instant deployment.
๐งพ Deployment Config
This file defines build targets, scheduled tasks, and geo-aware rewrites for Vercel deployment. It ensures modular routing, public observability, and remixable behavior across all endpoints.
This structure gives remixers and civic technologists the full blueprint for debugging webhook behavior, tracing malformed requests, and inspecting output through both JSON logs and browser previews.
“A webhook that logs what it receives is more reliable than one that only reacts.”
๐งช Validation Tools
Use test.sh to manually confirm that endpoints like /api/webhook respond correctly.
Payload snapshots are recorded under diagnostics/webhook-payloads. If they’re timestamped and growing, your webhook is live.
Serverless vs Node.js: A Civic Technologist’s Breakdown
Understanding serverless APIs, webhook listeners, and Node.js architecture for civic deployments
Serverless vs Node.js: A Civic Technologist’s Breakdown
Understanding webhook listeners, diagnostics, and deployment architecture for public infrastructure.
๐ฐ️ What Is Serverless?
Serverless architecture lets you deploy functions without managing servers. You write isolated handlers (e.g., cron.js, diagnostics.js) and deploy them to platforms like Vercel or Netlify. They scale automatically, respond to events, and are perfect for civic observability tools.
๐งฉ Node.js: The Traditional Runtime
Node.js gives you full control over the runtime environment. You manage the server, routing, and dependencies. It’s powerful but requires more setup, monitoring, and scaling logic. Great for long-running processes, but overkill for lightweight civic endpoints.
๐ก Webhooks & Diagnostics
Serverless shines for webhook listeners. You can deploy github-webhook.js to receive push events, log payloads, and trigger diagnostics — all without a persistent server. Add public logging and meta tags for transparency and discoverability.
๐ ️ Deployment & Remixability
With serverless, each function is modular and remixable. You can copy-paste cron.js into any civic dashboard, tweak the schedule, and redeploy instantly. Node.js apps require deeper integration and more documentation to remain remixable.
✅ Final Verdict
For civic technologists building public-facing tools, serverless offers speed, transparency, and modularity. Node.js still has its place — especially for complex workflows — but serverless is the remixable backbone of modern civic infrastructure.
๐ซ๐ Is Node.js the Server?
Not quite. Node.js is the runtime — the engine that runs JavaScript outside the browser. It lets you build server apps, but it’s not the server itself.
Concept
What It Is
Analogy
Node.js
A JavaScript engine that runs code
A chef who knows how to cook recipes
Express.js
A framework built on Node.js
A cookbook for making web servers
Your server file
The actual app that listens and responds
The restaurant serving meals
So when you write webhook-listener.js using Express, you’re building a server using Node.js as the engine. Node.js powers the logic, Express structures the routes, and your file becomes the server app that listens for webhooks.
Serverless vs Node.js: A Civic Technologist’s Breakdown
Understanding serverless APIs, webhook listeners, and Node.js architecture for civic deployments
Serverless vs Node.js: A Civic Technologist’s Breakdown
In civic tech deployments, clarity and modularity are essential. Whether you're building hashtag rotators, webhook listeners, or diagnostics endpoints, understanding the difference between serverless functions and traditional Node.js servers is key to remixability and public trust.
Serverless functions are short-lived, event-driven handlers deployed on platforms like Vercel. You don’t need to install Node.js — the platform runs it for you.
Serverless APIs on Vercel
When deploying serverless functions like /api/github-webhook.js, Vercel automatically provides the Node.js runtime. Your code executes only when triggered — no manual server setup required.
You write modular JavaScript, Vercel handles the execution. No need to run node manually.
Then it’s a full Node.js server. You run it manually using node webhook-listener.js. It stays active, listening for requests — unlike serverless functions, which spin up only when needed.
What Is a Server (for Non-Technical Readers)
A server is just a computer that listens for requests and sends back responses. Think of it like a reception desk: you ask for something, and it gives you what you need — whether it’s a webpage, data, or confirmation.
Is Node.js the Server? ๐ซ๐
Not quite. Node.js is the runtime — the engine that runs JavaScript outside the browser. It lets you build server apps, but it’s not the server itself.
Concept
What It Is
Analogy
Node.js
A JavaScript engine that runs code
A chef who knows how to cook recipes
Express.js
A framework built on Node.js
A cookbook for making web servers
Your server file
The actual app that listens and responds
The restaurant serving meals
So when you write webhook-listener.js using Express, you’re building a server using Node.js as the engine. Node.js powers the logic, Express structures the routes, and your file becomes the server app that listens for webhooks.
“Rewrites don’t redirect — they silently reroute traffic behind the scenes.” — Civic Deployment Rule #41
๐ Place the file in your project root, commit it to GitHub, and let Vercel auto-deploy the updated route. When users visit /, they’ll hit your rotator function instantly.
๐ Pro Tip: Combine rewrites with a JSON logger or visual dashboard at /status for public remixers to audit delivery results in real time.
๐ Understanding index.js in Your API Folder
Heads up: If you have a folder named /index.js/, that’s a misconfiguration. It should be a file, not a directory.
✅ Correct Setup: index.js as a File
If you want a default route (/) to respond with something — like a homepage, status message, or civic banner — then you should have:
/api/index.js responds to requests at /api/ and acts as a default API route.
๐ง Purpose of /api/index.js
Health checks
Welcome messages
Public status indicators
Redirects to other endpoints
๐งฌ Example Code
export default function handler(req, res) { res.status(200).json({ message: "✅ Civic webhook API is live", endpoints: [ "/api/hashtag-rotate-service", "/api/diagnostics" ], timestamp: new Date().toISOString() }); }
❌ Incorrect Setup: index.js as a Folder
If you have:
/index.js/ — that’s invalid. Vercel won’t recognize it as a route or function.
You should rename or restructure it to:
/api/index.js
/pages/index.js (if using Next.js for frontend)
Want a civic-grade index route? Just say “build index route” and I’ll generate a timestamped, remixable endpoint with diagnostics and metadata.
๐ก Civic API Index Endpoint
This endpoint provides a public-facing summary of all active webhook services, including diagnostics and rotator logic. It returns timestamped metadata for remixers, auditors, and civic observers.
✅ Endpoint:/api/index Returns live status, timestamp, and remix metadata for all civic webhook services.
๐ Linked Endpoints
Rotator Webhook: /api/hashtag-rotate-service Rotates civic hashtags based on GitHub events. Remixable & Verified.
๐ก This endpoint is designed for remixers, civic auditors, and public dashboards. It ensures transparency, traceability, and modular reuse across deployments.
๐ง What Exactly Is Parsing?
1️⃣ What Does It Mean “To Parse a File”?
Parsing means taking raw data (like a file or string) and analyzing its structure so a program can understand and use it.
Think of parsing like reading a blueprint: the system breaks it down into parts it can work with. If the file is well-structured, parsing succeeds. If it’s malformed, parsing fails — and you get errors.
2️⃣ What Does It Mean “To Parse a File as JSON: vercel.json”?
This means Vercel is trying to read your vercel.json file and interpret it as JSON format — a strict, structured data format used for configuration.
✅ JSON Must Follow Exact Rules:
All keys and strings must use double quotes ("key": "value")
No trailing commas
Proper nesting with {} and []
No comments allowed
๐งจ If parsing fails, you’ll see an error like: “Could not parse file as JSON: vercel.json” That means Vercel tried to read the file, expected valid JSON, and hit a syntax error — like a missing quote, extra comma, or invalid character.
๐ ️ Automate Responses • ๐ Secure Payloads • ๐ Build for Public Transparency
“Repository webhooks allow your civic tool or server to respond in real time to GitHub events — enabling automation, transparency, and engagement.”
๐ฃ Update: GitHub's REST API is now versioned. Add header X-GitHub-Api-Version: 2022-11-28 to all requests.
๐ What Are Webhooks?
Webhooks send HTTP POST payloads to your server whenever events like push or pull_request occur. They help automate civic dashboards, trigger builds, or notify services.
๐ฆ Listing Webhooks
Endpoint:GET /repos/{owner}/{repo}/hooks
Permissions:Webhooks: read access token required
Headers:Accept, Authorization, and X-GitHub-Api-Version