# Browser Automation Troubleshooting Guide Quick reference for common issues and solutions. ## Common Errors ### Element Not Found **Error:** `Element not found: button.submit` **Causes:** 1. Page still loading 2. Wrong selector 3. Element in iframe 4. Element hidden/not rendered **Solutions:** ```json // 1. Add wait before interaction {action: "await_element", selector: "button.submit", timeout: 10000} {action: "click", selector: "button.submit"} // 2. Verify selector exists {action: "extract", payload: "html"} {action: "eval", payload: "document.querySelector('button.submit')"} // 3. Check if in iframe {action: "eval", payload: "document.querySelectorAll('iframe').length"} // 4. Check visibility {action: "eval", payload: "window.getComputedStyle(document.querySelector('button.submit')).display"} ``` ### Timeout Errors **Error:** `Timeout waiting for element after 5000ms` **Solutions:** ```json // Increase timeout for slow pages {action: "await_element", selector: ".content", timeout: 30000} // Wait for loading to complete first {action: "await_element", selector: ".spinner"} {action: "eval", payload: ` new Promise(r => { const check = () => { if (!document.querySelector('.spinner')) r(true); else setTimeout(check, 100); }; check(); }) `} // Use JavaScript to wait for specific condition {action: "eval", payload: ` new Promise(resolve => { const observer = new MutationObserver(() => { if (document.querySelector('.loaded')) { observer.disconnect(); resolve(true); } }); observer.observe(document.body, { childList: true, subtree: true }); }) `} ``` ### Click Not Working **Error:** Click executes but nothing happens **Causes:** 1. JavaScript event handler not attached yet 2. Element covered by another element 3. Need to scroll element into view **Solutions:** ```json // 1. Wait longer before click {action: "await_element", selector: "button"} {action: "eval", payload: "new Promise(r => setTimeout(r, 1000))"} {action: "click", selector: "button"} // 2. Check z-index and overlays {action: "eval", payload: ` (() => { const elem = document.querySelector('button'); const rect = elem.getBoundingClientRect(); const topElem = document.elementFromPoint(rect.left + rect.width/2, rect.top + rect.height/2); return topElem === elem || elem.contains(topElem); })() `} // 3. Scroll into view first {action: "eval", payload: "document.querySelector('button').scrollIntoView()"} {action: "click", selector: "button"} // 4. Force click via JavaScript {action: "eval", payload: "document.querySelector('button').click()"} ``` ### Form Submission Issues **Error:** Form doesn't submit with `\n` **Solutions:** ```json // Try explicit click {action: "type", selector: "input[name=password]", payload: "pass123"} {action: "click", selector: "button[type=submit]"} // Or trigger form submit {action: "eval", payload: "document.querySelector('form').submit()"} // Or press Enter key specifically {action: "eval", payload: ` const input = document.querySelector('input[name=password]'); input.dispatchEvent(new KeyboardEvent('keypress', { key: 'Enter', keyCode: 13 })); `} ``` ### Tab Index Errors **Error:** `Tab index 2 out of range` **Cause:** Tab closed or indices shifted **Solution:** ```json // Always list tabs before operating on them {action: "list_tabs"} // After closing tabs, re-list {action: "close_tab", tab_index: 1} {action: "list_tabs"} {action: "click", tab_index: 1, selector: "a"} // Now correct index ``` ### Extract Returns Empty **Error:** Extract returns empty string **Causes:** 1. Element not loaded yet 2. Content in shadow DOM 3. Text in ::before/::after pseudo-elements **Solutions:** ```json // 1. Wait for content {action: "await_element", selector: ".content"} {action: "await_text", payload: "Expected text"} {action: "extract", payload: "text", selector: ".content"} // 2. Check shadow DOM {action: "eval", payload: "document.querySelector('my-component').shadowRoot.querySelector('.content').textContent"} // 3. Get computed styles for pseudo-elements {action: "eval", payload: "window.getComputedStyle(document.querySelector('.content'), '::before').content"} ``` --- ## Best Practices ### Selector Specificity **Use ID when available:** ```json {action: "click", selector: "#submit-button"} // ✅ Best {action: "click", selector: "button.submit"} // ✅ Good {action: "click", selector: "button"} // ❌ Too generic ``` **Combine selectors for uniqueness:** ```json {action: "click", selector: "form.login button[type=submit]"} // ✅ Specific {action: "click", selector: ".modal.active button.primary"} // ✅ Specific ``` **Use data attributes:** ```json {action: "click", selector: "[data-testid='submit-btn']"} // ✅ Reliable {action: "click", selector: "[data-action='save']"} // ✅ Semantic ``` ### Waiting Strategy **Always wait before interaction:** ```json // ❌ BAD - No waiting {action: "navigate", payload: "https://example.com"} {action: "click", selector: "button"} // ✅ GOOD - Wait for element {action: "navigate", payload: "https://example.com"} {action: "await_element", selector: "button"} {action: "click", selector: "button"} // ✅ BETTER - Wait for specific state {action: "navigate", payload: "https://example.com"} {action: "await_text", payload: "Page loaded"} {action: "click", selector: "button"} ``` **Wait for dynamic content:** ```json // After triggering AJAX {action: "click", selector: "button.load-more"} {action: "await_element", selector: ".new-content"} // After form submit {action: "click", selector: "button[type=submit]"} {action: "await_text", payload: "Success"} ``` ### Error Detection **Check for error messages:** ```json {action: "click", selector: "button.submit"} {action: "eval", payload: "!!document.querySelector('.error-message')"} {action: "extract", payload: "text", selector: ".error-message"} ``` **Validate expected state:** ```json {action: "click", selector: "button.add-to-cart"} {action: "await_element", selector: ".cart-count"} {action: "extract", payload: "text", selector: ".cart-count"} // Verify count increased ``` ### Data Extraction Efficiency **Use single eval for multiple fields:** ```json // ❌ Inefficient - Multiple calls {action: "extract", payload: "text", selector: "h1"} {action: "extract", payload: "text", selector: ".author"} {action: "extract", payload: "text", selector: ".date"} // ✅ Efficient - One call {action: "eval", payload: ` ({ title: document.querySelector('h1').textContent.trim(), author: document.querySelector('.author').textContent.trim(), date: document.querySelector('.date').textContent.trim() }) `} ``` **Extract arrays efficiently:** ```json {action: "eval", payload: ` Array.from(document.querySelectorAll('.item')).map(item => ({ name: item.querySelector('.name').textContent.trim(), price: item.querySelector('.price').textContent.trim(), url: item.querySelector('a').href })) `} ``` ### Performance Optimization **Minimize navigation:** ```json // ❌ Slow - Navigate for each item {action: "navigate", payload: "https://example.com/item/1"} {action: "extract", payload: "text", selector: ".price"} {action: "navigate", payload: "https://example.com/item/2"} {action: "extract", payload: "text", selector: ".price"} // ✅ Fast - Use API or extract list page {action: "navigate", payload: "https://example.com/items"} {action: "eval", payload: "Array.from(document.querySelectorAll('.item')).map(i => i.querySelector('.price').textContent)"} ``` **Reuse tabs:** ```json // ✅ Keep tabs open for repeated access {action: "new_tab"} {action: "navigate", tab_index: 1, payload: "https://tool.com"} // Later, reuse same tab {action: "click", tab_index: 1, selector: "button.refresh"} ``` ### Debugging Workflows **Step 1: Check page HTML:** ```json {action: "navigate", payload: "https://example.com"} {action: "await_element", selector: "body"} {action: "extract", payload: "html"} ``` **Step 2: Test selectors:** ```json {action: "eval", payload: "document.querySelector('button.submit')"} {action: "eval", payload: "document.querySelectorAll('button').length"} ``` **Step 3: Check element state:** ```json {action: "eval", payload: ` (() => { const elem = document.querySelector('button.submit'); return { exists: !!elem, visible: elem ? window.getComputedStyle(elem).display !== 'none' : false, enabled: elem ? !elem.disabled : false, text: elem ? elem.textContent : null }; })() `} ``` **Step 4: Check console errors:** ```json {action: "eval", payload: "console.error.toString()"} ``` --- ## Patterns Library ### Retry Logic ```json // Attempt operation with retry {action: "click", selector: "button.submit"} // Check if succeeded {action: "eval", payload: "document.querySelector('.success-message')"} // If null, retry {action: "click", selector: "button.submit"} {action: "await_text", payload: "Success", timeout: 10000} ``` ### Conditional Branching ```json // Check condition {action: "extract", payload: "text", selector: ".status"} // Branch based on result (in your logic) // If "available": {action: "click", selector: "button.buy"} // If "out of stock": {action: "type", selector: "input.email", payload: "notify@example.com\n"} ``` ### Pagination Handling ```json // Page 1 {action: "navigate", payload: "https://example.com/results"} {action: "await_element", selector: ".results"} {action: "eval", payload: "Array.from(document.querySelectorAll('.result')).map(r => r.textContent)"} // Check if next page exists {action: "eval", payload: "!!document.querySelector('a.next-page')"} // If yes, navigate {action: "click", selector: "a.next-page"} {action: "await_element", selector: ".results"} // Repeat extraction ``` ### Form Validation Waiting ```json // Fill form field {action: "type", selector: "input[name=email]", payload: "user@example.com"} // Wait for validation icon {action: "await_element", selector: "input[name=email] + .valid-icon"} // Proceed to next field {action: "type", selector: "input[name=password]", payload: "password123"} ``` ### Autocomplete Selection ```json // Type in autocomplete field {action: "type", selector: "input.autocomplete", payload: "San Fr"} // Wait for suggestions {action: "await_element", selector: ".autocomplete-suggestions"} // Click suggestion {action: "click", selector: ".autocomplete-suggestions li:first-child"} // Verify selection {action: "extract", payload: "text", selector: "input.autocomplete"} ``` ### Cookie Management ```json // Check if cookie exists {action: "eval", payload: "document.cookie.includes('session_id')"} // Set cookie {action: "eval", payload: "document.cookie = 'preferences=dark; path=/; max-age=31536000'"} // Clear specific cookie {action: "eval", payload: "document.cookie = 'session_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'"} // Get all cookies as object {action: "eval", payload: ` Object.fromEntries( document.cookie.split('; ').map(c => c.split('=')) ) `} ``` --- ## XPath Examples XPath is auto-detected (starts with `/` or `//`). ### Basic XPath Selectors ```json // Find by text content {action: "click", selector: "//button[text()='Submit']"} {action: "click", selector: "//a[contains(text(), 'Learn more')]"} // Find by attribute {action: "click", selector: "//button[@type='submit']"} {action: "extract", payload: "text", selector: "//div[@class='content']"} // Hierarchical {action: "click", selector: "//form[@id='login']//button[@type='submit']"} {action: "extract", payload: "text", selector: "//article/div[@class='content']/p[1]"} ``` ### Advanced XPath ```json // Multiple conditions {action: "click", selector: "//button[@type='submit' and contains(@class, 'primary')]"} // Following sibling {action: "extract", payload: "text", selector: "//label[text()='Username']/following-sibling::input/@value"} // Parent selection {action: "click", selector: "//td[text()='Active']/..//button[@class='edit']"} // Multiple elements {action: "extract", payload: "text", selector: "//h2 | //h3"} ``` --- ## Security Considerations ### Avoid Hardcoded Credentials ```json // ❌ BAD - Credentials in workflow {action: "type", selector: "input[name=password]", payload: "mypassword123"} // ✅ GOOD - Use environment variables or secure storage // Load credentials from secure source before workflow ``` ### Validate HTTPS ```json // Check protocol {action: "eval", payload: "window.location.protocol"} // Should return "https:" ``` ### Check for Security Indicators ```json // Verify login page is secure {action: "eval", payload: ` ({ protocol: window.location.protocol, hasLock: document.querySelector('link[rel=icon]')?.href.includes('secure'), url: window.location.href }) `} ``` --- ## Performance Tips ### Minimize Waits ```json // ❌ Arbitrary timeouts {action: "eval", payload: "new Promise(r => setTimeout(r, 5000))"} // ✅ Condition-based waits {action: "await_element", selector: ".loaded"} ``` ### Batch Operations ```json // ❌ Individual extracts {action: "extract", payload: "text", selector: ".title"} {action: "extract", payload: "text", selector: ".author"} {action: "extract", payload: "text", selector: ".date"} // ✅ Single eval {action: "eval", payload: ` ({ title: document.querySelector('.title').textContent, author: document.querySelector('.author').textContent, date: document.querySelector('.date').textContent }) `} ``` ### Reuse Browser State ```json // ✅ Stay logged in across operations {action: "navigate", payload: "https://app.com/login"} // ... login ... {action: "navigate", payload: "https://app.com/page1"} // ... work ... {action: "navigate", payload: "https://app.com/page2"} // ... work ... (still logged in) ```