Skip to main content

Configuration Settings

Define your short links, analytics trackers, private app access, and worker settings through a single JSON configuration file managed by the CLI.

Config File Location

The CLI resolves config.json by checking these locations in order:

  1. Current working directory
  2. Project root (detected by package.json)
  3. User config directory (~/.config/branded-short-links/)

If no config file exists, the CLI copies the starter template bundled with the npm package into the user config directory.

Structure

The config file has three required top-level sections and one optional app_access section:

config.json
json
{
  "links": { ... },
  "trackers": [ ... ],
  "app_access": { ... },
  "settings": { ... }
}

Settings

Controls worker identity and debug behavior.

FieldTypeRequiredDescription
worker_namestringYesName of the Cloudflare Worker deployment.
base_domainstringYesBase domain for short links (e.g., example.com).
show_response_outputbooleanYesShow masked config on the landing and 404 pages for debugging.
config.json
json
{
  "settings": {
    "worker_name": "branded-short-links",
    "base_domain": "example.com",
    "show_response_output": false
  }
}

Defines the shortcode-to-URL mappings and an optional fallback.

FieldTypeRequiredDescription
fallback_urlstringNoDefault redirect for unmatched shortcodes. Must be a valid URL.
itemsarrayYesArray of link items (see below).

Each item maps a shortcode path to a destination URL with a specific redirect status.

FieldTypeRequiredDescription
shortcodestringYesPath segment starting with / (e.g., /github). Min 2 chars.
http_responsenumberYesHTTP redirect status: 301, 302, 303, 307, or 308.
redirect_urlstringYesDestination URL. Must be a valid URL.
config.json
json
{
  "links": {
    "fallback_url": "https://example.com",
    "items": [
      {
        "shortcode": "/github",
        "http_response": 301,
        "redirect_url": "https://github.com/yourname"
      },
      {
        "shortcode": "/linkedin",
        "http_response": 302,
        "redirect_url": "https://linkedin.com/in/yourname"
      }
    ]
  }
}

Redirect Status Codes

CodeNameUse Case
301Moved PermanentlyPermanent redirect. Search engines transfer link equity.
302FoundTemporary redirect. Original URL retains SEO value.
303See OtherRedirect after POST. Forces GET on the destination.
307Temporary RedirectTemporary redirect. Preserves the original HTTP method.
308Permanent RedirectPermanent redirect. Preserves the original HTTP method.

Shortcode Matching

The worker strips trailing slashes before matching. Query strings and hash fragments are not used for matching and are not forwarded to the redirect destination for matched shortcodes — the redirect always goes to the exact redirect_url from your config.

This differs from fallback redirects, which do preserve the original path, query, and hash (see below).

RequestMatched ShortcodeRedirect Destination
https://example.com/github/githubhttps://github.com/yourname
https://example.com/github?ref=twitter/githubhttps://github.com/yourname
https://example.com/github//githubhttps://github.com/yourname
https://example.com/unknown(none)Fallback URL or 404 page

Fallback URL Behavior

When a request doesn't match any shortcode and a fallback_url is configured, the redirect behavior depends on the request path:

  • Root path (/) — Redirects to the fallback URL's origin only (e.g., https://example.com). The original path, query string, and hash are not forwarded.
  • Any other path — Redirects to the fallback URL's origin with the original pathname, query string, and hash fragment preserved (e.g., /about?ref=home#section appended to the fallback origin).

Fallback redirects always use HTTP status 301 (Moved Permanently). This is not configurable — only shortcode redirects use the per-link http_response setting.

When no fallback_url is configured, the root path serves the landing page and all other unmatched paths serve a 404 page.

Trackers

An array of analytics integrations. Each tracker has a type field that determines which additional fields are required. All trackers fire in parallel on every matched shortcode redirect.

See Trackers for the full reference on each tracker type.

Quick Reference

TypeRequired Fields
ga4name, measurement_id, api_secret
facebookname, pixel_id
ntfyname, server, topic, token
ntfy-reverse-proxyname, url; optional: token
posthogname, host, api_key
plain-textname, url; optional: token

App Access

The optional app_access section enables the private read-only endpoint at https://<base_domain>/__bsl/links. A native client signs in with the deployment URL, a configured username, and its access key over HTTPS Basic authentication.

config.json
json
{
  "app_access": {
    "users": [
      {
        "username": "jacky",
        "access_key": "artist-cactus-forest-magnet-river"
      }
    ]
  }
}
FieldTypeRequiredDescription
usersarrayYesDeployer-managed app users. An empty array keeps the endpoint disabled.
usernamestringYesUnique lowercase username using letters, digits, periods, underscores, or hyphens.
access_keystringYesKey generated by bsl access add or bsl access rotate.

The CLI supports three cryptographically random key formats:

FormatShapeBest For
memorableFive lowercase wordsManual entry on another device.
compactFive four-character chunksShorter manual entry using unambiguous Crockford Base32 characters.
randombsl_ plus 43 charactersCopy and paste when manual entry is not needed.

Credentials are intentionally stored as plain text in config.json because the app is read-only and configuration changes require a redeploy. Keep the config private. The authenticated response includes branded URLs, redirect destinations, response codes, fallback URL, and tracker configuration, but never includes the app_access section. Public landing and 404 debug output also omit the entire section.

Sample Config

The full sample configuration file:

config.json
json
{
  "links": {
    "fallback_url": "https://example.com",
    "items": [
      {
        "shortcode": "/example",
        "http_response": 301,
        "redirect_url": "https://example.com/destination"
      }
    ]
  },
  "trackers": [
    {
      "name": "my-ga4",
      "type": "ga4",
      "measurement_id": "",
      "api_secret": ""
    }
  ],
  "app_access": {
    "users": []
  },
  "settings": {
    "worker_name": "branded-short-links",
    "base_domain": "example.com",
    "show_response_output": false
  }
}

Validation

Run the validate command to check your config against the schema:

bash
bsl validate

Validation checks:

  • All required fields are present and correctly typed.
  • URLs are valid format.
  • Shortcodes start with / and are at least 2 characters.
  • HTTP response codes are one of the allowed values.
  • No duplicate shortcodes exist.
  • No duplicate tracker names exist.
  • No duplicate app-access usernames exist.
  • The reserved /__bsl/links path is not used as a shortcode.
  • App usernames and access keys match their supported formats.
  • Tracker-specific fields match the declared type (extra fields are rejected).

Environment Variables

The CLI resolves .env by checking these locations in order (same as config resolution):

  1. Current working directory
  2. Project root (detected by package.json)
  3. User config directory (~/.config/branded-short-links/)

The first .env file found is loaded automatically. During first deploy, the CLI saves new tokens to ~/.config/branded-short-links/.env.

VariablePurpose
CLOUDFLARE_API_TOKENAPI token for Cloudflare Workers deployment.
NODE_ENVNode.js environment setting.
LOG_LEVELControls CLI log verbosity.
LOG_TIMEEnables timestamps in CLI log output.