---
title: CLI commands and access
description: Sign in, approve scoped access and manage workspaces, sites, surveys and responses from the terminal.
package: "@userreason/cli"
version: "0.2.2"
url: https://docs.userreason.com/cli/
updated: 2026-11-09
---

# CLI commands and access

The CLI supports people, scripts and coding agents. It requires Node 22.12 or newer and does not require a WorkOS API key.

```sh
npm install -g @userreason/cli
userreason --help
userreason login --open
userreason whoami
```

You can also run it without a global installation using `npx -y @userreason/cli@latest` followed by the same command arguments.

## Install through the wizard

The wizard installs the CLI in the application's `devDependencies`, alongside the
SDK. This gives teammates and project agents a shared version through the committed
package manifest and lockfile. From the application directory, run:

```sh
npx --no-install userreason --help
```

For pnpm use `pnpm exec userreason`; for Yarn use `yarn exec userreason`.

The wizard also offers a separate global installation for a convenient `userreason`
command across projects. Request it explicitly with:

```sh
npx -y @userreason/wizard@latest --global-cli
```

`--yes` alone does not accept global installation. `--skip-global-cli` skips the
offer. To update the project packages and the optional global CLI together, use
`--refresh --global-cli`. Refresh without that flag leaves the global installation
alone. Global installation uses npm's configured global prefix; if it fails, project
setup remains complete and the wizard shows a manual command. If the command is
not on PATH, fix npm's global PATH and restart your terminal or agent.

Both installations can coexist. Project agent instructions use the project-local
CLI to keep the version consistent even if the global version differs. Commit
accepted agent notes and skills so teammates' agents can discover those commands.

## Join an existing project

Clone the configured project and install its development dependencies using its
usual package manager. Then, from the application directory:

```sh
npx --no-install userreason login --open
npx --no-install userreason whoami --json
```

Use the pnpm or Yarn command above when appropriate. Sign in with your own account;
you need membership in the project's UserReason workspace and must approve your
own CLI access. The CLI detects the existing site's SDK initialization, so you do
not need to run SDK setup again or create another site. Credentials stay outside
the repository and are never shared with teammates.

## Authentication and grants

`login --open` signs in when needed and opens a consent page. All current and future workspaces and available permissions start selected. You can select particular workspaces, deselect permissions, and choose the duration (90 days by default). Every operation is limited by your current role in its workspace. Removing a membership, downgrading a role or revoking a grant takes effect immediately.

Credentials are kept in a per-user file by default, outside your project. Tokens are plaintext with owner-only file permissions (`0600`) on POSIX systems, and files are replaced atomically. Each API and authentication client uses a separate file under `$XDG_CONFIG_HOME/userreason/credentials/`, or `~/.config/userreason/credentials/`.

For OS storage, run `userreason login --open --credential-store keychain`. This uses macOS Keychain, Windows Credential Manager or Linux Secret Service through an optional native dependency. Explicit Keychain selection never silently falls back to a file. `--credential-store file` selects file storage; `UR_CREDENTIAL_STORE` also accepts `file` or `keychain`. Precedence is command flag, environment variable, saved selection, then file storage. Login saves the selection for the chosen API environment.

Existing Keychain sessions are not automatically copied into files. Reuse one with `--credential-store keychain`, or log in once with `--credential-store file` for the new default. The wizard accepts the same storage option for ongoing CLI access.

Valid tokens are read without a filesystem lock. Refreshing an expired token needs a lock, local write access and network access. Local failures such as `lock_failed`, `read_failed`, `write_failed`, `native_addons_blocked` or `network_blocked` require the named local capability; approving broader workspace permissions will not fix them.

An account connection can keep you signed in with no operational permissions. It cannot read or change workspace data until you approve the relevant permissions.

Use `userreason access --open` to review new permissions or renew access. Existing grants keep their original limits. `--no-wait` returns a pending request; `grant status --id REQUEST_UUID --wait` resumes waiting. For an intentionally restricted connection, use `grant request --workspace WORKSPACE_UUID --site SITE_UUID --scope site:read --wait` and approve the printed link.

| Scope | Allows |
| - | - |
| `workspace:create`, `workspace:read` | Workspace creation or reading. |
| `site:create`, `site:read`, `site:update` | Site creation; reading surveys, audiences, events, results, responses, users and eligibility; configuration changes such as the frequency policy. |
| `survey:write` | Editing survey content and rules. |
| `campaign:publish` | Activating and managing published delivery. |

