---
id: accessibility/guides/report-run-checks-github
title: Report Run Checks as GitHub pull request statuses in Cypress Accessibility
description: >-
  Post Cypress Accessibility Run Checks as GitHub commit statuses so score and
  failed-element thresholds block a pull request merge.
section: accessibility
source_path: docs/accessibility/guides/report-run-checks-github.mdx
version: 8d82546d64f56f8552b1f2cba6e27dab5f929d15
updated_at: '2026-11-07T17:30:41.906Z'
---
# Report Run Checks as GitHub pull request statuses

[Run Checks](/llm/markdown/cloud/features/checks.md) let you encode accessibility thresholds in your App Quality configuration, such as a minimum [accessibility score](/llm/markdown/accessibility/core-concepts/accessibility-score.md) or a maximum number of failing elements, and have Cypress Cloud evaluate them on every recorded run. To surface those results on a pull request, fetch them in CI with `getCheckResults()` and post one commit status per applicable check.

This guide covers the GitHub workflow for posting Run Check statuses. Similar techniques apply to other version control contexts. For custom policy logic the built-in assertion types don't cover, such as allowlisting known failing rules or comparing against a baseline, use the [Results API](/llm/markdown/accessibility/connect-and-extend/results-api.md) approach in [Block pull requests and set policies](/llm/markdown/accessibility/guides/block-pull-requests.md).

Install `@cypress/extract-cloud-results` as described in the [Results API](/llm/markdown/accessibility/connect-and-extend/results-api.md#Installation) guide. Run the status script in the same CI job that recorded the run, after `cypress run --record`. For the full `getCheckResults()` response shape and options, see [Using check results in CI](/llm/markdown/cloud/features/checks.md#Using-check-results-in-CI).

This GitHub Actions workflow records a run, then posts one [commit status](https://docs.github.com/en/rest/commits/statuses) per applicable [Run Check](/llm/markdown/cloud/features/checks.md) to the pull request. A failed check shows as a failing status on the pull request, and you can make the statuses required in your branch protection rules.

.github/workflows/cypress.yml

```
name: Cypress
on: pull_request

permissions:
  contents: read
  statuses: write

jobs:
  cypress:
    runs-on: ubuntu-latest
    env:
      CYPRESS_PROJECT_ID: abc123
      CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      # Failing tests fail this step, but the checks still need to be reported.
      - run: npx cypress run --record
        continue-on-error: true
      - run: npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz
      - run: node scripts/post-check-statuses.js
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

scripts/post-check-statuses.js

```
const fs = require('fs')
const { getCheckResults } = require('@cypress/extract-cloud-results')

const STATES = { passed: 'success', failed: 'failure' }

// On pull_request events, GITHUB_SHA is a merge commit that GitHub creates.
// Statuses only show on the pull request when they're posted to its head commit.
const event = JSON.parse(fs.readFileSync(process.env.GITHUB_EVENT_PATH, 'utf8'))
const sha = event.pull_request?.head.sha ?? process.env.GITHUB_SHA

const main = async () => {
  const results = await getCheckResults()
  const checks = (results.checks ?? []).filter(
    (check) => check.status !== 'not-applicable'
  )

  for (const check of checks) {
    const missed = check.assertionResults
      .filter((assertion) => assertion.status !== 'passed')
      .map(({ type, value, status }) => `${type} ${value} (${status})`)

    const response = await fetch(
      `https://api.github.com/repos/${process.env.GITHUB_REPOSITORY}/statuses/${sha}`,
      {
        method: 'POST',
        headers: {
          authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
          accept: 'application/vnd.github+json',
        },
        body: JSON.stringify({
          context: `Cypress check: ${check.name}`,
          state: STATES[check.status] ?? 'error',
          description: (missed.length
            ? `Missed: ${missed.join('; ')}`
            : 'All assertions passed'
          ).slice(0, 140),
          target_url: `${results.runUrl}/properties`,
        }),
      }
    )

    if (!response.ok) {
      throw new Error(`GitHub responded ${response.status}`)
    }
  }
}

main().catch((error) => {
  console.error(error.message)
  process.exit(1)
})
```

The script skips `not-applicable` checks, so a check scoped to `release/.*` branches only appears on pull requests from those branches. GitHub limits a status description to 140 characters, so the script truncates it and links each status to the run for details.

## See also

*   [Run Checks](/llm/markdown/cloud/features/checks.md) - accessibility assertion types, view matching, and run scoping
*   [Block pull requests and set policies](/llm/markdown/accessibility/guides/block-pull-requests.md) - custom Results API policies
*   [Results API](/llm/markdown/accessibility/connect-and-extend/results-api.md) - fetch per-rule and per-view accessibility results in CI
