Skip to main content
@traffical/cli manages your Traffical configuration as code. You define parameters, events, and metrics in a .traffical/ directory, version-control them alongside your application, and sync with the platform with push, pull, and status.

Why config-as-code

  • Single source of truth — parameter and event definitions live in your repo, reviewed in pull requests like any other code.
  • No drift — definitions you push become synced: read-only in the dashboard, so the repo and the platform can’t disagree.
  • Typed events — generate TypeScript types from your event schemas so invalid track() calls fail at compile time.
  • CI-enforceabletraffical status exits non-zero on drift, so you can gate merges on the repo and platform being in sync.
Policies, allocations, and experiment decisions still live in the dashboard — the CLI owns the definitions, not the rollout state.

Installation

npm install -g @traffical/cli
# or run without installing
bunx @traffical/cli init
Requires Node.js 18+.

Quickstart

1

Initialize

From your project root, scaffold the .traffical/ directory and link a project:
traffical init
init logs you in, lets you pick an org and project, writes config.yaml and project.yaml, creates a public SDK key, and drops example code for your framework.
2

Edit your config

Add or change parameters and events in .traffical/config.yaml. See the configuration file reference for every field.
3

Push to Traffical

traffical push
4

Check for drift

traffical status

Authentication

For interactive use, log in once with the browser-based device flow:
traffical login
This opens your browser, asks you to confirm a code, and stores a session at ~/.config/traffical/auth.json (mode 0600). The session holds a refresh token and renews access tokens automatically, so you rarely log in again.
traffical whoami            # show the active identity and linked project
traffical whoami --verify   # live-check the session against the server
traffical logout            # remove the local session
whoami without --verify reports the cached session. A cached session can still be reported as authenticated after it has ended server-side — use --verify when you need a definitive answer.

Credential precedence

The CLI resolves a bearer token in this order:
  1. --api-key <key> on the command line
  2. TRAFFICAL_API_KEY environment variable (org-scoped key — the CI path)
  3. TRAFFICAL_API_TOKEN environment variable (pre-minted JWT, for agents)
  4. The device-flow session from traffical login
  5. A legacy ~/.trafficalrc profile (--profile <name>) — deprecated
For CI, set TRAFFICAL_API_KEY and skip login entirely.
# Headless / agent login with a pre-minted token
traffical login --token "$JWT"
# Print the URL + code instead of opening a browser
traffical login --no-browser

Selecting a project

A repo is linked to exactly one Traffical project, recorded in .traffical/project.yaml.
traffical link                      # interactive org + project picker
traffical link --org acme --project mahally
traffical unlink                    # remove the link (leaves config.yaml)
When a flag is omitted, the CLI prompts: a select list for ≤10 options, a search box beyond that. Pass --force to re-link a repo that’s already linked. Manage orgs and projects directly:
traffical org list                  # orgs you belong to
traffical org use <key>             # default org for commands that need one

traffical project list              # projects in the active org
traffical project create <name> --link
traffical project use <key>         # alias of `link --project <key>`

Syncing configuration

1

status — see the difference

traffical status
Shows what’s synced, what has local changes to push, and what exists only in the dashboard. Exits with code 10 when there’s drift, so it doubles as a CI check.
Connected to: Salla PoC/Mahally (proj_ST6qGDbR)

Parameters
  Synced: 7 parameters
  Dashboard-only: 2 parameters
    ui.sees-feature-y (created 5/20/2026)

Events
  Synced: 4 events

Metrics
  Dashboard-only: 4 metrics
2

push — repo → Traffical

traffical push [--dry-run] [--prune]
Creates new definitions and updates existing synced ones. Pushed definitions become read-only in the dashboard.
  • --dry-run — validate and print the diff without applying.
  • --prune — archive synced definitions that have been removed from the file. Without it, removals stay on the platform.
3

pull — Traffical → repo

traffical pull [--include-types]
Downloads synced parameters, events, and property groups into config.yaml. Dashboard-only definitions stay in the dashboard until you import them. --include-types runs generate-types afterwards.
4

sync — both directions

traffical sync [--all] [--dry-run] [--prune]
Pushes local changes and pulls new remote definitions in one pass. On conflict, local wins. --all syncs every config file in the repo.

Importing dashboard definitions

Definitions created in the dashboard are dashboard-only until you adopt them into code:
traffical import param ui.accent_color   # one parameter
traffical import param 'ui.*'            # wildcard
traffical import metrics --all           # all metrics → metrics.yaml
traffical import metrics add_to_cart_rate

Type-safe events

Generate TypeScript types from your event definitions so invalid event names and properties become compile errors:
traffical generate-types          # writes .traffical/traffical.generated.ts
traffical generate-types -o src/traffical.generated.ts
This emits a TrafficalEventProperties map — event name → typed property shape. Wrap your client’s track:
import type { TrafficalEventProperties } from "./traffical.generated";

type TypedTrack = <E extends keyof TrafficalEventProperties>(
  event: E,
  options: { unitKey: string; properties?: TrafficalEventProperties[E]; decisionId?: string }
) => void;

export const track = traffical.track.bind(traffical) as TypedTrack;
track("add_to_cart", { unitKey: "user_789", properties: { product_id: "p_1" } }); // ✅
track("add_to_cart", { unitKey: "user_789", properties: { unknown: true } });      // ❌ compile error
Run it after every pull (or in CI) to keep types in sync. See Type-safe events for the full flow.

CI/CD integration

# .github/workflows/traffical.yml
name: Traffical
on: [pull_request]
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v1
      - run: bunx @traffical/cli status   # exits 10 on drift
        env:
          TRAFFICAL_API_KEY: ${{ secrets.TRAFFICAL_API_KEY }}

Command reference

CommandDescription
loginAuthenticate via browser (OAuth device flow).
logoutRemove the local session.
whoamiShow the active identity and linked project.
initLog in, link a project, and scaffold .traffical/.
link / unlinkLink the repo to a project / remove the link.
org list / org useList orgs / set the default org.
project list / create / useManage projects in the active org.
statusShow drift between local and remote.
pushSend local definitions to Traffical.
pullPull synced definitions into the repo.
syncBidirectional sync (local wins on conflict).
import param / import metricsAdopt dashboard definitions into code.
generate-typesGenerate TypeScript types from event definitions.

Global options

OptionDescription
-c, --config <path>Path to the config file (default .traffical/config.yaml).
-b, --api-base <url>Override the API endpoint.
-j, --format <fmt>human (default) or json.
-q, --quietSuppress non-essential output.
-p, --profile <name>Legacy ~/.trafficalrc profile (deprecated).
Environment variables: TRAFFICAL_API_KEY, TRAFFICAL_API_TOKEN, TRAFFICAL_API_BASE.

Exit codes

CodeMeaning
0Success.
1Validation error in config.
2Authentication error (not logged in / token invalid).
3Network or API error.
4Not linked (no project.yaml).
10Drift detected (status).
11Experiment needs attention.

Next steps

Configuration file

Every field in config.yaml, project.yaml, and metrics.yaml.

Parameters

Typed values with defaults.

Type-safe events

Codegen, SDK typing, and dev-mode validation.

Quickstart

Resolve a parameter and track an event.