CLI Reference
The Framedash CLI provides terminal access to telemetry data, analytics, and project management. It integrates into CI/CD pipelines for automated map uploads and content syncing.
Installation
Section titled “Installation”Requires Node.js and npm. Install it globally, or run it on demand with npx without installing.
# Install globallynpm install -g @framedash/cli
# Or run without installingnpx @framedash/cli --helpAuthentication
Section titled “Authentication”Provide the API key via an environment variable, or read it from a file:
# Environment variableexport FRAMEDASH_API_KEY=fd_your_api_key_here
# Or from a file (use - to read from stdin)framedash status --api-key-file ./read.keyVerify your key is valid and see the bound project:
framedash authThe CLI can also sign in interactively with framedash login, which stores an OAuth session so you do not need to pass a key for subsequent non-SQL analytics reads.
Common Options
Section titled “Common Options”Most commands accept these options:
| Option | Description |
|---|---|
--api-key <key> | API key (or FRAMEDASH_API_KEY env) |
--api-key-file <path> | Read the API key from a file (- for stdin) |
--project-id <uuid> | Project ID (or FRAMEDASH_PROJECT_ID env) |
--base-url <url> | API host URL (default: https://app.framedash.dev) |
--format <fmt> | Output format: json, table, csv (default: json) |
-h, --help | Show help |
Commands
Section titled “Commands”This page covers the commands you reach for most often. Run framedash --help (or framedash <command> --help) for the authoritative, version-specific list.
framedash auth
Section titled “framedash auth”Verify your API key and show the bound project.
framedash authOptions: --api-key, --base-url, --format
With --format json, stdout contains only the JSON document, so it is safe to pipe to tools such as jq. Validation and credential-source status remain visible on stderr.
framedash login / framedash logout
Section titled “framedash login / framedash logout”framedash login signs you in interactively with the OAuth 2.1 authorization code flow and PKCE (S256). It opens your system browser to {base-url}/oauth/authorize with a loopback redirect and waits up to 5 minutes for you to approve.
framedash login| Option | Description |
|---|---|
--scopes <list> | Space-delimited scopes to request (default analytics:read) |
--no-browser | Print the authorization URL instead of opening a browser |
--base-url <url> | Authorization server (default https://app.framedash.dev) |
Tokens are stored in ~/.config/framedash/credentials.json (honoring XDG_CONFIG_HOME; the same path convention applies on Windows), keyed by server origin, and refreshed automatically. Token values are never printed.
framedash logout revokes the token server-side (best effort) and deletes the local credentials for the resolved base URL. Pass --all to clear every origin. API keys are unaffected.
framedash logoutframedash logout --allAn explicit --api-key, --api-key-file, or FRAMEDASH_API_KEY always takes precedence over a stored login, so CI should authenticate with FRAMEDASH_API_KEY rather than framedash login. Grants made through login can be reviewed and revoked in the dashboard under Settings -> Connected apps.
framedash projects list
Section titled “framedash projects list”List the projects you can access (id, name, createdAt). Works with API keys that carry the analytics:read scope, or with OAuth logins, and needs no --project-id. An Ingest key with only events:write cannot list projects. Available from @framedash/cli 0.1.4.
framedash projects list --format tableSet the output with --format json|table|csv.
framedash status
Section titled “framedash status”Show project health status.
framedash statuskpis.fetchedAt is the Unix timestamp in milliseconds when the KPI snapshot was queried. Status normally uses the server cache; pass --fresh to bypass it when CI or troubleshooting needs a newly queried snapshot. This option is not included in @framedash/cli 0.1.7; install a later release and confirm that it appears in framedash status --help before using it.
framedash dashboard
Section titled “framedash dashboard”Show dashboard KPIs (DAU, MAU, sessions, events).
framedash dashboard --days 30| Option | Values | Default |
|---|---|---|
--days | 7, 14, 30, 90 | 30 |
framedash retention
Section titled “framedash retention”Show player retention cohorts (D1, D7, D30).
framedash retention --days 14| Option | Values | Default |
|---|---|---|
--days | 7, 14, 30, 90 | 30 |
framedash funnel
Section titled “framedash funnel”Analyze event funnels to measure player conversion between steps.
framedash funnel --steps "player_spawn,player_death,player_respawn"| Option | Description | Default |
|---|---|---|
--steps | Comma-separated event names (required, 2-8 steps) | — |
--window | Time window in seconds (3600, 21600, 86400, 604800) | 86400 |
--days | Time period (7, 14, 30, 90) | 30 |
framedash builds
Section titled “framedash builds”List build IDs seen for the project, newest first. Use this to pick build IDs for framedash perf-diff.
framedash builds --days 30| Option | Values | Default |
|---|---|---|
--days | 7, 14, 30, 90 | 30 |
framedash perf-diff
Section titled “framedash perf-diff”Compare two builds’ P50/P95 performance (frame time, memory, GPU time). With --fail-on-regression, the command exits 1 when the candidate regressed beyond the threshold.
framedash perf-diff --baseline "$BASE_SHA" --candidate "$GITHUB_SHA" \ --threshold 5 --fail-on-regression| Option | Description |
|---|---|
--baseline <id> | Known-good build_id (required) |
--candidate <id> | New build_id under test (required) |
--metric <name> | Restrict the gate to one metric: frame_time, memory, gpu_time, io.read_bytes, io.read_time_ms, io.read_ops, load_time_ms, or mem.vram (default: all). load_time_ms needs SDK map-load timing; mem.vram needs SDK VRAM sampling |
--threshold <pct> | Allowed regression percentage. Default is 0 |
--fail-on-regression | Exit non-zero when a regression is detected |
--days <n> | Time period: 7, 14, 30, 90 (default 30) |
--map <id> | Restrict the comparison to one map |
--platform <name> | Restrict the comparison to one platform |
--baseline and --candidate must be different build IDs. The CLI rejects identical IDs so a misconfigured CI job fails fast instead of comparing a build against itself.
framedash run-profile-test
Section titled “framedash run-profile-test”Run a profiling build end-to-end for CI: export the FRAMEDASH_* automated-session variables, launch your game/profiling command, wait for its telemetry to ingest, then run the perf-diff gate against a baseline. The turnkey companion to builds and perf-diff.
framedash run-profile-test \ --command "./Build/Game.exe -nullrhi -ExecCmds='Automation RunTest Perf'" \ --scenario nightly --api-key-file ci-read.key \ --baseline "$BASE_SHA" --threshold 5 --fail-on-regression| Option | Description |
|---|---|
--command <cmd> | Game/profiling command to launch via the shell (required) |
--build-id <id> | Candidate build_id (default: --commit, else git HEAD) |
--branch <name> | Default: git rev-parse --abbrev-ref HEAD |
--commit <sha> | Default: git rev-parse HEAD |
--scenario <name> | Test scenario label |
--ingest-timeout <s> | Max seconds to wait for fresh telemetry (default 180) |
--poll-interval <s> | Seconds between ingest polls (default 5) |
--skip-wait | Skip the ingest wait |
--baseline <id> | Known-good build_id to gate the candidate against |
The --baseline, --metric, --threshold, --fail-on-regression, --days, --map, and --platform flags behave exactly as in framedash perf-diff.
The launched command inherits FRAMEDASH_BUILD_ID / FRAMEDASH_GIT_BRANCH / FRAMEDASH_GIT_COMMIT / FRAMEDASH_TEST_SCENARIO. Once an SDK calls BeginAutomatedSessionFromEnvironment(), every event is tagged automatically, with no per-event tagging code. See CI Profiling for the full setup.
framedash query
Section titled “framedash query”Execute a SQL query against telemetry data.
# Inline SQLframedash query "SELECT event_name, count() FROM events GROUP BY event_name"
# From a fileframedash query --file ./queries/daily-active.sql| Option | Description |
|---|---|
--file <path> | Read SQL from a file instead of inline argument |
--limit <n> | Maximum rows to return |
framedash alerts
Section titled “framedash alerts”Manage performance alert rules.
# List all alert rulesframedash alerts list
# Create a new alert ruleframedash alerts create --name "FPS Alert" --map-id <uuid> \ --threshold-profile-id <uuid> --metric fps --threshold-level warn \ --fail-percentage 20 --evaluation-days 7 --cell-size 25 \ --cooldown-minutes 60
# Update an alert ruleframedash alerts update <alert-id> --name "Updated Alert"
# Deactivate an alert ruleframedash alerts delete <alert-id>framedash threshold-profiles
Section titled “framedash threshold-profiles”Manage the performance threshold profiles that alert rules reference (the warn/good bands per metric).
Newly created projects start with one automatically created profile named Default (all-wildcard device filters and built-in default thresholds), so alert rules can reference a profile right away; customize it or add more later.
# List threshold profilesframedash threshold-profiles list
# Create a threshold profileframedash threshold-profiles create --name "Console 60fps" \ --fps-good 60 --fps-warn 30 --platform windows
# Delete a threshold profileframedash threshold-profiles delete <profileId>framedash threshold-profiles create (@framedash/cli 0.1.7 and later) adds a profile. --name is required (max 100 characters). Threshold pairs are optional and fall back to the built-in defaults when omitted: --fps-good / --fps-warn (FPS), --frame-time-good / --frame-time-warn (ms), --memory-good / --memory-warn (MB), and --gpu-time-good / --gpu-time-warn (ms). FPS is higher-is-better (good above warn); the others are lower-is-better (good below warn). Optional device filters (--platform, --resolution such as 1920x1080, --build-config, --gpu, --storage) scope the profile, and an omitted filter acts as a wildcard. Creation needs an API key with the resources:write scope, or an OAuth session from a framedash login run with --scopes including resources:write (the default login requests analytics:read only); the server rejects a duplicate name or an identical device-filter combination (all five filters equal) with 409, while a partially overlapping combination succeeds and the command reports the overlapping profile names. On success the CLI prints Threshold profile created and the new profile.
framedash threshold-profiles delete <profileId> (@framedash/cli 0.1.8 and later) removes a profile. The command needs an API key with the resources:write scope, or an OAuth session from a framedash login run with --scopes including resources:write (the default login requests analytics:read only). A profile that is still referenced by an alert rule (as a primary threshold profile or as a bundle member) is rejected with 409; deactivating a rule does not unblock the deletion, so re-point the referencing alert rules at another profile with framedash alerts update <alert-id> --threshold-profile-ids <...> first.
framedash maps
Section titled “framedash maps”Manage game maps.
# List mapsframedash maps list
# Delete a map by map identifierframedash maps delete <map-id>The identifier here is the mapId slug you assigned when capturing the map, not the internal UUID primary key.
framedash map-capture
Section titled “framedash map-capture”Upload captured map images. This command has its own option parser and does not use the shared global options.
# Preview what would be uploaded (dry run)framedash map-capture --input-dir ./captures --upload --dry-run
# Upload map capturesframedash map-capture --input-dir ./captures --upload \ --api-key fd_xxx --project-id <uuid>| Option | Description |
|---|---|
--input-dir <path> | Directory containing captured map images (required) |
--upload | Actually upload the captures (required to perform upload) |
--api-key <key> | API key for upload |
--project-id <uuid> | Target project |
--base-url <url> | API base URL |
--dry-run | Preview upload without sending |
--metadata-pattern <glob> | Only read matching JSON sidecars (for example *.capture.json) |
Input contract
Section titled “Input contract”--input-dir is scanned non-recursively. By default every *.json file is treated as a capture metadata sidecar. If the directory also contains unrelated JSON, use --metadata-pattern '*.capture.json' and name sidecars accordingly. The --metadata-pattern option is not included in @framedash/cli 0.1.7; install a later release and confirm that it appears in framedash map-capture --help before using it. The command reads each selected JSON file, validates it, and uploads the image it references. A sidecar points at its image through image_path, resolved relative to the input directory. Absolute paths and paths that escape the directory are rejected; subdirectories inside the input directory are allowed. Supported image formats are .png, .jpg, .jpeg, and .webp.
Required fields:
| Field | Type | Notes |
|---|---|---|
version | string | Must be the literal "1.0" |
map_id | string | 1-128 characters |
image_path | string | Path to the image, relative to --input-dir |
image_dimensions | object | { "width", "height" }, positive integers |
world_bounds | object | { "min": {x,y,z}, "max": {x,y,z} }, finite numbers. max.x must exceed min.x and max.y must exceed min.y; z is unconstrained. Values are engine world units (for example, centimeters in Unreal Engine) |
Optional fields:
| Field | Type | Notes |
|---|---|---|
projection | string | Free text |
capture_axis | string | Free text |
coordinate_system | string | Free text |
engine | string | Free text |
build_id | string | Up to 255 characters |
captured_at | string | ISO 8601 datetime |
Worked example. Place a sidecar arena.json next to its image arena.png (a 1024x1024 top-down capture) in ./captures:
{ "version": "1.0", "map_id": "arena_dust", "image_path": "arena.png", "image_dimensions": { "width": 1024, "height": 1024 }, "world_bounds": { "min": { "x": -8192, "y": -8192, "z": 0 }, "max": { "x": 8192, "y": 8192, "z": 2048 } }, "engine": "UE5", "captured_at": "2026-07-16T09:30:00Z"}Validate first with --dry-run. It needs no credentials and uploads nothing:
framedash map-capture --input-dir ./captures --dry-runThe dry run prints one line per file (map_id=..., image=..., bounds=[minX,minY]->[maxX,maxY], size=WxH), then a Done: N succeeded, M failed summary, and exits 1 if any file failed validation. Once it reports no failures, upload for real. The upload is a multipart POST to /api/v1/maps/upload and needs an API key with the resources:write scope:
framedash map-capture --input-dir ./captures --upload \ --api-key fd_xxx --project-id <uuid>framedash content
Section titled “framedash content”Manage the content registry (items, weapons, event types, etc.).
# List content entriesframedash content list
# Import content from a JSON fileframedash content import ./game-content.json
# Delete by UUIDframedash content delete <uuid>
# Delete by type and content IDframedash content delete --type weapon --content-id ak47Import JSON may be an array or { "entries": [...] }. Every entry requires non-empty string fields contentType, contentId, and displayName. Optional description and category are strings or null; metadata is an object or null. Validation errors identify the 1-based entry number before any request is sent.
Rate limits
Section titled “Rate limits”The hourly API rate limit is enforced per account (tenant) and shared across every project and API key the account owns. The free plan allows 100 requests per hour; higher plans allow more. Because the budget is shared, parallel CLI invocations and separate keys all draw from the same pool.
On a 429, honor the Retry-After header on every response rather than scheduling around the X-RateLimit-Reset timestamp. Both values are derived from a sliding window, so they can understate the real wait immediately after the advertised reset, and retrying exactly at the reset time may hit another 429.
Usage in CI/CD
Section titled “Usage in CI/CD”GitHub Actions example:
- name: Upload maps and import content env: FRAMEDASH_API_KEY: ${{ secrets.FRAMEDASH_API_KEY }} FRAMEDASH_PROJECT_ID: ${{ vars.PROJECT_ID }} run: | framedash map-capture --input-dir ./map-captures --upload framedash content import ./game-content.jsonFor Jenkins and TeamCity examples, see the CI/CD Integration Guide.
Next Steps
Section titled “Next Steps”- Events Schema: columns and rules for
framedash query - Troubleshooting: confirm events arrived
- API Reference: REST API details
- CI/CD Integration: Jenkins and TeamCity pipeline examples
- CI Profiling: Automated performance profiling setup