Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
5af1762
docs: Add Snapshots EA product documentation
mtopo27 Apr 13, 2026
86507a0
path and title change
mtopo27 Apr 13, 2026
61464bd
cleanup
mtopo27 Apr 14, 2026
47891dd
nelson comments
mtopo27 Apr 14, 2026
6e9a27f
edits
mtopo27 Apr 16, 2026
73a2f74
Update docs/product/snapshots/uploading-snapshots/index.mdx
mtopo27 Apr 20, 2026
bc58655
Apply suggestions from code review
mtopo27 Apr 20, 2026
3a6caa5
docs(snapshots): Split CI setup into its own page (#17424)
runningcode Apr 23, 2026
5d0583f
docs(snapshots): Add Android setup guide (EME-1031) (#17425)
runningcode Apr 23, 2026
5788c95
docs(snapshots): Bump sentry-cli minimum to 3.4.0
runningcode Apr 23, 2026
6d02de1
docs(snapshots): Bump SAGP to 6.5.0 and reword "snapshot tests" (#17473)
runningcode Apr 24, 2026
6a686e6
docs(snapshots): Add iOS setup guide (EME-1030) (#17474)
cameroncooke Apr 27, 2026
6f110f5
revert accidental change
mtopo27 Apr 27, 2026
ef6b0e4
typo
mtopo27 Apr 27, 2026
ebf7208
Apply suggestions from code review
mtopo27 Apr 28, 2026
1d4a0ae
make iOS:Android more consistent
mtopo27 Apr 28, 2026
cfd61ba
docs(snapshots): Align Android DSL with plugin restructuring (#17565)
runningcode Apr 30, 2026
b21ee7d
explain comparisons
mtopo27 May 1, 2026
695e91d
diff threshold docs
mtopo27 May 1, 2026
f23c69a
status check pics + polish
mtopo27 May 1, 2026
d45a21d
approval
mtopo27 May 1, 2026
b98243c
change label for supported platforms, remove todo
mtopo27 May 1, 2026
db7fed1
remove open todos
mtopo27 May 1, 2026
f4f5003
rework portion on sentry UI + compress images
mtopo27 May 1, 2026
74f0125
alex suggestion
mtopo27 May 4, 2026
e24c6e3
remove todo
mtopo27 May 4, 2026
5de0c3d
docs(snapshots): Add sentry-cli reference page for snapshots (#17464)
runningcode May 4, 2026
b09f2ae
Add PNG to extended words in _typos (#17600)
coolguyzone May 4, 2026
8357d22
replace pngs
mtopo27 May 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions _typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ extend-exclude = [
# .NET ecosystem
Paket = "Paket" # .NET package manager (legitimate tool)
paket = "paket" # .NET package manager CLI command
PNGs = "PNGs"
PNG = "PNG"

# Platform-specific terms
ITMS = "ITMS" # Apple error code prefix (legitimate)
Expand Down
100 changes: 100 additions & 0 deletions docs/cli/snapshots.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
title: Snapshots (CLI)
sidebar_order: 6
description: "Upload snapshot images to Sentry with sentry-cli for visual diffing and GitHub status checks."
beta: true
---

<Include name="feature-available-for-user-group-early-adopter" />

The `sentry-cli build snapshots` command uploads a directory of images to [Snapshots](/product/snapshots/) for visual diffing against a base build.

<Alert level="warning">
`sentry-cli build snapshots` is experimental. The command is subject to
breaking changes, including removal, in any Sentry CLI release.
</Alert>

## Requirements

- `sentry-cli` version 3.4.0 or later. See [Installation](/cli/installation/).
- A Sentry auth token with `project:write` scope (personal) or `org:ci` scope (org-level). See [Configuration](/cli/configuration/#to-authenticate-manually).
- A directory of `.png` or `.jpeg` images, optionally with `.json` sidecar metadata. See [Uploading Snapshots](/product/snapshots/uploading-snapshots/) for the directory layout.

## Basic Usage

With `SENTRY_AUTH_TOKEN`, `SENTRY_ORG`, and `SENTRY_PROJECT` configured:

```bash
sentry-cli build snapshots ./snapshots --app-id web-frontend
```

`--app-id` identifies your app or bundle (for example, `web-frontend`, `ios-app`). Keep it consistent across uploads — Sentry uses it to match head and base snapshots.

The `<PATH>` argument is the directory containing images. Images may be nested in subdirectories; subdirectory paths become part of each snapshot's filename in the Sentry UI.

## Git Metadata

When run in a supported CI environment, `sentry-cli` automatically detects:

- `--head-sha` — the current commit SHA.
- `--base-sha` — the merge-base against the remote tracking branch (PR builds only).
- `--vcs-provider` — inferred from the git remote (for example, `github`).
- `--head-repo-name` / `--base-repo-name` — inferred from the git remote.
- `--head-ref` / `--base-ref` — current and base branch names.
- `--pr-number` — detected from GitHub Actions environment variables on `pull_request` workflows.

Pass any of these flags explicitly to override auto-detection, or use:

- `--no-git-metadata` to skip detection entirely (for example, when uploading snapshots not tied to a commit).
- `--force-git-metadata` to require detection outside CI (for example, when testing CI behavior locally).

For PRs from forks, set `--base-repo-name` to the upstream repository so Sentry can locate the base build.

## Selective Uploads

If you shard snapshot generation across parallel CI jobs and upload each shard separately, pass `--selective` on every upload:

```bash
sentry-cli build snapshots ./shard-1 --app-id web-frontend --selective
sentry-cli build snapshots ./shard-2 --app-id web-frontend --selective
```

Sentry merges selective uploads that share the same commit SHA and `app-id`. Removals and renames cannot be detected on PRs when using `--selective`, because Sentry cannot distinguish an intentionally deleted snapshot from one that simply wasn't part of this shard.

## Diff Threshold

Use `--diff-threshold` to ignore sub-pixel or anti-aliasing noise. The value is a float between `0.0` and `1.0` representing the fraction of pixels that must change before Sentry reports an image as changed:

```bash
sentry-cli build snapshots ./snapshots --app-id web-frontend --diff-threshold 0.01
```

With a value of `0.01`, images with less than 1% of pixels changed are reported as unchanged.

## Flag Reference

```bash
sentry-cli build snapshots [OPTIONS] --app-id <APP_ID> <PATH>
```

| Flag | Description |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `<PATH>` | Directory containing `.png` or `.jpeg` images (and optional `.json` sidecars). |
| `--app-id <APP_ID>` | Identifier for the app or bundle (for example, `web-frontend`, `ios-app`). Must be consistent across uploads — Sentry uses it to match head and base snapshots. Max 255 chars. |
| `--auth-token <TOKEN>` | Sentry auth token. Can also be set via `SENTRY_AUTH_TOKEN`. |
| `-o`, `--org <ORG>` | Sentry organization slug. Can also be set via `SENTRY_ORG`. |
| `-p`, `--project <PROJECT>` | Sentry project slug. Can also be set via `SENTRY_PROJECT`. |
| `--selective` | Mark the upload as a subset. Use when sharding snapshot generation across parallel jobs. |
| `--diff-threshold <THRESHOLD>` | Float between `0.0` and `1.0`. Sentry only reports images as changed if the percentage of changed pixels exceeds this value. |
| `--head-sha <SHA>` | Commit SHA for the upload. Auto-detected in CI. |
| `--base-sha <SHA>` | Base commit SHA for comparison (PR only). Auto-detected from merge-base. |
| `--vcs-provider <PROVIDER>` | VCS provider (for example, `github`). Auto-detected from the git remote. |
| `--head-repo-name <OWNER/REPO>` | Repository in `owner/repo` format. Auto-detected from the git remote. |
| `--base-repo-name <OWNER/REPO>` | Base repository in `owner/repo` format (required for PRs from forks). |
| `--head-ref <BRANCH>` | Head branch name. Auto-detected in CI. |
| `--base-ref <BRANCH>` | Base branch name (PR only). Auto-detected from the remote tracking branch. |
| `--pr-number <NUMBER>` | Pull request number. Auto-detected in GitHub Actions `pull_request` workflows. |
| `--no-git-metadata` | Skip automatic git metadata detection. |
| `--force-git-metadata` | Force git metadata collection outside CI. |
| `--log-level <LEVEL>` | Logging verbosity: `trace`, `debug`, `info`, `warn`, or `error`. |
| `--quiet` | Suppress output while preserving exit codes. Alias: `--silent`. |
166 changes: 166 additions & 0 deletions docs/platforms/android/snapshots/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
---
title: Set Up Snapshots
sidebar_title: Snapshots
sidebar_order: 5275
sidebar_section: features
description: Set up snapshots for Android apps with the Sentry Android Gradle Plugin.
beta: true
---

<Include name="feature-available-for-user-group-early-adopter" />

Set up [Snapshots](/product/snapshots/) for your Android app with the Sentry Android Gradle Plugin. Generate snapshots locally or in your own CI using your preferred snapshot library, then upload the generated images to Sentry for image diffing, visual review, and GitHub status checks.

## Step 1: Enable Snapshots

Ensure the [Sentry Android Gradle Plugin](/platforms/android/configuration/gradle/) version 6.6.0 or higher is applied and configured.

Then enable snapshots in your `build.gradle`:

```kotlin
sentry {
snapshots {
enabled = true
}
}
```

## Step 2: Generate Images

On Android you can either [generate images from compose previews (recommended)](/platforms/android/snapshots/#generate-snapshots-from-compose-previews-recommended) or [from an existing snapshot tool](/platforms/android/snapshots/#generate-snapshots-from-an-existing-snapshot-tool) like Roborazzi or Paparazzi.

These methods are not mutually exclusive — you can generate and upload snapshots from your previews and any existing snapshot tests.

### Generate Snapshots From Compose Previews (Recommended)

Paparazzi and ComposePreviewScanner automatically turns every `@Preview` composable in your project into a snapshot image, so you don't have to maintain explicit snapshot tests.

First, choose a Paparazzi version compatible with your project:

| Version | Gradle | compileSdk | JDK | compose-bom |
| --------------- | -------------- | ---------- | --- | ------------ |
| `2.0.0-alpha04` | 9.1.x or 9.2.x | 36 | 21+ | > 2025.05.00 |
| `1.3.5` | 8.x or 9.x | ≤ 35 | 17+ | ≤ 2025.04.00 |

Then apply the plugin:

```kotlin
plugins {
// existing plugins
id("app.cash.paparazzi") version "<paparazzi_version>"
}
```

#### Customize Preview Generation

The `previews` block inside `snapshots` exposes options that shape the generated Paparazzi tests. These only apply when `generateTests` is `true` (the default).

```kotlin
sentry {
snapshots {
enabled = true
previews {
theme = "@style/Theme.MyApp" // optional
includePrivatePreviews = false // optional, defaults to true
packageTrees = listOf("com.example") // optional, defaults to Android namespace
}
}
}
```

| Option | Default | Description |
| ------------------------ | ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `theme` | Paparazzi default (`android:Theme.Material.NoActionBar.Fullscreen`) | Android theme resource used when rendering previews. Set this if your previews rely on a specific theme. |
| `includePrivatePreviews` | `true` | Whether `@Preview` composables declared `private` are snapshotted. Set to `false` to exclude in-progress or internal-only previews. |
| `packageTrees` | `[]` (falls back to Android namespace) | Package prefixes to scan for `@Preview` composables. When empty, the plugin uses the Android namespace from the build variant. |

If you don't set a `theme`, Paparazzi uses its own default (`android:Theme.Material.NoActionBar.Fullscreen`). If the background of your previews isn't important — for example, when you just want to compare component geometry — you can use a translucent platform theme such as `android:Theme.Translucent.NoTitleBar`:

```kotlin
sentry {
snapshots {
enabled = true
previews {
theme = "android:Theme.Translucent.NoTitleBar"
}
}
}
```

<Alert level="warning">
If `theme` references a style the renderer can't resolve (typo, wrong prefix, or a theme not on the classpath), neither Sentry nor Paparazzi raises an error or warning. Snapshots still generate, but with incorrect visuals. Double-check the theme string if rendered output looks unexpected.
</Alert>

Continue to [Step 3](#step-3-test-locally).

### Generate Snapshots From an Existing Snapshot Tool

Use this path if you already generate snapshots with another tool. The configuration depends on which tool you use.

#### Paparazzi

If you already have [Paparazzi](https://github.com/cashapp/paparazzi) configured, set `generateTests = false` inside the `previews` block so Sentry uses your existing tests instead of auto-generating preview-based ones:

```kotlin
sentry {
snapshots {
enabled = true
previews {
generateTests = false
}
}
}
```

Continue to [Step 3](#step-3-test-locally).

#### Roborazzi

If you already have [Roborazzi](https://github.com/takahirom/roborazzi) configured, wire the Sentry upload task to the output of your Roborazzi record task:

```kotlin
afterEvaluate {
tasks.named<SentryUploadSnapshotsTask>("sentryUploadSnapshotsDebug") {
dependsOn(tasks.named("recordRoborazziDebug"))
snapshotsPath.set(
project.extensions.getByType<RoborazziExtension>().outputDir
)
}
}
```

Continue to [Step 3](#step-3-test-locally).

#### Other Tools

The same pattern works with any snapshot tool. Set `snapshotsPath` to the directory your tool writes images to, and add a `dependsOn` for the task that generates them:

```kotlin
afterEvaluate {
tasks.named<SentryUploadSnapshotsTask>("sentryUploadSnapshotsDebug") {
dependsOn(tasks.named("yourSnapshotTask"))
snapshotsPath.set(layout.projectDirectory.dir("path/to/snapshots"))
}
}
```

Alternatively, you can skip the Gradle plugin entirely and upload with [`sentry-cli build snapshots`](/cli/snapshots/):

```bash
sentry-cli build snapshots ./build/paparazzi/snapshots \
--app-id android-app
```

Use this path if your build pipeline doesn't use Gradle, or if you want to run the upload outside of a Gradle task. See [Uploading Snapshots](/product/snapshots/uploading-snapshots/) for the expected directory layout.

## Step 3: Test Locally

Verify your setup by running:

```bash
./gradlew sentryUploadSnapshotsDebug
```

## Step 4: Integrate Into CI

Once the local upload succeeds, wire the same command into your CI. See [Integrating Into CI](/product/snapshots/integrating-into-ci/) for an example GitHub Actions workflow.
Loading
Loading