> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stably.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# GitHub Actions

> Integrate Stably tests into your GitHub Actions workflows using the Stably GitHub Action.

Stably provides a dedicated [GitHub Action](https://github.com/stablyai/stably-runner-action) that runs your Playwright tests on Stably Cloud as part of your GitHub workflows. The action automatically detects whether to use v2 (project-based) or v1 (test-suite-based) mode based on the inputs you provide.

## Overview

The Stably GitHub Action allows you to:

* Run all or specific Playwright projects on Stably Cloud
* Override environment variables per-run
* Receive test results as PR comments
* Block deployments on test failures

## Setup Instructions

<Steps>
  <Step title="Create API Key Secret">
    Get your API key from the [settings page](https://app.stably.ai/settings?tab=api-key) on the Web UI.

    Then, go to your GitHub repository, click on "Settings" > "Secrets and variables" > "Actions". Create a new Repository Secret named `STABLY_API_KEY` and paste your API key into the secret value.
  </Step>

  <Step title="Get Project ID">
    Find your project ID in your Stably dashboard settings or project URL.
  </Step>

  <Step title="Create Workflow File">
    Create the file `.github/workflows/stably.yaml` in your GitHub repository with your test configuration.
  </Step>
</Steps>

## Basic Configuration

### Run All Tests

```yaml .github/workflows/stably.yaml theme={null}
name: Run Stably Tests

on:
  pull_request:
  push:
    branches:
      - main

permissions:
  pull-requests: write
  contents: write

jobs:
  test:
    name: Run Tests
    runs-on: ubuntu-latest

    steps:
      - name: Run Stably Tests
        uses: stablyai/stably-runner-action@v4
        with:
          api-key: ${{ secrets.STABLY_API_KEY }}
          project-id: your-project-id
```

### Run Specific Playwright Projects

Use the `playwright-project-name` input to run specific Playwright projects:

```yaml .github/workflows/stably.yaml theme={null}
name: Run Smoke Tests

on:
  pull_request:

permissions:
  pull-requests: write
  contents: write

jobs:
  smoke-tests:
    name: Smoke Tests
    runs-on: ubuntu-latest

    steps:
      - name: Run Smoke Tests
        uses: stablyai/stably-runner-action@v4
        with:
          api-key: ${{ secrets.STABLY_API_KEY }}
          project-id: your-project-id
          playwright-project-name: smoke
```

### Select an Environment

Use `environment-name` to load variables from a [Stably Environment](/stably2/environments). Instead of adding each test secret to GitHub individually, you can [upload your `.env` file](https://app.stably.ai/environments) to Stably once — the only GitHub secret you need is `STABLY_API_KEY`, and when credentials rotate you update them in one place instead of in every repo's settings.

<Tip>
  Set up an environment in seconds via [**Bulk Import**](/stably2/environments#bulk-import) — upload a `.env` file and you're done.
</Tip>

```yaml .github/workflows/stably.yaml theme={null}
name: Run Staging Tests

on:
  push:
    branches:
      - main

permissions:
  pull-requests: write
  contents: write

jobs:
  staging-tests:
    name: Staging Tests
    runs-on: ubuntu-latest

    steps:
      - name: Run Tests on Staging
        uses: stablyai/stably-runner-action@v4
        with:
          api-key: ${{ secrets.STABLY_API_KEY }}
          project-id: your-project-id
          environment-name: Staging
```

## Pull Request Comments

PR comments are enabled by default (`github-comment: true`). To use them, add the required permissions:

```yaml .github/workflows/stably.yaml theme={null}
name: PR Testing

on:
  pull_request:

permissions:
  pull-requests: write
  contents: write

jobs:
  test:
    name: Run PR Tests
    runs-on: ubuntu-latest

    steps:
      - name: Run Tests with PR Comments
        uses: stablyai/stably-runner-action@v4
        with:
          api-key: ${{ secrets.STABLY_API_KEY }}
          project-id: your-project-id
```

## Environment Variable Overrides

Override environment variables for a specific run using `env-overrides`:

```yaml theme={null}
- name: Run Tests
  uses: stablyai/stably-runner-action@v4
  with:
    api-key: ${{ secrets.STABLY_API_KEY }}
    project-id: your-project-id
    env-overrides: |
      BASE_URL: https://staging.example.com
      API_KEY: abc123
```

### Using Dynamic URLs from Previous Steps

If your preview URL is generated dynamically (e.g. from Vercel or Netlify), capture it and pass it via `env-overrides`:

```yaml .github/workflows/stably.yaml theme={null}
name: Deploy and Test

on:
  pull_request:

permissions:
  pull-requests: write
  contents: write

jobs:
  deploy-and-test:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy Preview
        id: deploy
        run: |
          # Your deployment step — capture the URL
          PREVIEW_URL="https://my-app-${{ github.sha }}.vercel.app"
          echo "preview_url=$PREVIEW_URL" >> $GITHUB_OUTPUT

      - name: Run Stably Tests
        uses: stablyai/stably-runner-action@v4
        with:
          api-key: ${{ secrets.STABLY_API_KEY }}
          project-id: your-project-id
          env-overrides: |
            BASE_URL: ${{ steps.deploy.outputs.preview_url }}
```

## Action Inputs Reference

| Input                     | Required | Default               | Description                                                               |
| ------------------------- | -------- | --------------------- | ------------------------------------------------------------------------- |
| `api-key`                 | Yes      | —                     | Your Stably API key                                                       |
| `project-id`              | Yes (v2) | —                     | Your Stably project ID. Use this OR `test-suite-id`, not both.            |
| `playwright-project-name` | No       | —                     | Playwright project name(s) to run. Maps to the `--project` CLI flag.      |
| `environment-name`        | No       | —                     | Environment to use (e.g. "Staging"). Falls back to the project's default. |
| `env-overrides`           | No       | —                     | YAML string or JSON object of environment variable overrides.             |
| `test-suite-id`           | Yes (v1) | —                     | Test suite ID to execute (v1 only). Use this OR `project-id`.             |
| `github-comment`          | No       | `true`                | Post test results as a PR/commit comment.                                 |
| `github-token`            | No       | `${{ github.token }}` | Token for posting comments.                                               |
| `async`                   | No       | `false`               | Launch tests without waiting. Comments won't work in async mode.          |

## Action Outputs

| Output           | Description                                  |
| ---------------- | -------------------------------------------- |
| `success`        | Boolean indicating if the run was successful |
| `runId`          | The run ID (v2 only)                         |
| `testSuiteRunId` | The test suite run ID (v1 only)              |

## Complete Example

```yaml .github/workflows/stably.yaml theme={null}
name: Stably Test Suite

on:
  pull_request:
  push:
    branches:
      - main

permissions:
  pull-requests: write
  contents: write

jobs:
  smoke-tests:
    name: Smoke Tests
    runs-on: ubuntu-latest
    steps:
      - name: Run Smoke Tests
        id: smoke
        uses: stablyai/stably-runner-action@v4
        with:
          api-key: ${{ secrets.STABLY_API_KEY }}
          project-id: ${{ secrets.STABLY_PROJECT_ID }}
          playwright-project-name: smoke

      - name: Print Result
        run: echo "Success: ${{ steps.smoke.outputs.success }}"

  regression-tests:
    name: Regression Tests
    runs-on: ubuntu-latest
    needs: smoke-tests
    if: github.event_name == 'push'
    steps:
      - name: Run Full Regression
        uses: stablyai/stably-runner-action@v4
        with:
          api-key: ${{ secrets.STABLY_API_KEY }}
          project-id: ${{ secrets.STABLY_PROJECT_ID }}
          playwright-project-name: regression
          environment-name: Production
```

## Test Organization

For optimal GitHub Actions integration, organize your tests using [Playwright projects](/use-cases/defining-test-groups):

```typescript playwright.config.ts theme={null}
import { defineConfig } from '@playwright/test';

export default defineConfig({
  projects: [
    {
      name: 'smoke',
      testMatch: '/smoke/**'
    },
    {
      name: 'regression',
      testMatch: '/regression/**'
    }
  ]
});
```

Then reference these projects in your workflows:

```yaml theme={null}
- uses: stablyai/stably-runner-action@v4
  with:
    api-key: ${{ secrets.STABLY_API_KEY }}
    project-id: ${{ secrets.STABLY_PROJECT_ID }}
    playwright-project-name: smoke
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="Permission Denied for PR Comments">
    Make sure you've set the required permissions in your workflow:

    ```yaml theme={null}
    permissions:
      pull-requests: write
      contents: write
    ```

    For organizations, you must first allow these permissions at the organization level.
  </Accordion>

  <Accordion title="Project Not Found">
    Verify the project names in your `playwright-project-name` input match exactly what's defined in your `playwright.config.ts`.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Define Test Groups" icon="layer-group" href="/use-cases/defining-test-groups">
    Organize tests using Playwright projects
  </Card>

  <Card title="Run on Cloud" icon="cloud" href="/run-tests/run-tests-on-cloud">
    Learn more about cloud execution
  </Card>

  <Card title="Schedule Tests" icon="clock" href="/run-tests/scheduled-runs">
    Configure automatic test schedules
  </Card>

  <Card title="Configure Notifications" icon="bell" href="/run-tests/alerting">
    Set up test result notifications
  </Card>
</CardGroup>