Repeat `--scope` or supply comma-separated scopes. A grant request can include multiple `--site` values. Installation access from the wizard does not authorize publishing surveys.

`logout` removes credentials from the selected local store. Revoke approved access in the dashboard when you also want to stop that grant on the server.

## Offline command discovery

Find commands and exact usage from the installed package without login, network access or credential reads:

```sh
userreason cli search "create a feedback survey"
userreason cli get "prompt create"
userreason cli list
userreason docs get /cli/
userreason docs search "publish survey" --offline
```

Discovery results are JSON, including command usage, scopes and notes. Search returns up to five matches; `--limit` accepts 1–20. The bundled reference follows the installed CLI version. `docs get /cli/ --live` reads the hosted version instead. The offline catalog covers CLI commands, not the full SDK documentation.

## Project targeting

From an application directory, the CLI reads a literal `UserReason.init({siteId, apiBaseUrl})` in its browser entry or generated initialization file. It resolves that exact site's workspace through the authenticated API, even if browser origins are restricted. `whoami --json` reports the API, project target and access status. No project configuration file is created.

Commands such as `userreason prompt list` and `userreason site activity` can omit `--workspace` and `--site`. Explicit flags override detection; an explicit workspace never inherits a different project's site. Dynamic or multiple conflicting initializations need explicit flags. Missing access produces an error and never selects another available site.

The SDK's API URL chooses production or development. `--dev` or `--api-url` can select the API for explicit targets. Customer site environment is a separate setting. Ongoing access can create more than one workspace; a new workspace is added to a selected-workspace connection. Legacy one-workspace creation grants retain their previous behavior.

## Workspaces and sites

| Command | Purpose |
| - | - |
| `workspace list` | List your available workspaces. |
| `workspace create --name NAME` | Create a workspace with approved access. |
| `site list --workspace UUID` | List sites in a workspace. |
| `site create --workspace UUID --name NAME` | Create a site. |

For site creation, `--environment development` or `production` chooses the customer site's environment. Production is the default. Origins are unrestricted by default; repeat `--origin https://app.example.com` to add exact origin restrictions. Development sites can include local origins.

Creation supports `--request-id UUID` and `--workspace-id UUID` or `--site-id UUID` when you need stable IDs for an uncertain retry.

## Surveys

Surveys use the existing `prompt` command group. Command names, API fields such as `prompt_id`, and MCP tool names are unchanged.

