Prompt
How do I troubleshoot browser automation when it works on my machine but not in GitHub Actions?
Latest observation
When browser automation works locally but fails in GitHub Actions, it’s usually one of a few classes of issues: environment differences, missing dependencies, timing/flakiness, or CI-specific restrictions. Here’s a practical troubleshooting checklist.
1) Compare local vs CI environment
Start by logging the basics in GitHub Actions:
- OS and browser version
- Node/Python version
- Automation library version
- Headless/headful mode
- Screen size / viewport
- Environment variables
- Installed browser binaries
For example, print versions in CI:
node -v
npm -v
google-chrome --version || true
chromium --version || true
If you use Playwright:
npx playwright --version
npx playwright install --with-deps
If you use Selenium:
- verify the browser binary and driver versions match
- confirm the driver is on the PATH
2) Make the CI environment match local as closely as possible
Common causes of “works locally, fails in CI”:
- Different browser version
- Different viewport/window size
- Different time zone or locale
- Missing fonts
- Different network speed
- Running headless in CI but headed locally
- Different CPU/memory constraints
Try setting explicit, stable values in CI:
- viewport size:
1280x720 - language/locale
- timezone
- consistent test data
3) Check headless mode assumptions
CI usually runs headless, which can expose issues:
- elements not visible until scrolled
- popups blocked
- hover-dependent UI
- animations causing timing issues
Make sure your code does not rely on:
- real mouse movement
- manual waits
- browser UI dialogs
If possible, try running headed in a virtual display for debugging:
- use Xvfb on Linux
- or use Playwright’s trace/video/screenshot features
4) Add screenshots, traces, and logs
This is often the fastest way to find the problem.
Playwright
Enable trace on failure:
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
}
Selenium
Capture:
- screenshots on failure
- browser console logs
- page source
- network logs if available
Generic
Log:
- current URL
- DOM state around the failing selector
- console errors
- failed network requests
5) Look for timing and synchronization issues
CI is slower and less predictable. Flaky tests often hide race conditions.
Avoid:
- fixed sleeps like
wait(2000) - clicking before the page is ready
- asserting immediately after navigation
Prefer:
- explicit waits for selectors
- waiting for network idle only when appropriate
- waiting for a specific DOM state or URL
Examples:
- wait for element to be visible
- wait for text to appear
- wait for a request/response to finish
6) Verify dependencies on Linux runners
GitHub Actions Ubuntu runners can miss libraries needed by browsers.
If using Playwright:
npx playwright install --with-deps
If using Chrome/Chromium directly, ensure required packages are installed. Missing libraries can cause:
- browser not launching
- sandbox errors
- crashes
Common fixes:
- use official browser automation images
- install dependencies explicitly
- avoid relying on system Chrome unless necessary
7) Handle sandbox and permissions issues
In CI, Chromium sometimes needs flags like:
--no-sandbox
--disable-dev-shm-usage
Be careful: --no-sandbox is common in CI but should only be used where appropriate.
If you see crashes related to shared memory, --disable-dev-shm-usage often helps.
8) Check network and authentication differences
If tests depend on external services:
- API rate limits may differ
- local auth tokens might not exist in CI
- localhost may not be reachable the same way
- DNS or firewall rules may differ
Make sure:
- secrets are configured in GitHub Actions
- test accounts are available
- remote services aren’t blocking CI IPs
- requests aren’t failing due to expired credentials
9) Use retries carefully
Retries can hide real problems, but they’re useful for diagnosing flakiness.
In CI:
- retry only failing tests once or twice
- capture artifacts on every failure
- identify patterns: same selector? same step? same page?
10) Reproduce locally with a CI-like environment
The best debugging step is often to reproduce the runner environment locally:
- run tests inside Docker
- use the same browser version as CI
- run headless
- limit CPU/memory if possible
For Playwright, the official Docker image is very helpful:
- same dependencies
- same browser versions
- closer to CI behavior
11) Use GitHub Actions artifacts
Upload failure artifacts so you can inspect them after the run:
- screenshots
- videos
- traces
- logs
Example:
- name: Upload artifacts
uses: actions/upload-artifact@v4
if: failure()
with:
name: test-artifacts
path: |
test-results/
playwright-report/
12) Simplify the failing test
If only one test fails in CI:
- reduce it to the smallest reproducible case
- isolate the exact step that fails
- check whether it’s caused by test order or shared state
13) Common root causes by framework
Playwright
- forgot
npx playwright install --with-deps - selector too strict
- waiting for the wrong condition
- actionability issues in headless mode
Selenium
- chromedriver/browser version mismatch
- stale element references due to rerenders
- implicit/explicit wait conflicts
- missing Linux dependencies
Puppeteer
- browser launch flags
- timeout differences
- needing
--no-sandbox - page load timing or navigation races
Quick debugging recipe
If you need a fast path:
- Print versions in CI
- Add screenshots/traces on failure
- Increase timeout temporarily
- Replace sleeps with explicit waits
- Run the same browser version locally in headless mode
- Compare selectors and DOM state at the failure point
- Check browser logs and console errors
If you want, I can help more specifically
If you share:
- the framework you use (Playwright/Selenium/Puppeteer/etc.)
- the failing step or error message
- your GitHub Actions YAML
…I can suggest targeted fixes and likely causes.