# CLI

The stateofpixel package on npm. Node 20 or newer. Run npx stateofpixel \<command> --help for the same list.

The source is in [`packages/cli`](https://github.com/VaibhavAcharya/stateofpixel/tree/main/packages/cli) of [VaibhavAcharya/stateofpixel](https://github.com/VaibhavAcharya/stateofpixel) under the MIT license. Open an [issue](https://github.com/VaibhavAcharya/stateofpixel/issues) for bugs and feature requests. The [changelog](https://github.com/VaibhavAcharya/stateofpixel/blob/main/packages/cli/CHANGELOG.md) lists the changes in each release.

Use 1.7.0 or newer. It sends builds to `https://stateofpixel.com/api/v1`. Older versions use a previous API address that no longer works.

## Commands

| Command                        | What it does                                                     |
| ------------------------------ | ---------------------------------------------------------------- |
| `upload <dir>`                 | Upload a folder of screenshots and compare it with the baseline. |
| `storybook <static-dir>`       | Capture every story of a built Storybook, then upload.           |
| `finalize`                     | Finish a build whose shards ran with --shard auto.               |
| `compare <dir> <baseline-dir>` | Compare a folder of screenshots against a baseline folder.       |

## upload

| Flag                                                        | Default | What it does                                                       |
| ----------------------------------------------------------- | ------- | ------------------------------------------------------------------ |
| `--build-name <name>` STATEOFPIXEL\_BUILD\_NAME             |         | Separate builds of one project, like storybook.                    |
| `--shard <i/n>` STATEOFPIXEL\_SHARD                         |         | This shard and the shard count, or auto with a finalize step.      |
| `--nonce <id>` STATEOFPIXEL\_NONCE                          |         | Shared by every shard of one build.                                |
| `--baseline-branch <branch>` STATEOFPIXEL\_BASELINE\_BRANCH |         | Branch to compare against.                                         |
| `--subset`                                                  |         | Only some snapshots ran, do not mark others removed.               |
| `--threshold <number>`                                      |         | Color difference threshold, 0 to 1, overrides project settings.    |
| `--max-diff-pixels <number>`                                |         | Changed pixels to ignore per snapshot, overrides project settings. |
| `--strict`                                                  |         | Fail instead of skipping on an outage, a rate limit or a fork.     |
| `--dry-run`                                                 |         | Hash and print the plan, upload nothing.                           |

## storybook

Takes every flag of `upload`, plus these. See [Storybook](https://stateofpixel.com/docs/storybook.md).

| Flag                             | Default               | What it does                           |
| -------------------------------- | --------------------- | -------------------------------------- |
| `--viewports <widths>`           | `1280`                | Comma separated viewport widths.       |
| `--include <glob>`               |                       | Only stories whose title/name match.   |
| `--exclude <glob>`               |                       | Skip stories whose title/name match.   |
| `--wait-for-selector <selector>` | `#storybook-root > *` | Wait for this before each screenshot.  |
| `--delay <ms>`                   | `0`                   | Wait this long before each screenshot. |

## finalize

Use the same values the shards used. See [Sharding](https://stateofpixel.com/docs/sharding.md).

| Flag                                                        | Default | What it does                                                   |
| ----------------------------------------------------------- | ------- | -------------------------------------------------------------- |
| `--build-name <name>` STATEOFPIXEL\_BUILD\_NAME             |         | The build name the shards used.                                |
| `--nonce <id>` STATEOFPIXEL\_NONCE                          |         | The nonce the shards used.                                     |
| `--baseline-branch <branch>` STATEOFPIXEL\_BASELINE\_BRANCH |         | Branch to compare against, for --skip-if-empty.                |
| `--skip-if-empty`                                           |         | Create a build with no changes when no shard ran.              |
| `--strict`                                                  |         | Fail instead of skipping on an outage, a rate limit or a fork. |

## compare

| Flag                         | Default               | What it does                           |
| ---------------------------- | --------------------- | -------------------------------------- |
| `--out <dir>`                | `stateofpixel-report` | Report folder.                         |
| `--threshold <number>`       | `0.1`                 | Color difference threshold, 0 to 1.    |
| `--max-diff-pixels <number>` | `0`                   | Changed pixels to ignore per snapshot. |
| `--include-aa`               |                       | Count anti-aliased pixels as changes.  |

## Diff engine

The CLI diffs changed snapshots on your machine, both before an upload and in `compare`. It uses odiff from the `odiff-bin` package, an optional dependency. When `odiff-bin` or its binary is missing, it falls back to pixelmatch. `compare` prints the engine it used, like `compared with odiff in 1.2 s`.

## Environment variables

The flags above list the variable that sets each of them. The CLI also reads these.

| Variable               | What it does                                                                                               |
| ---------------------- | ---------------------------------------------------------------------------------------------------------- |
| `STATEOFPIXEL_TOKEN`   | Project token, for CI other than GitHub Actions.                                                           |
| `STATEOFPIXEL_DIR`     | Folder that snapshot() writes to and the Playwright reporter uploads, stateofpixel-screenshots by default. |
| `STATEOFPIXEL_API_URL` | API of a self-hosted server, https\://stateofpixel.com/api/v1 by default.                                  |
| `CI`                   | The Playwright reporter uploads only when it is set.                                                       |

## Authentication

On GitHub Actions the CLI uses the OIDC token, which needs `permissions: id-token: write`. Anywhere else, set `STATEOFPIXEL_TOKEN` to a project token. See [Other CI](https://stateofpixel.com/docs/other-ci.md) and [Security](https://stateofpixel.com/docs/security.md#how-ci-signs-in).

GitHub gives pull requests from forks no OIDC token and no secrets, so the CLI skips them with a warning and sets no check. If `stateofpixel` is a required check, those pull requests cannot merge until an admin bypasses the rule. See [No check on the pull request](https://stateofpixel.com/docs/troubleshooting.md#no-check-on-the-pull-request).

## Output

```sh terminal
stateofpixel  build #411  feat/header vs main (#405)
  1,500 snapshots  1,488 unchanged  10 changed  2 added  1 removed
  uploaded 22 images (1.3 MB) in 2.1 s
  review: https://stateofpixel.com/acme/web-app/builds/411
```

## Exit codes

- **0** when the build was reported, with or without changes. The GitHub check decides whether the pull request can merge.
- **0** with a warning when stateofpixel or the GitHub OIDC token service is down, a rate limit is hit, or the pull request comes from a fork, so an outage does not break your CI. Pass `--strict` to exit 1 instead.
- **1** on configuration and authentication errors, failed uploads, and images over the [limits](https://stateofpixel.com/docs/limits.md). See [Troubleshooting](https://stateofpixel.com/docs/troubleshooting.md) for the common causes.

`compare` runs on your machine and exits 0 when images differ. Open its report to see the changes.
