Troubleshooting & Debugging
When writing scenarios, things might not work on the first try. Web apps are complex, and headless browsers can act differently than a real user.
This guide helps you find and fix common problems.
1. Debugging Failed XPaths
If a fill, click, or wait_for_selector step fails, Playwright probably cannot find the element.
Common Causes & Solutions
- Async Rendering (React/Vue/Angular): The element might not be in the DOM right away. Playwright waits for elements to be visible. But if the element is removed and re-added fast, the selector might fail. Use
wait_for_selectorbefore clicking, or use stabledata-testidattributes. - iFrames: The exporter looks for elements in the main frame. If the element is inside an
<iframe>(like Stripe checkout), a standard XPath will not find it. (Note: Full frame support is planned. For now, avoid targeting elements in cross-domain iframes). - Shadow DOM: Standard XPaths do not work inside Shadow DOM. If your app uses Shadow DOM, try using Playwright's text or CSS selectors instead of
xpath=. - Dynamic Classes: Do not use XPaths with auto-generated CSS classes (like
//div[@class='sc-bdfBwQ gBikH']). Use stable IDs likeid,name, ordata-testid.
2. Handling WAFs, Cloudflare, and CAPTCHAs
A common reason a UI test fails is that a Web Application Firewall (WAF) or DDoS protection (like Cloudflare or AWS WAF) blocks the headless browser.
Diagnosis
If the first goto step times out, or a screenshot shows an "Access Denied" page, a WAF is blocking you. Headless Chromium tells the server it is a bot through the User-Agent and webdriver flags.
Solutions
- IP Allowlisting (Recommended): The best fix is to give the exporter a static IP (or NAT Gateway IP). Then, allow this IP in your WAF rules to bypass bot protection.
- Custom Headers: Set your WAF to allow traffic if a secret HTTP header is present.
- Environment Isolation: Run your tests against a staging environment where bot protection is turned off.
3. Interpreting error_type_name
When a step fails, the synthetic_ui_journey_errors_total Prometheus counter increases. It includes the error_type_name from your config.yaml.
How to use this: If you see error_type_name="login_button_missing", you know the page loaded, but the button did not render. The UI might have changed, or the service is down.
If you see error_type_name="navigation_failed", it means a network or DNS problem stopped the page from loading.
Group your Grafana panels and Alertmanager alerts by error_type_name to help you find the cause faster.
4. Internal Logs & Container Debugging
If the metrics do not give enough information, or the exporter crashes, read the internal logs.
The exporter uses JSON logging (via Go's slog). This works well with log tools like Loki or ELK.
Reading Logs
- Docker: Run
docker logs <container_id>. You will see logs for every step, how long it took, and the exact Playwright error. - Kubernetes: Run
kubectl logs -l app=synthetic-exporterto see the pod logs.
What to look for:
browser launch failed: The container might be out of memory (OOM). Check your container memory limits.Timeout 30000ms exceeded: Playwright waited 30 seconds for your element, but it did not appear. Check your XPath, or test the page manually to see if it is slow or broken.
