# Pull Request Screenshots and Video for React Native and Expo, Recorded by Your AI Agent

> Your AI agent verifies a React Native or Expo change on a real runtime, then records a clean video and per-state screenshots as pull request evidence.

- Author: Ike Studios LLC
- Published: 2026-10-08
- Canonical: https://ceraph.dev/blog/pull-request-screenshots-video-react-native

---

A pull request for a mobile app asks the reviewer to take something on faith. The diff shows what changed in the code; it doesn't show the checkout button actually working on a phone. Reviewers need visual evidence: pull request screenshots or a quick PR video of the change running. When an AI coding agent wrote the change, the gap is wider: the agent says it's done, and the reviewer has no visual evidence that the change ever ran.

Ceraph closes that gap at the source. It's an [MCP](https://modelcontextprotocol.io) server that lets your AI coding agent drive and test your React Native or Expo app on real devices, simulators, and emulators. Once the agent has verified a change in the running app, it records that verified path as a clean screen recording plus a screenshot of each verified state. That is the visual evidence a reviewer needs for a mobile app pull request review, and the agent produces it as part of the same task that wrote the code.

## Verify first, then record

Screen recording for code review only helps when the recording shows a path that actually works. Ceraph keeps verifying and recording as two separate steps.

**Verify.** The agent brings the app up with `ceraph_start`, reads the screen with `ceraph_snapshot`, and drives the flow with the `screen_*` tools: tap, type, swipe, deep-link. It snapshots again after each action and reads anything the app threw from `rn_get_errors`. This is where the agent explores, hits the bug, fixes it, and tries again.

**Record.** Once the path works, the agent calls `ceraph_record_run`. It replays the verified path without model pauses: no dead air while the agent thinks, no exploratory detours, no debugging retries. Each recorded checkpoint must match a screen state the agent already observed during verification, so a replay that doesn't reach a state it already verified is marked failed in `run.json`.

For a change that's purely visual and static, like a new color or a reworded label, a recording adds nothing. In that case the agent verifies the settled screen with `screen_screenshot` and `ceraph_snapshot`, and passes `saveTo` so the same screenshot is written to a PNG in your project, ready to attach to the PR.

## What you get

Each recorded run writes its evidence to `.ceraph/recorded-runs/<run-id>/`, a directory that `ceraph init` adds to your `.gitignore`, so evidence stays out of your commits:

- **`recording.mp4`** is the clean H.264 replay of the verified flow, on iOS or Android.
- **`states/*.jpg`** holds a screenshot of each verified state in the order it was reached, so you get stills without scrubbing the video.
- **`snapshots/*.json`** holds the structured UI snapshot behind each verified state: the elements, their roles and labels, and on-screen bounds.
- **`run.json`** is a manifest with the run's title, every replayed step in order, and each verified state with its evidence. Values the agent typed into fields are recorded only by length, so a password used during the run is not written to the manifest.

The recording captures the screen only. It doesn't capture or verify audio.

The manifest is also the agent's source for the PR description. Its ordered steps and verified states become the "How it was tested" section, written from what actually ran rather than from memory.

## Getting the evidence into the pull request

GitHub CLI v2.99.0 added a repeatable [`--attach` flag](https://docs.github.com/en/github-cli/github-cli/attaching-files-with-github-cli) to `gh pr create`, `gh pr edit`, and `gh pr comment`. It uploads local images and video and embeds them in the body. So an AI agent opening a pull request can post the evidence itself. It writes the body, references the files, and attaches them in one command. Attach only runs whose `run.json` status is `succeeded`:

```bash
gh pr create \
  --title "Fix: Place order button stays disabled after card entry" \
  --body-file pr-body.md \
  --attach .ceraph/recorded-runs/<run-id>/recording.mp4 \
  --attach .ceraph/recorded-runs/<run-id>/states/<confirmation-state>.jpg
```

A few GitHub rules apply. Attaching requires push access to the repository. Videos are limited to [10 MB on Free-plan repositories and 100 MB on paid plans](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/attaching-files), so keep recorded runs focused on the flow under review. Attached files the body doesn't reference are appended to the end of it, and a video renders as an inline player only when its reference is alone in its paragraph. On an older `gh`, or when you'd rather choose the clips yourself, drag `recording.mp4` and the state screenshots into the PR from `.ceraph/recorded-runs/`.

## A walkthrough: fixing a checkout bug

Say a user reports that the "Place order" button stays disabled after they enter a valid card. You ask your agent to fix it and open a PR with evidence.

1. **Reproduce.** The agent calls `ceraph_start`, opens checkout with `screen_open_url` (`myapp://checkout`), fills the form with `screen_type_into_field`, and sees in `ceraph_snapshot` that the button is still disabled.
2. **Fix and verify.** The agent finds the validation bug and edits the code, then runs the form again, and this time `screen_tap_and_verify` taps "Place order" and confirms the order confirmation screen appears. `rn_get_errors` is clean.
3. **Record.** The agent calls `ceraph_record_run` with the verified path: open checkout, fill the card, tap "Place order", reach confirmation.
4. **Draft the PR.** The agent writes the description from `run.json` and attaches the evidence:

```markdown
## Fix: Place order stays disabled after valid card entry

Card validation rejected 16-digit numbers that contained spaces, so the
form never became valid.

### How it was tested (iPhone 16 Simulator, verified run)
1. Opened `myapp://checkout`
2. Entered shipping address and card `4242 4242 4242 4242`
3. Tapped "Place order"
4. Order confirmation screen appeared, no runtime errors
```

The body doesn't reference the media, so `gh` appends the attached recording and confirmation screenshot to the end of the description.

The reviewer opens the PR and watches the fix work on a real runtime before reading the diff.

## Before and after screenshots

If a reviewer wants before and after screenshots, ask the agent for both. It records the broken flow with `ceraph_record_run` before it edits anything, then records the fixed flow afterward. Both runs write `states/*.jpg` files, so the PR can carry the pair.

## Where this fits

The loop is the same one described in [Expo E2E testing with an AI coding agent](/blog/expo-e2e-testing-ai-agent): bring the app up, observe, act, observe. The recording is that loop's output in a form a reviewer can watch.

Ready to give your pull requests visual evidence? [Get started here.](/docs/get-started)
