← Back to Library

CI/CD & Automation

Integrating Bug Reporting into GitHub Actions CI/CD

When a CI run fails, the developer needs to know what broke and why — not just an exit code. Here's how to wire GitHub Actions into your bug reporting workflow so failures are actionable from the moment they happen.

Why CI failures need more than a log dump

A CI failure tells you something broke. A log dump tells you what the code did. Neither tells you what the user would have seen — the visual state, the console errors, the network requests that failed. For end-to-end test failures especially, this gap is where hours of debugging time disappear.

The goal is to make failures self-describing: when a CI job fails, the context needed to reproduce and fix the bug should be attached to a GitHub Issue automatically, waiting for the developer when they open their notifications.

Pattern 1: Report on test step failure

For Playwright or Cypress end-to-end tests, capture a report on failure and POST it to Site Reviewer's API. The webhook payload format is the same as the browser extension — description, URL, console log, network requests, screenshot.

# .github/workflows/e2e.yml
name: E2E Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install dependencies
        run: npm ci

      - name: Run E2E tests
        id: e2e
        run: npx playwright test
        continue-on-error: true

      - name: Report failure to Site Reviewer
        if: steps.e2e.outcome == 'failure'
        run: |
          curl -s -X POST https://api.sitereviewer.app/api/v1/reports \
            -H "X-Api-Key: ${{ secrets.SITE_REVIEWER_API_KEY }}" \
            -H "Content-Type: application/json" \
            -d '{
              "id": "${{ github.run_id }}-${{ github.run_attempt }}",
              "type": "bug",
              "severity": "blocking",
              "description": "E2E test suite failed on ${{ github.ref_name }}",
              "context": {
                "url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}",
                "title": "GitHub Actions — ${{ github.workflow }}",
                "timestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
              },
              "consoleLog": [],
              "networkRequests": []
            }'

      - name: Fail job if tests failed
        if: steps.e2e.outcome == 'failure'
        run: exit 1

Pattern 2: Attach Playwright test artifacts

Playwright generates screenshots and traces on failure. Upload them to Site Reviewer's screenshot endpoint for visual context in the issue.

      - name: Upload failure screenshot
        if: steps.e2e.outcome == 'failure'
        run: |
          # Find the first failure screenshot
          SCREENSHOT=$(find test-results -name "*.png" | head -1)
          if [ -n "$SCREENSHOT" ]; then
            SCREENSHOT_B64=$(base64 -w 0 "$SCREENSHOT")
            # Include in the report payload as the screenshot field
            # (Site Reviewer accepts base64 data URLs)
            echo "data:image/png;base64,$SCREENSHOT_B64" > /tmp/screenshot.txt
          fi

Pattern 3: Nightly regression report

For nightly runs against staging, submit a summary report that includes pass/fail counts as the description and links to the GitHub Actions run for drill-down.

# .github/workflows/nightly.yml
on:
  schedule:
    - cron: '0 2 * * *'   # 2am UTC nightly

jobs:
  nightly-regression:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run test suite
        id: tests
        run: npm test -- --reporter=json > test-results.json
        continue-on-error: true

      - name: Parse results
        id: parse
        run: |
          PASSED=$(jq '.numPassedTests' test-results.json)
          FAILED=$(jq '.numFailedTests' test-results.json)
          echo "passed=$PASSED" >> $GITHUB_OUTPUT
          echo "failed=$FAILED" >> $GITHUB_OUTPUT

      - name: Create Site Reviewer report if failures
        if: steps.parse.outputs.failed != '0'
        run: |
          curl -s -X POST https://api.sitereviewer.app/api/v1/reports \
            -H "X-Api-Key: ${{ secrets.SITE_REVIEWER_API_KEY }}" \
            -H "Content-Type: application/json" \
            -d "{
              \"id\": \"nightly-${{ github.run_id }}\",
              \"type\": \"bug\",
              \"severity\": \"blocking\",
              \"description\": \"Nightly regression: ${{ steps.parse.outputs.failed }} tests failed, ${{ steps.parse.outputs.passed }} passed\",
              \"context\": {
                \"url\": \"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\",
                \"title\": \"Nightly Regression — $(date +%Y-%m-%d)\",
                \"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"
              },
              \"consoleLog\": [],
              \"networkRequests\": []
            }"

Routing CI failures to the right place

Once reports land in Site Reviewer, you can route them automatically:

  • GitHub Issues — connect the GitHub App integration to create an issue in the relevant repo automatically
  • Slack — configure the Slack integration to ping the on-call channel for blocking severity reports
  • Linear / Jira — create tickets in your issue tracker automatically with full context attached

Because CI-generated reports use the same schema as extension-submitted reports, they flow through the same integration pipeline. No special handling needed.

The environment variable you need

The only required setup is adding your Site Reviewer API key as a GitHub Actions secret. In your repository settings:

Settings → Secrets and variables → Actions → New repository secret → name it SITE_REVIEWER_API_KEY.

Get your API key from app.sitereviewer.app/settings.

"CI failures should create a ticket, not a mystery. The person fixing the bug shouldn't have to re-run the test suite to figure out what happened."

Start integrating today

Site Reviewer is free for up to 100 reports/month. Create your workspace → and add the GitHub Actions steps above in five minutes.