> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.doc-detective.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.doc-detective.com/_mcp/server.

# Run in CI with the GitHub Action

> Add the Doc Detective GitHub Action to a workflow, gate pull requests on the results, and open PRs or issues automatically.

The [Doc Detective GitHub Action](https://github.com/doc-detective/github-action) runs your tests inside a GitHub Actions workflow. It's the recommended way to run Doc Detective in CI. It installs Doc Detective for you, and it fails the job when tests fail if you set `exit_on_fail` to `true`. It can also open a pull request or file an issue when a run finds a problem. This guide covers adding the action to a workflow, failing the build on test failures, and wiring up the pull request and issue features.

For the full list of inputs and outputs, see the [action's README](https://github.com/doc-detective/github-action).

## Before you begin

* A GitHub repository with documentation tests. That's either a spec you can run, or docs with inline or detected tests.
* Permission to add a workflow file under `.github/workflows/` in that repository.

## Step 1: Add the action to a workflow

Create a workflow file in `.github/workflows/`. Check out the repository first so the action can read your tests, then add the Doc Detective step:

**`.github/workflows/doc-detective.yml`**

```yaml title=".github/workflows/doc-detective.yml"
name: doc-detective
on: [pull_request]

jobs:
  runTests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: doc-detective/github-action@v1
```

This runs Doc Detective on every pull request. Pin to the major version (`@v1`) to pick up fixes automatically, or pin to a full version such as `@v1.4.1` for a fixed release.

## Step 2: Point the action at your tests

By default, the action runs from the repository root and uses the config file Doc Detective discovers there. To override either one, set the corresponding input:

```yaml
- uses: doc-detective/github-action@v1
  with:
    version: latest
    config: .doc-detective.json
    input: ./docs
```

| Input               | Default  | Description                                                                                                                                                                                                                                                                                       |
| ------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `version`           | `latest` | Doc Detective version to run, as a version number or an npm tag such as `latest`. Leave it empty (`""`) to run a locally resolvable build instead of installing from the registry.                                                                                                                |
| `working_directory` | `.`      | Directory to run in, relative to the repository root.                                                                                                                                                                                                                                             |
| `ios`               | `auto`   | Cache the WebDriverAgent build on macOS runners so `ios`-platform tests skip the slow cold compile. `auto` caches only when your specs use an `ios` platform, `true` always caches, and `false` never does. No effect off macOS. See [Speed up iOS tests on macOS](#speed-up-ios-tests-on-macos). |
| `config`            | None     | Path to a configuration file.                                                                                                                                                                                                                                                                     |
| `input`             | None     | Path to an input file or directory. Overrides the `input` field in the config file.                                                                                                                                                                                                               |

> **Note**
>
> Leave `version` empty to skip the registry install and run whatever `doc-detective` is already resolvable in the working directory. One example is a local build you exposed with `npm link` in an earlier step. This lets a repository test the action against its own build under review rather than the published package.

## Step 3: Fail the build when tests fail

By default, the action doesn't fail the job when tests fail. It reports the results and exits cleanly. To make a failing test fail the workflow and block the pull request, set `exit_on_fail` to `true`:

```yaml
- uses: doc-detective/github-action@v1
  with:
    exit_on_fail: true
```

> **Note**
>
> This is the action's main advantage over running the CLI directly in a workflow. The standalone `doc-detective` CLI exits non-zero only when it crashes or your config is invalid, never because a test failed. A script that relies on its exit code therefore reports success even when documentation tests failed. The action reads the results and exits non-zero for you. See [Reporters and artifacts](/docs/ci/reporters-and-artifacts#step-6-fail-ci-when-tests-fail) for the CLI behavior in detail.

## Step 4: Open a pull request when files change

Doc Detective sometimes updates files during a run, refreshing screenshots or recording new command output. The action can commit those changes to a new branch and open a pull request for review. To enable this, set `create_pr_on_change` to `true` and grant the job permission to write contents and pull requests:

```yaml
name: doc-detective
on:
  schedule:
    - cron: '0 0 * * *'  # Run daily at midnight

jobs:
  runTests:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
      - uses: doc-detective/github-action@v1
        with:
          create_pr_on_change: true
          pr_title: Doc Detective found changes
          pr_labels: doc-detective,for-review
```

> **Note**
>
> You must allow GitHub Actions to create pull requests for the repository. Go to **Settings** > **Actions** > **General** and select **Allow GitHub Actions to create and approve pull requests**.

| Input                 | Default                 | Description                                                 |
| --------------------- | ----------------------- | ----------------------------------------------------------- |
| `create_pr_on_change` | `false`                 | Open a pull request if any files change during the run.     |
| `pr_branch`           | `doc-detective-{DATE}`  | Branch name for the pull request.                           |
| `pr_title`            | `Doc Detective Changes` | Pull request title.                                         |
| `pr_body`             | See README              | Pull request body. `$RUN_URL` inserts the workflow run URL. |
| `pr_labels`           | `doc-detective`         | Comma-separated labels.                                     |
| `pr_assignees`        | None                    | Comma-separated usernames to assign.                        |
| `pr_reviewers`        | None                    | Comma-separated usernames to request reviews from.          |

A created pull request means files changed, not that tests passed or failed. Review the diff before merging.

## Step 5: File an issue when tests fail

When a run has failing tests, the action can open a GitHub issue to track the failure and mention an AI integration to investigate it. To enable this, set `create_issue_on_fail` to `true` and grant the job permission to write issues:

```yaml
name: doc-detective
on: [pull_request]

jobs:
  runTests:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      issues: write
    steps:
      - uses: actions/checkout@v4
      - uses: doc-detective/github-action@v1
        with:
          create_issue_on_fail: true
          issue_title: Doc Detective found documentation issues
          integrations: claude
```

| Input                  | Default                 | Description                                                                                                 |
| ---------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------- |
| `create_issue_on_fail` | `false`                 | Open an issue if one or more tests fail.                                                                    |
| `issue_title`          | `Doc Detective Failure` | Issue title.                                                                                                |
| `issue_body`           | See README              | Issue body. `$RESULTS` inserts the results, `$RUN_URL` the workflow run URL, and `$PROMPT` the prompt text. |
| `issue_labels`         | `doc-detective`         | Comma-separated labels.                                                                                     |
| `issue_assignees`      | None                    | Comma-separated usernames to assign.                                                                        |
| `integrations`         | None                    | Comma-separated integrations to mention in the issue (see [Integrations](/docs/test-docs/integrations)).    |
| `prompt`               | See README              | Prompt text passed to integrations.                                                                         |

The `integrations` input mentions an AI assistant in the issue so it can investigate the failure and suggest a fix. Options include `claude`, `copilot`, `cursor`, and `promptless`. For the full list, see [Integrations](/docs/test-docs/integrations).

## Step 6: Use the results in later steps

The action exposes the run's results so later steps can act on them. Give the step an `id`, then read its outputs:

```yaml
- uses: doc-detective/github-action@v1
  id: doc-detective
- run: echo "Results: ${{ steps.doc-detective.outputs.results }}"
```

| Output             | Description                                                            |
| ------------------ | ---------------------------------------------------------------------- |
| `results`          | JSON-formatted test results.                                           |
| `pull_request_url` | URL of the created pull request, when `create_pr_on_change` opens one. |
| `issue_url`        | URL of the created issue, when `create_issue_on_fail` opens one.       |

## Browser modes

On Ubuntu runners, the action runs browsers headless. Chrome and Firefox contexts fall back to headless mode automatically.

Some tests need a display, such as recording video with the `ffmpeg` engine. Run those jobs on a macOS or Windows runner instead:

```yaml
jobs:
  runTests:
    runs-on: macos-latest  # or windows-latest
    steps:
      - uses: actions/checkout@v4
      - uses: doc-detective/github-action@v1
```

See [Docker and headless](/docs/ci/docker-and-headless) for how headless environments affect a run.

## Speed up iOS tests on macOS

Tests against the `ios` platform run on macOS runners, where the first XCUITest session compiles the WebDriverAgent (WDA) with `xcodebuild`. On a cold, ephemeral runner that compile takes around 10 minutes and dominates the run. To avoid paying that cost every time, the action caches the WDA build products and restores them on later runs. The build then becomes near-instant.

```yaml
jobs:
  runTests:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
      - uses: doc-detective/github-action@v1
        # ios: auto is the default—nothing else is needed on macOS.
```

The `ios` input controls this behavior:

| Input | Default | Description                                                                                                                                                                                 |
| ----- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ios` | `auto`  | Cache the WebDriverAgent build on macOS runners. `auto` scans your resolved specs and config and caches only when it finds an `ios` platform, `true` always caches, and `false` never does. |

The first run compiles WDA cold and saves the build to the cache. Later runs restore it and finish with a quick incremental build. The cache key covers the runner OS, the Xcode version, and the XCUITest driver version. A change to the runner OS or Xcode starts a fresh, cold build. A driver-version bump is gentler. The exact key misses, but the action falls back to the most recent build for the same OS and Xcode. It warms an incremental rebuild from that, then re-caches the result under the new driver version. A driver upgrade therefore repairs the cache on the next run instead of leaving it stale.

Caching only affects build speed. Doc Detective still bootstraps the XCUITest driver and simulator it needs at test time. Leave `ios` at `auto` for most workflows. Set it to `true` when your `ios` platform lives outside the scanned specs and config, or `false` to turn caching off.

> **Note**
>
> iOS simulators run only on macOS, so this input has no effect on Linux or Windows runners.

### Alternative: prebuild WebDriverAgent into a persisted cache

Your workflow might already persist Doc Detective's [cache directory](/reference/reference/cli/install#cache-directory) between runs, for example with `actions/cache`. You can then skip the action's WDA cache and let Doc Detective manage the build itself. Run [`doc-detective install ios --yes`](/reference/reference/cli/install#install-ios) in your setup steps. It compiles WebDriverAgent once into the cache, keyed by your Xcode **and** XCUITest driver versions. Test sessions consume the products automatically and read-only, which is safe to share across parallel jobs. Set `ios: 'false'` on the action in that case. The two mechanisms overlap, and the action's cache takes precedence when both are active, so you'd pay for both.

```yaml
jobs:
  runTests:
    runs-on: macos-latest
    env:
      DOC_DETECTIVE_CACHE_DIR: ${{ github.workspace }}/.dd-cache
    steps:
      - uses: actions/checkout@v4
      - uses: actions/cache@v4
        with:
          path: .dd-cache
          key: dd-cache-${{ runner.os }}
      - run: npx doc-detective install ios --yes
      - uses: doc-detective/github-action@v1
        with:
          ios: 'false'
```

## Runtime caching

Doc Detective installs heavy runtime assets on first use, including browsers, drivers, and npm packages. To speed up CI, cache them between runs.

### Cache the runtime directory

Point `DOC_DETECTIVE_CACHE_DIR` at a path under the workspace, then use GitHub's cache action to persist it between runs:

```yaml
jobs:
  runTests:
    runs-on: ubuntu-latest
    env:
      DOC_DETECTIVE_CACHE_DIR: ${{ github.workspace }}/.doc-detective-cache
    steps:
      - uses: actions/checkout@v4
      - uses: actions/cache@v4
        with:
          path: .doc-detective-cache
          key: doc-detective-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            doc-detective-${{ runner.os }}-
      - uses: doc-detective/github-action@v1
```

Because `DOC_DETECTIVE_CACHE_DIR` points to a path under `${{ github.workspace }}`, the cache action can store and restore those assets across runs.

### Pre-install assets

To control exactly when assets download, install them before the action runs:

```yaml
jobs:
  runTests:
    runs-on: ubuntu-latest
    env:
      DOC_DETECTIVE_CACHE_DIR: ${{ github.workspace }}/.doc-detective-cache
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - uses: actions/cache@v4
        with:
          path: .doc-detective-cache
          key: doc-detective-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            doc-detective-${{ runner.os }}-
      - run: npm install -g doc-detective
      - run: doc-detective install all --yes
      - uses: doc-detective/github-action@v1
```

Setting `env` at the job level makes `DOC_DETECTIVE_CACHE_DIR` visible to every step, so the pre-install step and the action share the same cached directory.

## Verify it works

Open a pull request that touches a documented command, screenshot, or API response, then confirm:

* The `doc-detective` job runs and its log shows the terminal summary.
* With `exit_on_fail: true`, a failing test fails the job and blocks the pull request.
* With `create_pr_on_change: true`, a run that changes files opens a pull request.
* With `create_issue_on_fail: true`, a run with failing tests opens an issue.

## Troubleshooting

### The job passes even though a test failed

**Cause:** `exit_on_fail` defaults to `false`, so the action reports failures without failing the job.

**Solution:** Set `exit_on_fail` to `true` so failing tests fail the workflow. See [Step 3](#step-3-fail-the-build-when-tests-fail).

### The action can't create a pull request or issue

**Cause:** The job lacks the required permissions, or the repository doesn't allow Actions to create pull requests.

**Solution:** Add `permissions: { contents: write, pull-requests: write }` for pull requests or `permissions: { issues: write }` for issues. For pull requests, also enable **Allow GitHub Actions to create and approve pull requests** under **Settings** > **Actions** > **General**.

### Runs are slow because assets download every time

**Cause:** The runtime cache isn't persisted between runs.

**Solution:** Set `DOC_DETECTIVE_CACHE_DIR` to a cached workspace path and pre-install assets. See [Runtime caching](#runtime-caching).

## What's next

* [Consume results and fail the build correctly with reporters and artifacts](/docs/ci/reporters-and-artifacts).
* [Run in Docker and headless](/docs/ci/docker-and-headless) for containerized or non-GitHub pipelines.
* [Troubleshoot a failing or flaky test](/docs/troubleshoot/overview) when a run isn't green.