> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apsio.io/llms.txt
> Use this file to discover all available pages before exploring further.

# The apsio CLI

> Install the apsio command-line tool, read issues, sessions and releases, and upload symbols from a terminal or CI.

`apsio` reads Apsio from a terminal and uploads debug symbols so crashes are symbolicated.
It is in development: version 0.3.0 reads issues, sessions, release health and missing
symbols through the [read API](/read-api), and uploads dSYMs, Android R8 mappings, NDK
symbols and React Native source maps. Coding agents use the same
commands (see [Agents](/agents)).

## Install

Homebrew, npm and prebuilt release binaries are not published yet. Until they are, build it
from source with Rust 1.94 or later:

```sh theme={null}
cargo install --locked --git https://github.com/Apsio/apsio-cli
apsio --version
```

## Sign in

```sh theme={null}
apsio login --with-token < token.txt
```

`--with-token` reads a token from standard input, checks it against the server and stores it
in your user configuration. `apsio logout` removes it.

Today there are two kinds of token, and one `APSIO_TOKEN` cannot do both jobs:

| Token | Used by |
| - | - |
| [Project token](/read-api#authentication) (`apsio_pt_v0...`) | The read commands: `issues`, `issue`, `sessions`, `releases`, `symbols missing` |
| [Upload token](/symbols/upload#upload-tokens) | `apsio upload dsyms`, `apsio upload mappings`, `apsio upload ndk`, `apsio upload sourcemaps` |

When you need both, store the one you use most and give the other per command, for example
`APSIO_TOKEN="$PROJECT_TOKEN" apsio issues`. They become one project token from the console
when the console ships.

`apsio login` without a token starts a device sign-in in the browser. The Apsio sign-in
server for it is not live yet; until it is, the command says so and you use
`--with-token`.

## Commands

| Command | What it does |
| - | - |
| `apsio login --with-token` | Stores a token read from standard input |
| `apsio logout` | Forgets the stored token |
| `apsio issues` | Lists issues: crashes, handled errors, ANRs, hangs and abnormal exits |
| `apsio issue <id>` | Shows one issue: the symbolicated stack, breadcrumbs, releases, devices and the latest session |
| `apsio sessions <id>` | Shows a session's timeline: its logs and spans in time order |
| `apsio releases` | Shows release health per app and release |
| `apsio releases compare <base> <candidate>` | Compares two releases: crash-free rates, and the issues new or more frequent in the candidate |
| `apsio symbols missing <release>` | Lists the in-app images of a release that have no uploaded debug file: dSYM, R8 mapping, NDK library or source map |
| `apsio issue open <id>` | Prints the issue's console URL (also `apsio sessions open <id>`) |
| `apsio perf start` | App start percentiles by type, by release, OS version, device or iOS prewarming |
| `apsio perf screens` | Screens: loads, TTID and TTFD percentiles, and the hangs and ANRs on each |
| `apsio perf endpoints` | HTTP endpoints: requests, failure rates and latency percentiles |
| `apsio trace <id>` | One trace's spans, and the link to the same trace in your APM |
| `apsio upload dsyms <paths>...` | Uploads dSYMs from dSYM bundles, `.xcarchive` bundles or folders searched recursively. See [Upload dSYMs](/symbols/upload). |
| `apsio upload mappings <path> --build-id <id>` | Uploads an Android build's R8 or ProGuard mapping under its build id. See [Upload R8 mappings](/symbols/android). |
| `apsio upload ndk <dir> --build-id <id>` | Uploads an Android build's native libraries with debug information, one subdirectory per ABI. See [Upload NDK symbols](/symbols/android-ndk). |
| `apsio upload sourcemaps <map> --build-id <id>` | Uploads a React Native bundle's source map for its build. See [Upload React Native source maps](/symbols/react-native). |
| `apsio build-id` | Prints a new build id for an Android build |
| `apsio --version` | Prints the version |

Every command takes `--help`. `session` also works in place of `sessions`.

## Read issues, sessions and releases

The read commands call the [read API](/read-api) with your project token and print what the
console shows, as compact tables:

```sh theme={null}
apsio issues --since 24h --kind crash --sort users
apsio issue 3f9a0c2e7d1b4a6c8e0f1a2b3c4d5e6f
apsio sessions 7f3c9b02-5d1e-4a8b-9c0f-2e6a1d4be19a
apsio releases --since 30d
apsio releases compare 4.12.0 4.13.0
apsio symbols missing 4.13.0
apsio perf endpoints --sort errors --since 24h
apsio trace 4bf92f3577b34da6a3ce929d0e0e4736
```

* `apsio issues` filters with `--kind` (`crash`, `error`, `anr`, `hang`, `abnormal-exit`),
  `--release`, `--app` (an app id) and sorts with `--sort` (`last-seen`, `occurrences`,
  `users`).
* Time ranges: `--since` takes a duration ending now (`30m`, `24h`, `7d`, `2w`), or give
  `--from` and `--to` as RFC 3339 times or dates (`2026-10-01`, midnight UTC). A range covers
  at most 90 days. Without one, each command uses the API's default: the last 7 days, and 90
  days for one issue.
* Lists come in pages: a table ends with the `--cursor` value for the next page, and
  `--limit` sets the page size.
* `apsio releases compare` takes the release to compare against first, then the new one. The
  CLI computes it from release health and the issue lists of both releases, per app:
  crash-free sessions and users, abnormal exits, and the candidate's new issues and the
  issues that occur more often per 1000 sessions.
* `apsio perf start` breaks app start down with `--by` (`release`, `os`, `device`,
  `prewarmed`, `none`); `apsio perf screens` sorts with `--sort` (`loads`, `ttid`, `ttfd`);
  `apsio perf endpoints` sorts with `--sort` (`requests`, `errors`, `p90`) and filters with
  `--host`. All three take `--app` and `--release`, and cover at most 30 days.
* `apsio issue open` and `apsio sessions open` print a console URL to share. They need the
  organization id, which is in the console's URLs (`/o/<org>/...`): pass `--org` or set
  `APSIO_ORG`.

Text written by your app and its users, such as exception messages and breadcrumbs, is shown
quoted and escaped, under a note that says it is untrusted. No control character from the API
reaches your terminal.

## JSON for scripts and agents

| Flag | What it does |
| - | - |
| `--json` | Prints the API's JSON instead of a table. For `releases compare`, it prints the comparison; `apsio releases compare --help` describes its fields |
| `--jq <expr>` | Filters the JSON with a jq expression; jq is built in, so nothing else needs to be installed. The filter sees the response only, not the environment or files, and stops past 100,000 values or 64 MiB of output (exit code 2) |
| `-r` | With `--json` or `--jq`: prints strings without quotes |

```sh theme={null}
apsio issues --kind crash --jq '.issues[].id' -r
apsio issue 3f9a0c2e7d1b4a6c8e0f1a2b3c4d5e6f --jq '.latest.frames[] | select(.in_app) | "\(.file):\(.line)"' -r
apsio releases compare 4.12.0 4.13.0 --jq '.apps[] | {app_id, change, new: [.issues.new[].id]}'
```

JSON output escapes every control character, and `-r` removes them from the strings it
prints.

## Configuration

| Setting | Flag | Environment | Stored by `apsio login` |
| - | - | - | - |
| API URL (default `https://api.apsio.io`) | `--url` | `APSIO_URL` | Yes, when `--url` is given |
| Symbol upload URL (default `https://symbols.apsio.io`) | `--symbols-url` | `APSIO_SYMBOLS_URL` | Yes, when `--symbols-url` is given |
| Token | `--token` (`login` and the `upload` commands) | `APSIO_TOKEN` | Yes |
| Project id, for the read commands | `--project` | `APSIO_PROJECT` | Yes, when `--project` is given |
| Organization id, for console URLs | `--org` | `APSIO_ORG` | Yes, when `--org` is given |
| Console URL (default `https://app.apsio.io`) | | `APSIO_CONSOLE_URL` | No |

Flags win over the environment, which wins over the stored configuration. The `upload`
commands send symbols to the symbol upload URL, a service of its own; the read commands use the
API URL. When the API URL is on your machine (`localhost`), uploads default to
`http://localhost:18795`, the local symbol service. A token given as a
flag shows in shell history and the process list: in CI use `APSIO_TOKEN`, and on a laptop
use `apsio login --with-token`.

A project token names its project, so with one you can leave out `--project`. A token used on
another project's id is refused (exit code 3) with a hint naming the token's project.

The URL must use `https://`; plain `http://` is accepted only for `localhost`, `127.0.0.1` and
`[::1]`, so a token never travels unencrypted.

The configuration file is `$APSIO_CONFIG_DIR/config.toml`, else
`$XDG_CONFIG_HOME/apsio/config.toml`, else `~/.config/apsio/config.toml`, readable by its
owner only.

## Exit codes

| Code | Meaning |
| - | - |
| 0 | Success. An empty list is a success |
| 1 | A failure a retry may fix: network or server error |
| 2 | Usage error: an unknown flag, a missing argument, a time or `--jq` expression that does not parse, no project, or no organization for a console URL |
| 3 | Not authenticated: no token, or the server refused it |
| 4 | Bad input: nothing to upload, a file that is not a dSYM, mapping, NDK library with debug information or source map, files the server rejected, a request the API rejected (such as a range over 90 days), or a plain `http://` URL to another machine |
| 5 | Not found: no issue or session with that id, or no sessions of either release in `releases compare` |

The codes are stable, so scripts and agents can branch on them. Commands never prompt when
they are not attached to a terminal: `apsio login` without a token needs a terminal, and the
read commands never ask anything.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.