Guides · Cloud Run & Google Cloud · Published 2026-09-13 · 3 min read

A Tiny Redirect Service on Cloud Run — Short Links in Firestore, Click Counting by Month, and Why It Beats Pasting Affiliate URLs Into Articles

Build a go.example.com redirect service in Node and Express backed by Firestore: one document per slug, a 302 to the target, a per-month click counter, and an admin list. Why routing every outbound link through it saves you when programs change.

Every outbound link on a content site is a liability the moment you paste it in: affiliate programs change tracking parameters, reject you and later approve you, or shut down, and each change means editing every article. A redirect service fixes that in one place. Articles link to go.example.com/some-slug; the service looks the slug up, counts the click, and sends a 302 to whatever the current target is. Changing a partner is one document update.

Data model

One Firestore document per slug in a links collection:

Field Purpose
url The current target, including any tracking parameters
channelId Which partner or program the link belongs to, for grouping in reports
label Human-readable note for the admin list
active Set false to disable without deleting; the service then returns a 404 or a fallback
clicks Total count
clicksByMonth A map of YYYY-MM to count, so reports do not need a query per month
createdAt Timestamp

Keeping counts in the document rather than logging each click keeps costs at one read and one write per redirect and makes the admin page a single collection scan.

The redirect route

The handler reads the document, returns 404 if missing or inactive, increments both counters with a transaction or an atomic increment, and responds with a 302 to url. Use 302 rather than 301: a 301 is cached by browsers and by some crawlers, which defeats counting and freezes the target. Set Cache-Control: no-store for the same reason. Do the counter write after sending the response, or fire it without awaiting, so a Firestore hiccup never delays the user; a lost click is cheaper than a slow redirect.

Admin

An admin site with a login cookie lists the links, lets you create or edit a slug and target, and shows clicks by month per channel. The same service can expose a small JSON endpoint so scripts can create links in bulk when publishing a batch of articles, which is how we add ten route guides with their booking links in one go.

Deploying

The service is a normal Express app on Cloud Run, with the Firestore client using the default service account. Map a subdomain to it and add robots.txt disallowing everything, since the redirect URLs have no content of their own. The deployment steps are the same as in deploying Node and Express to Cloud Run, and the domain mapping is in Cloud Run custom domains with Cloudflare DNS. Scale-to-zero cold starts add a moment to the first click after a quiet period; for a redirect that is acceptable, and the trade-off is covered in what a small Cloud Run site really costs.

Disclosure and rel attributes

Route affiliate links through the service but keep the disclosure on the page: readers should know a link may earn a commission, and the anchor should carry rel="sponsored noopener" where the program requires it. Your own product links can use rel="noopener" alone. The redirect service does not change what the link is; it only makes it manageable.

Common mistakes

Summary

A slug-to-URL document, a 302 with no caching, an atomic per-month counter and a small admin list are all a link service needs. Every article then links to something you control, and a changed program is one edit rather than a hundred.

Related guides