Install any skill in seconds. Free to start, no credit card required.
Get Started Free →SOP for debugging browser automation failures on complex websites. Use when browser tools fail on specific sites like LinkedIn, Twitter/X, SPAs, or sites with Shadow DOM.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 26% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 31% | 0% |
| case-09 | ✗→✓ | ▲ Improved | -2% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 2% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 66% | 0% |
Standard Operating Procedure for debugging and fixing browser automation failures on complex websites.
browser_interact(action="scroll") succeeds but page doesn't movebrowser_interact(action="left_click") succeeds but no action triggeredbrowser_interact(action="type") text disappears or doesn't workbrowser_snapshot hangs or returns stale contentbrowser_navigate loads wrong content1. Create minimal test case demonstrating failure
2. Test against simple site (example.com) to verify tool works
3. Test against problematic site to confirm issueQuick isolation test:
python# Test 1: Does the tool work at all? await browser_navigate(tab_id, "https://example.com") result = await browser_interact(action="scroll", tab_id=tab_id, scroll_direction="down", scroll_amount=100) # Should work on simple sites # Test 2: Does it fail on the problematic site? await browser_navigate(tab_id, "https://linkedin.com/feed") result = await browser_interact(action="scroll", tab_id=tab_id, scroll_direction="down", scroll_amount=100) # If this fails but example.com works → site-specific edge case
Step 2a: Check console for errors
pythonconsole = await browser_console(tab_id) # Look for: CSP violations, React errors, JavaScript exceptions
Step 2b: Inspect DOM structure
pythonhtml = await browser_html(tab_id) snapshot = await browser_snapshot(tab_id) # Look for: # - Nested scrollable divs (overflow: scroll/auto) # - Shadow DOM roots # - iframes # - Custom widgets
Step 2c: Identify the pattern
| Symptom | Likely Cause | Check | |---------|--------------|-------| | Scroll doesn't move | Nested scroll container | Look for overflow: scroll divs | | Click no effect | Element covered | Check getBoundingClientRect vs viewport | | Type clears | Autocomplete/React | Check for event listeners on input; try a type action with no selector | | Snapshot hangs | Huge DOM | Check node count in snapshot | | Snapshot stale | SPA hydration | Wait after navigation |
Pattern: Always have fallbacks
pythonasync def robust_operation(tab_id): # Method 1: Primary approach try: result = await primary_method(tab_id) if verify_success(result): return result except Exception: pass # Method 2: CDP fallback try: result = await cdp_fallback(tab_id) if verify_success(result): return result except Exception: pass # Method 3: JavaScript fallback return await javascript_fallback(tab_id)
Pattern: Always add timeouts
python# Bad - can hang forever result = await browser_snapshot(tab_id) # Good - fails fast with useful error try: result = await browser_snapshot(tab_id, timeout_s=10.0) except asyncio.TimeoutError: # Handle timeout gracefully result = await fallback_snapshot(tab_id)
1. Run against problematic site → should work
2. Run against simple site → should still work (regression check)
3. Document in registry.mdSites: LinkedIn, Twitter/X, any SPA with scrollable feeds
Detection:
javascript// Find largest scrollable container const candidates = []; document.querySelectorAll('*').forEach(el => { const style = getComputedStyle(el); if (style.overflow.includes('scroll') || style.overflow.includes('auto')) { const rect = el.getBoundingClientRect(); if (rect.width > 100 && rect.height > 100) { candidates.push({el, area: rect.width * rect.height}); } } }); candidates.sort((a, b) => b.area - a.area); return candidates[0]?.el;
Fix: Dispatch scroll events at container's center, not viewport center.
Sites: Modals, tooltips, SPAs with loading overlays
Detection:
javascriptconst rect = element.getBoundingClientRect(); const centerX = rect.left + rect.width / 2; const centerY = rect.top + rect.height / 2; const topElement = document.elementFromPoint(centerX, centerY); return topElement === element || element.contains(topElement);
Fix: Wait for overlay to disappear, or use JavaScript click.
Sites: React SPAs, modern web apps
Detection: If CDP click doesn't trigger handler but manual click works.
Fix: Use JavaScript click as primary:
javascriptelement.click();
Sites: LinkedIn, Facebook, Twitter (feeds with 1000s of nodes)
Detection:
javascriptdocument.querySelectorAll('*').length > 5000
Fix:
Sites: React, Vue, Angular SPAs after navigation
Detection:
javascript// Check if React app has hydrated document.querySelector('[data-reactroot]') || document.querySelector('[data-reactid]')
Fix: Wait for specific selector after navigation:
pythonawait browser_navigate(tab_id, url, wait_until="load") await browser_interact(action="wait", tab_id=tab_id, wait_for_selector='[data-testid="content"]', timeout_ms=5000)
Sites: Components using Shadow DOM, Lit elements
Detection:
javascriptdocument.querySelectorAll('*').some(el => el.shadowRoot)
Fix: Pierce shadow root:
javascriptfunction queryShadow(selector) { const parts = selector.split('>>>'); let node = document; for (const part of parts) { if (node.shadowRoot) { node = node.shadowRoot.querySelector(part.trim()); } else { node = node.querySelector(part.trim()); } } return node; }
| Issue | Primary Fix | Fallback | |-------|-------------|----------| | Scroll not working | Find scrollable container | Mouse wheel at container center | | Click no effect | JavaScript click() | CDP mouse events | | Type clears | use_insert_text=False (per-keystroke) | Use a type action (Input.insertText) | | Snapshot hangs | Add timeout_s | DOM snapshot fallback | | Stale content | Wait for selector | Increase wait_until timeout | | Shadow DOM | Pierce selector | JavaScript traversal |
Other measured skills in the registry, with their headline benchmark lift.