Skip to main content

System Architecture

Understand how Branded Short Links routes requests, fires analytics trackers, and manages configuration across two separate runtimes.

System Overview

The project has two entry points running on different runtimes:

The worker handles incoming HTTP requests at the edge. The CLI manages the configuration file that the worker reads at runtime.

Request Flow

When a request arrives at the Cloudflare Worker:

  1. Parse environment — The worker reads SETTINGS, LINKS, and TRACKERS from Wrangler environment variables (injected as JSON strings during deployment). It validates them against the Zod config schema.

  2. Check HTTP method — Only GET and HEAD requests are processed. All other methods return 405 Method Not Allowed.

  3. Match shortcode — The URL pathname is stripped of its trailing slash and matched against the configured link items.

  4. Route the response:

ConditionResponse
Shortcode matchedFire trackers in background, redirect with configured HTTP status
No match, fallback configured, root path (/)Redirect to fallback URL origin only (always 301)
No match, fallback configured, other pathRedirect to fallback origin + original path/query/hash (always 301)
No match, no fallback, root path (/)Serve the branded landing page (200)
No match, no fallback, other pathServe the 404 not-found page (404)
  1. Log event — Every request logs a structured JSON payload to console.info() with the matched shortcode (or null), redirect URL, HTTP response code, and tracker names. You can view these logs in real time with npm run tail. Example payload:
{
  "shortcode": "/github",
  "redirect_url": "https://github.com/yourname",
  "http_response": 301,
  "trackers": ["my-ga4", "my-ntfy"]
}

Tracker Dispatch

Trackers fire in the background so the redirect response is returned immediately:

  • All trackers fire in parallel via Promise.allSettled().
  • Individual failures don't affect other trackers or the redirect.
  • Each tracker type makes its own HTTP request to the respective service's API endpoint.

Landing Page

When a GET request hits the root path (/) and no fallback URL is configured, the worker serves a branded HTML page:

  • Project name and description.
  • Link to the GitHub repository.
  • Dark mode support via CSS custom properties (prefers-color-scheme).
  • Fade-in animation.

When show_response_output is true, an expandable <details> element shows the config with sensitive values masked (••••••). The masking function replaces:

  • Linksredirect_url on every link item.
  • GA4 trackersmeasurement_id and api_secret.
  • Facebook trackerspixel_id.
  • ntfy trackersserver and token.
  • Reverse Proxy for ntfy trackersurl and optionally token.
  • PostHog trackershost and api_key.
  • Plain-text trackersurl and optionally token.

Settings (including worker_name, base_domain) and the fallback_url are shown unmasked.

A similar 404 page is served for unmatched paths when no fallback URL is configured.

Configuration Pipeline

The config file is never deployed directly. The CLI serializes each section as a JSON string into Wrangler environment variables. The worker parses these strings back into objects at runtime.

Source Structure

packages/branded-short-links/src/
|-- worker/                <-- Cloudflare Worker runtime
|   |-- index.ts           <-- Request handler, routing logic
|   |-- trackers.ts        <-- Tracker dispatch (GA4, Facebook, ntfy, Reverse Proxy for ntfy, PostHog, plain-text)
|   '-- landing/
|       '-- page.ts        <-- Landing page and 404 page HTML generation
|-- cli/                   <-- Node.js CLI runtime
|   |-- index.ts           <-- CLI entry point (Commander)
|   |-- commands/
|   |   |-- config-io.ts   <-- Config file read/write
|   |   |-- deploy.ts      <-- Deployment orchestration (7 steps)
|   |   |-- generate.ts    <-- wrangler.toml generation
|   |   |-- links.ts       <-- Link CRUD operations
|   |   |-- settings.ts    <-- Settings read/update
|   |   |-- trackers.ts    <-- Tracker CRUD operations
|   |   '-- validate.ts    <-- Config schema + duplicate validation
|   '-- menu/
|       '-- interactive.ts <-- Interactive TUI menu (prompts)
|-- lib/
|   |-- schema.ts          <-- Zod validation schemas (all types)
|   |-- regex.ts           <-- Centralized regex patterns
|   '-- item.ts            <-- App name constant
'-- types/                 <-- TypeScript declarations (.d.ts), mirrors src/