All survey commands use the detected project target or explicit `--workspace UUID --site UUID`. Each command uses one site. See [Your first survey](https://docs.userreason.com/get-started/first-prompt/index.md) for a complete runnable sequence and JSON file.

| Command | Required additional arguments |
| - | - |
| `prompt list` | Optional `--limit` and `--after`. |
| `prompt get PROMPT_UUID` | None. |
| `prompt create --file prompt.json` | Optional `--id UUID` to choose the survey ID. |
| `prompt validate --file prompt.json` | Check a draft without saving or publishing. Optional `--context-file EXAMPLE.json` supplies `application_context`, `local_events` and `client_capabilities`. |
| `prompt update PROMPT_UUID --file prompt.json` | `--revision N`. |
| `prompt publish PROMPT_UUID` | `--revision N`. |
| `prompt pause PROMPT_UUID` | `--revision N`. |
| `prompt resume PROMPT_UUID` | `--revision N`. |
| `prompt archive PROMPT_UUID` | `--revision N`. |
| `prompt responses PROMPT_UUID` | Optional `--limit` and `--after`. |

Create and update require a **complete** [survey definition](https://docs.userreason.com/prompts/definition/index.md), not a patch. Read the current revision with `prompt get` before every mutation. Revisions are positive decimal strings and change after mutations. Publishing is explicit; editing a draft does not alter live delivery.

CLI 0.1.1 or later supports `results experiments PROMPT_UUID` with optional `--run UUID`, `--all-attempts` and `--reported-only`. `responses list` accepts `--run UUID` and `--variant ID`; a variant requires a run. See [Survey experiments](https://docs.userreason.com/prompts/experiments/index.md) for a complete definition, report semantics and examples. Use [Writing useful surveys](https://docs.userreason.com/prompts/survey-quality/index.md) for methodology; runtime output focuses on the current configuration and action.

Survey results include dashboard URLs in `links`: `edit` to review the draft, `results` for its overview, and `responses` for its answers. Archived surveys omit `edit`. The URLs use the same UserReason environment as the API.

Pagination limits are 1–100, default 50. `--after` accepts the returned cursor UUID. Survey mutations accept `--request-id UUID` for idempotent retry.

If a mutation times out, retry with the same input, survey ID and request ID printed in the error. If the desired input has changed, read the current state first and make a new request. On a revision conflict, reread and review the change rather than blindly retrying with a newer revision.

## Saved audiences

A [saved audience](https://docs.userreason.com/prompts/targeting/index.md#saved-audiences) is shared by the surveys that name it. These commands use the project target or explicit `--workspace UUID --site UUID`.

| Command | Required additional arguments |
| - | - |
| `audience list` | Optional `--limit` and `--after`. |
| `audience get AUDIENCE_UUID` | None. |
| `audience create --file audience.json` | Optional `--id UUID` to choose the audience ID. |
| `audience update AUDIENCE_UUID --file audience.json` | `--revision N`. |
| `audience publish AUDIENCE_UUID` | `--revision N`. |
| `audience discard AUDIENCE_UUID` | `--revision N`. Drops the draft of a published audience. |
| `audience archive AUDIENCE_UUID` | `--revision N`. |

The file holds `name`, an optional `description` and the `rule`:

```json
{
  "name": "Trial users",
  "description": "People on a trial plan",
  "rule": { "type": "field", "source": "trait", "key": "plan", "comparison": { "operator": "eq", "value": "trial" } }
}
```

Create and update save a draft that reaches nobody. **Publishing changes every live survey that follows the audience, at once**: read `used_by` from `audience get` first. A survey follows one with `"saved_audience": { "audience_id": "AUDIENCE_UUID" }` in its `rules`.

## Results and responses

These read what the dashboard shows and need `site:read`. All use the project target or explicit `--workspace UUID --site UUID`.

| Command | Reads |
| - | - |
| `results overview` | The site's numbers for the period against the one before: shown, started, completed, response rate, and each survey. |
| `results prompt PROMPT_UUID` | One survey: its funnel, every question with its answers, where people stopped and, for a flow, routes and endings. |
| `results breakdown --by DIMENSION` | Results split by `country`, `language`, `device_type`, `os` or `browser`. Add `--prompt-id UUID` for one survey. |
| `responses list` | Responses with answers in words, newest first. Filters: `--prompt-id UUID`, `--user UUID`, `--search TEXT`. |

`--days` is `1`, `7`, `30` (default) or `90`, and `--time-zone Europe/Amsterdam` sets where a day starts. `--country NL` and one `--segment key=value` (such as `--segment browser=Chrome`) narrow results and responses. `responses list` pages with `--limit` and the returned `--cursor`.

## Users and eligibility

| Command | Reads |
| - | - |
| `user list` | People seen on the site. `--kind all\|identified\|anonymous\|responded`, `--search TEXT`, `--days N`, `--country NL`, `--cursor`. |
| `user get USER_UUID` | One person: properties, linked anonymous visits and what they did with each survey. |
| `user eligibility USER_UUID` | Why this person does or does not get each published survey right now, [check by check](https://docs.userreason.com/prompts/targeting/index.md#why-a-person-does-or-does-not-get-a-survey), with the limit that holds a survey back and until when. |

`user eligibility USER_UUID --file audience.json` also tries an audience that is not published yet on that person. The file is an audience file or the rule alone; nothing is saved.

These commands return personal data. They need `site:read`, like responses.

## Events, site activity and members

| Command | Purpose |
| - | - |
| `event list` | The site's event definitions. |
| `event overview` | Events received in the period, registered and discovered, with counts. `--days N`. |
| `event create --file event.json` | Register an event. Optional `--id UUID`. Without an explicit collection policy, `--purpose business` (default) collects backend history; `--purpose activity` keeps occurrences local. |
| `event update EVENT_UUID --file event.json` | Change its properties or collection. `--revision N`. |
| `site activity` | Whether the SDK is connected: the last session, event and display received. |
| `prompt history` | When the site's survey history starts. |
| `member list --workspace UUID` | Workspace members and roles. Needs `workspace:read`. |

An event file holds `event_key` (for create), `properties` and `collection`:

```json
{
  "event_key": "export.completed",
  "properties": { "format": { "type": "string", "required": false } },
  "collection": { "memory": true, "local": false, "server": true, "raw_retention_days": 30, "history_retention_days": 90 }
}
```

Server collection stores visitor history. Turn it on only when a person asked for it.

## Site frequency

The site's [frequency policy](https://docs.userreason.com/prompts/targeting/index.md#the-sites-policy) applies to every live survey at once. Changing it needs `site:update` and the owner or admin role.

| Command | Purpose |
| - | - |
| `site frequency get` | The policy and the site's `revision`. `frequency_policy` is `null` while the site uses the starting values. |
| `site frequency set --file policy.json --revision N` | Replace the policy. |
| `site frequency reset --revision N` | Return to the starting values. |
| `site events preview --mode explicit` | Review a migration to business-event and local-activity policies. Optional `--file LIMITS.json` supplies collection limits. |
| `site events set --mode explicit --revision N` | Apply the reviewed mode and limits. Supply `--confirmation-token TOKEN` when the preview requires it. Existing registered policies are preserved. |

```json
{
  "min_gap_seconds": 86400,
  "rolling": { "max_prompts": 2, "window_seconds": 2592000 },
  "defaults": {
    "max_shown": "3",
    "after_seen_seconds": 604800,
    "after_dismissed_seconds": 1209600,
    "after_completed": { "type": "never" },
    "after_screen_out": { "type": "never" }
  }
}
```

`rolling` may be `null` for no cap on surveys per person.

## Queries and commands

`query` reads `sites`, `surveys`, `campaigns`, `prompts`, `audiences`, `events`, `event_capture`, `responses` or `audits`:

```sh
userreason query --workspace WORKSPACE_UUID --site SITE_UUID --resource events --limit 50 --json
```

Optional filters are `--id UUID`, pagination `--after UUID`, and `--prompt-id UUID` for responses. `command --file COMMAND.json` sends a complete versioned management command for workflows beyond the survey helpers. JSON input files must contain an object, be valid UTF-8 and be at most 64 KB. Prefer the survey helpers for survey lifecycle work.

## Public documentation

These commands need no login or grant:

```sh
userreason docs search "How do I display a survey?" --limit 5
userreason docs get /sdk/show/
```

Search limits are 1–20. If a network request fails, search falls back to the bundled CLI catalog and labels its result `source: "bundled"`, with a warning. Use `--offline` to skip the network, or `--live` to require hosted results. SDK documentation still requires network access. `docs get` accepts a docs URL or path and returns Markdown. `--docs-url https://docs-dev.userreason.com` selects the development docs; it does not change the management API environment. See [Agents](https://docs.userreason.com/agents/index.md) for MCP and the Markdown endpoints.

## Global options and automation

| Option | Meaning |
| - | - |
| `--json` | Compact JSON output for scripts. Errors are JSON on stderr with a nonzero exit code. |
| `--dev` | Select UserReason's development API environment. This is separate from a customer's site environment. |
| `--api-url ORIGIN` | Override the API origin; HTTPS or loopback HTTP. |
| `--client-id CLIENT_ID` | Select the authentication client. |

Management results are JSON even without `--json`, formatted for readability. Documentation search is human-readable by default, and `docs get` prints Markdown. Use `--json` when parsing them programmatically. Scripts should check the exit code and handle approval requirements, errors and retry IDs explicitly.

A new ongoing consent replaces earlier grants for that client and login, so narrowing permissions takes effect immediately. Other signed-in devices keep their own connections.

## Permanent deletion

Owners and admins with `resource:delete` can permanently remove a resource and its associated data. These commands preview by default:

```sh
userreason workspace delete WORKSPACE_UUID --preview
userreason site delete SITE_UUID --workspace WORKSPACE_UUID --preview
userreason prompt delete PROMPT_UUID --workspace WORKSPACE_UUID --site SITE_UUID --preview
```

To confirm, repeat the selected command with `--confirm NAME --revision N --confirmation-token TOKEN`, replacing the values with the exact name, revision and token from its preview. Quote names containing spaces. Save a `--request-id UUID` and reuse it with the same request on an uncertain retry. Follow cleanup with `userreason deletion status --workspace WORKSPACE_UUID --id JOB_UUID`.

Read [Delete resources](https://docs.userreason.com/get-started/delete-resources/index.md) for consequences, references, permissions and background cleanup. Legacy generic `site.delete` and `survey.delete` commands keep their disable/archive meaning.

## Development conversations

CLI 0.2.0 includes `workspace ai get`, `workspace ai set --file`, `results conversations`, and `conversation get`. They require a compatible, explicitly enabled backend and workspace AI configuration; production conversations remain separately gated. Existing `prompt create`, `update`, `validate` and `publish` commands accept the full [conversation definition](https://docs.userreason.com/prompts/conversations/index.md) in an enabled development environment. Use the installed CLI's `cli get` for exact usage.
