Use npx wrangler preview directly in automation. Before you start, review Resources and isolation.
If your Worker is connected to Cloudflare, enable Preview Builds and confirm the Preview command is npx wrangler preview. Workers Builds creates the Preview and comments its URL on the pull request.
Add your Cloudflare credentials to the repository:
gh auth login
gh secret set CLOUDFLARE_API_TOKEN
gh secret set CLOUDFLARE_ACCOUNT_IDThe API token needs permission to edit Workers Scripts and the resources used by the Preview. GitHub provides ${{ secrets.GITHUB_TOKEN }} automatically.
Repository secrets are unavailable to forked pull requests by default. Before exposing Cloudflare credentials, verify that github.event.pull_request.head.repo.full_name == github.repository.
This workflow creates one Preview per pull request and comments its URL:
name: Preview
on:
pull_request:
types: [opened, synchronize, reopened, closed]
permissions:
contents: read
pull-requests: write
jobs:
preview:
if: github.event.action != 'closed'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: preview
name: Create or update Preview
run: |
set -o pipefail
output="$(npx wrangler preview --name "pr-${{ github.event.pull_request.number }}" --json)"
printf '%s\n' "$output"
preview_url="$(printf '%s' "$output" | jq -er '.preview_urls[0] // .preview.urls[0]')"
echo "preview_url=$preview_url" >> "$GITHUB_OUTPUT"
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
- name: Comment Preview URL
run: gh pr comment "${{ github.event.pull_request.number }}" --body "Preview: ${{ steps.preview.outputs.preview_url }}"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}Add required install or build steps before the Preview step. GitHub-hosted Ubuntu runners include jq, which the workflow uses to read the Preview URL.
To update one comment instead of creating a new comment on each run, add --edit-last --create-if-none to gh pr comment.
Add a request that verifies the deployed Preview:
- name: Probe Preview
run: curl --fail --show-error --silent "$PREVIEW_URL/api/health"
env:
PREVIEW_URL: ${{ steps.preview.outputs.preview_url }}Replace /api/health with a route that verifies your Worker. If the probe fails, use Workers Observability or Test and debug.
Capture the rendered Preview as a workflow artifact:
- name: Capture Preview screenshot
run: |
npx --yes playwright install --with-deps chromium
npx --yes playwright screenshot "$PREVIEW_URL" preview.png
env:
PREVIEW_URL: ${{ steps.preview.outputs.preview_url }}
- uses: actions/upload-artifact@v4
with:
name: preview-screenshot
path: preview.pngFor hosted browser checks, use the Browser Run screenshot endpoint.
The workflow trigger above includes the closed event. Add this cleanup job under jobs:
cleanup:
if: github.event.action == 'closed'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Delete Preview
run: npx wrangler preview delete --name "pr-${{ github.event.pull_request.number }}" --skip-confirmation
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}If you prefer a wrapper, use cloudflare/wrangler-action ↗. It exposes Preview URLs as outputs and can create a GitHub Deployment.
Preview names are scoped to a Worker. In a monorepo, each Worker can have a Preview with the same pull request name:
cd workers/api && npx wrangler preview --name "pr-123"
cd ../web && npx wrangler preview --name "pr-123"Service bindings between these Previews resolve to the bound Worker's production deployment. Refer to Limitations.
For other CI systems, run:
npx wrangler preview --name "$BRANCH_NAME" --jsonUse the JSON output to post the Preview URL to your review tool.