Worker code and CLI code are cleanly separated because they run on different runtimes (Cloudflare Workers vs. Node.js). They share the lib/ directory for schemas and utilities.

Error Strategy

LayerStrategy
Worker entry pointTry/catch wraps the entire fetch handler. Returns JSON error response on failure.
Config parsingZod safeParse at request time validates env vars. Returns 500 with error issues on failure.
Shortcode matchingNo match falls through to fallback URL, landing page, or 404. Never crashes.
Tracker dispatchPromise.allSettled() catches individual failures silently. Never blocks.
CLI commandsTry/catch at command level. Chalk-formatted errors. Non-zero exit code.
Config validationZod schemas catch type mismatches, missing fields, invalid URLs, duplicates.

Data Collected Per Request

When trackers fire, they can access these data points from the Cloudflare Workers runtime. Each tracker type selects the subset of data relevant to its API. See Trackers for what each type sends.

Shortcode Properties

VariableDescription
shortcodeThe matched shortcode path (e.g., /github).
redirect_urlThe destination URL the shortcode redirects to.

Request Properties

VariableSourceDescription
request_methodrequest.methodThe HTTP method (GET, HEAD).
request_urlrequest.urlThe full request URL.

Request Headers

VariableHeaderDescription
headers_cfConnectingIpCF-Connecting-IPThe client's IP address.
headers_cfIpCountryCF-IPCountryTwo-letter country code of the client (e.g., US).
headers_cfRayCF-RAYUnique Cloudflare request identifier.
headers_hostHostThe hostname from the request.
headers_userAgentUser-AgentThe client's user agent string.
headers_xRealIpX-Real-IPThe client's real IP when behind a proxy.

Cloudflare Edge Properties

These properties come from the request.cf object populated by Cloudflare's edge network.

VariableSourceDescription
cf_asnrequest.cf.asnASN of the incoming request (e.g., 395747).
cf_asOrganizationrequest.cf.asOrganizationOrganization that owns the ASN (e.g., Google Cloud).
cf_cityrequest.cf.cityCity of the incoming request (e.g., Austin).
cf_colorequest.cf.coloThree-letter IATA airport code of the data center (e.g., DFW).
cf_continentrequest.cf.continentContinent code (e.g., NA).
cf_countryrequest.cf.countryTwo-letter country code (e.g., US). Same as the CF-IPCountry header.
cf_isEUCountryrequest.cf.isEUCountryReturns "1" if the country is in the EU. Omitted otherwise.
cf_latituderequest.cf.latitudeLatitude of the incoming request (e.g., 30.27130).
cf_longituderequest.cf.longitudeLongitude of the incoming request (e.g., -97.74260).
cf_metroCoderequest.cf.metroCodeDMA metro code (e.g., 635).
cf_postalCoderequest.cf.postalCodePostal code (e.g., 78701).
cf_regionrequest.cf.regionISO 3166-2 region name (e.g., Texas).
cf_regionCoderequest.cf.regionCodeISO 3166-2 region code (e.g., TX).
cf_timezonerequest.cf.timezoneIANA timezone (e.g., America/Chicago).

Why Direct Tracking?

Traditional tag management systems like Google Tag Manager rely on embedding JavaScript in the browser. This doesn't work for URL shorteners because browsers immediately follow the Location header on a 3xx redirect response instead of loading the response body, so embedded analytics scripts never execute.

Branded Short Links solves this by firing analytics trackers server-side from the Cloudflare Worker, bypassing the browser entirely. This means:

  • No client-side JavaScript required.
  • No dependency on browser-side tag containers.
  • Tracking works even when JavaScript is blocked or disabled.
  • No http-equiv meta refresh redirects (which are bad for SEO).