CAPTCHA-protected pages break automated tests. CaptchaAI integrates with GitHub Actions to solve CAPTCHAs during CI/CD test runs, keeping your pipeline green.
GitHub Actions Workflow
# .github/workflows/captcha-tests.yml
name: CAPTCHA Integration Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: "0 6 * * 1" # Weekly Monday 6 AM
jobs:
captcha-tests:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: pip install requests pytest
- name: Run CAPTCHA integration tests
env:
CAPTCHAAI_KEY: ${{ secrets.CAPTCHAAI_KEY }}
run: pytest tests/test_captcha.py -v --tb=short
Store API Key as GitHub Secret
- Go to Settings → Secrets and variables → Actions
- Click New repository secret
- Name:
CAPTCHAAI_KEY - Value: your CaptchaAI API key
- Click Add secret
Test File
# tests/test_captcha.py
import os
import time
import pytest
import requests
API_KEY = os.environ.get("CAPTCHAAI_KEY")
BASE_URL = "https://ocr.captchaai.com"
def solve_recaptcha(site_key, page_url, timeout=90):
"""Solve reCAPTCHA v2 via CaptchaAI."""
resp = requests.post(f"{BASE_URL}/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": page_url,
"json": 1,
}, timeout=30)
result = resp.json()
assert result.get("status") == 1, f"Submit failed: {result}"
task_id = result["request"]
start = time.time()
while time.time() - start < timeout:
time.sleep(5)
resp = requests.get(f"{BASE_URL}/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
}, timeout=15)
data = resp.json()
if data["request"] != "CAPCHA_NOT_READY":
assert data.get("status") == 1, f"Solve failed: {data}"
return data["request"]
pytest.fail("CAPTCHA solve timed out")
@pytest.mark.skipif(not API_KEY, reason="CAPTCHAAI_KEY not set")
class TestCaptchaIntegration:
"""Integration tests for CAPTCHA-protected flows."""
def test_recaptcha_v2_solve(self):
"""Verify CaptchaAI can solve reCAPTCHA v2."""
token = solve_recaptcha(
site_key="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
page_url="https://www.google.com/recaptcha/api2/demo",
)
assert len(token) > 100
assert token.isascii()
def test_balance_sufficient(self):
"""Ensure account balance is enough for test suite."""
resp = requests.get(f"{BASE_URL}/res.php", params={
"key": API_KEY,
"action": "getbalance",
"json": 1,
})
balance = float(resp.json()["request"])
assert balance > 0.50, f"Low balance: ${balance}"
def test_api_key_valid(self):
"""Verify API key is accepted."""
resp = requests.get(f"{BASE_URL}/res.php", params={
"key": API_KEY,
"action": "getbalance",
"json": 1,
})
result = resp.json()
assert result.get("status") == 1, f"Invalid key: {result}"
Matrix Testing (Multiple CAPTCHA Types)
jobs:
captcha-matrix:
runs-on: ubuntu-latest
strategy:
matrix:
captcha-type: [recaptcha-v2, turnstile, image]
fail-fast: false
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: pip install requests pytest
- name: Run ${{ matrix.captcha-type }} tests
env:
CAPTCHAAI_KEY: ${{ secrets.CAPTCHAAI_KEY }}
CAPTCHA_TYPE: ${{ matrix.captcha-type }}
run: pytest tests/test_${{ matrix.captcha-type }}.py -v
Caching Test Results
Avoid redundant CAPTCHA solves for unchanged code:
- name: Cache test results
uses: actions/cache@v4
with:
path: .test-cache
key: captcha-tests-${{ hashFiles('tests/**') }}
- name: Skip if cached
id: check-cache
run: |
if [ -f .test-cache/passed ]; then
echo "skip=true" >> $GITHUB_OUTPUT
fi
- name: Run tests
if: steps.check-cache.outputs.skip != 'true'
env:
CAPTCHAAI_KEY: ${{ secrets.CAPTCHAAI_KEY }}
run: |
pytest tests/test_captcha.py -v
mkdir -p .test-cache && touch .test-cache/passed
Slack Notification on Failure
- name: Notify on failure
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "CAPTCHA tests failed on ${{ github.ref }}",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "CAPTCHA tests *failed* on `${{ github.ref }}`\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View run>"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Troubleshooting
| Issue | Cause | Fix |
|---|---|---|
| Tests skip with "CAPTCHAAI_KEY not set" | Secret not configured | Add secret in repo Settings |
| Timeout in CI but works locally | Runner network latency | Increase timeout to 120s |
| Balance check fails | Key format issue | Verify secret value has no whitespace |
| Workflow never runs | Wrong branch/trigger config | Check on: block in YAML |
FAQ
How much does running CAPTCHA tests in CI cost?
A typical test suite solving 3-5 CAPTCHAs costs $0.01-0.03 per run. Weekly scheduled runs cost around $0.10-0.15/month.
Should I run CAPTCHA tests on every PR?
Run balance and key validation on every PR. Run full CAPTCHA solve tests on merge to main or on a weekly schedule to minimize costs.
Can I use this with other CI platforms?
Yes. The Python test code works the same in GitLab CI, CircleCI, or Jenkins. Only the workflow YAML syntax differs.
Related Guides
Keep your pipeline green — get CaptchaAI for CI/CD.
Discussions (0)
Join the conversation
Sign in to share your opinion.
Sign InNo comments yet.