How to Debug Extraction Failures When Browser MCP Cannot Locate Elements in AI-Website-Cloner-Template

When the browser Model-Context-Protocol (MCP) cannot locate elements during the AI-Website-Cloner-Template inspection phase, root causes typically include missing MCP endpoints, dynamic DOM rendering, premature selector execution before network idle, viewport mismatches, or cross-origin iframe boundaries.

The AI-Website-Cloner-Template relies on a browser MCP—such as Chrome MCP or Playwright MCP—to automate the extraction of design tokens and component specifications from target websites. When the extraction script fails to locate expected elements, the cloning workflow defined in .windsurf/workflows/clone-website.md may abort or produce incomplete component specs. Understanding how to debug these browser MCP element location failures ensures reliable data capture across diverse web architectures.

Common Causes of MCP Element Location Failures

MCP Connection and Tool Availability

Before any extraction begins, the skill validates that an MCP tool is available. According to the source code in .windsurf/workflows/clone-website.md at line 26, the workflow checks for Chrome MCP, Playwright MCP, or equivalent endpoints. If none are detected, the skill aborts immediately. Run opencode list-mcp (or your agent's equivalent) to verify the browser automation service is connected and reporting a healthy endpoint.

Dynamic Rendering and Selector Instability

The extraction scripts rely on document.querySelector and page.waitForSelector to locate nodes. Elements rendered via JavaScript after initial load, hidden inside modals, or nested within shadow DOM boundaries often return null if queried immediately. This instability is a primary reason the browser MCP cannot locate elements even when they appear visible in a screenshot.

Timing and Network Idle Conditions

Without explicit waits, the script may execute selectors while assets are still loading. The page must reach a networkidle state before DOM queries return complete results. If the script runs too early, partially hydrated frameworks like React or Vue may not have appended the target nodes to the document yet.

Viewport Size and Responsive State

Many components only render at specific breakpoints. If the MCP session initializes with a mobile viewport but targets a desktop-only navigation bar, the selector will never match. The extraction logic must explicitly set viewport dimensions—such as { width: 1440, height: 900 }—to match the design token extraction plan.

Cross-Origin and Sandboxed Frames

MCP cannot pierce cross-origin iframes due to browser security policies. If the target element lives inside an embedded frame from a different origin, you must first switch the execution context to that specific frame before running selectors.

Step-by-Step Debugging Workflow

Follow this systematic checklist to isolate why the browser MCP cannot locate target elements:

  1. Verify MCP Availability: Confirm your agent reports an active MCP endpoint using opencode list-mcp. This validates that the skill can communicate with the browser automation layer as required by the pre-flight step in .windsurf/workflows/clone-website.md.

  2. Check Page Load Completion: Use await page.goto(url, { waitUntil: "networkidle" }) followed by await page.title() to ensure the page is fully rendered before attempting extraction.

  3. Validate Selectors Manually: Open the target page in a standard Chrome window, launch DevTools, and execute document.querySelector('<your-selector>'). If it returns null, the selector is incorrect or the element requires interaction to appear.

  4. Add Explicit Visibility Waits: Insert await page.waitForSelector('<selector>', { state: "visible", timeout: 15000 }) before reading CSS or text content. This handles lazy-loaded or animated components.

  5. Scroll Into View: Force lazy-load triggers by scrolling: await page.evaluate(s => { const el = document.querySelector(s); if (el) el.scrollIntoView(); }, selector).

  6. Handle Nested Frames: Detect iframe contexts with const frame = page.frame({ url: /.*embed\.html/ }), then query inside the frame object rather than the main page.

  7. Log Computed Styles: After locating the element, capture await page.evaluate(el => getComputedStyle(el).cssText, element) to confirm you are extracting the exact computed values needed for the spec.

  8. Re-run Extraction: After script modifications, re-execute the extraction and verify the spec file in docs/research/components/ updates correctly. Consult the docs/research/INSPECTION_GUIDE.md at line 5 to ensure all required tokens are captured.

Robust Extraction Code Examples

Use these Playwright-style MCP snippets to make your extraction logic resilient to timing and visibility issues.

First, load the page and set the correct viewport:

// Load page and wait for network idle
await page.goto(targetUrl, { waitUntil: "networkidle" });

// Match viewport to design token extraction requirements
await page.setViewportSize({ width: 1440, height: 900 });

Create a helper function to safely locate elements with scrolling and visibility checks:

// Helper to locate element with scroll-into-view and visibility wait
async function locate(selector) {
  // Scroll into view to trigger lazy-load
  await page.evaluate(s => {
    const el = document.querySelector(s);
    if (el) el.scrollIntoView();
  }, selector);
  
  // Wait until visible (max 15s)
  await page.waitForSelector(selector, { state: "visible", timeout: 15000 });
  return await page.$(selector);
}

Extract computed CSS from a located element:

// Example: Extract computed CSS of a primary button
const button = await locate('button.primary');
const css = await page.evaluate(el => getComputedStyle(el).cssText, button);
console.log('Button CSS →', css);

Handle elements inside cross-origin iframes:

// Example: Extracting a component inside an iframe
const frame = page.frame({ url: /.*embed\.html/ });
const iframeBtn = await frame.waitForSelector('button.submit', { state: "visible" });
const iframeCss = await frame.evaluate(el => getComputedStyle(el).cssText, iframeBtn);
console.log('Iframe button CSS →', iframeCss);

Key Source Files for Troubleshooting

Understanding these files helps diagnose why the browser MCP cannot locate elements:

  • .windsurf/workflows/clone-website.md: Defines the full inspection pipeline, including the "Browser automation is required" pre-flight check at line 26 that validates MCP availability before extraction begins.

  • docs/research/INSPECTION_GUIDE.md: Lists every token, component, and interaction that must be captured during reconnaissance. Missing any required item here causes the spec generation to abort (see line 5).

  • src/app/layout.tsx: Contains global font and metadata configurations that the extraction phase updates. Failures to locate these root elements indicate viewport or timing issues.

  • scripts/download-assets.mjs: Handles post-extraction fetching of images and videos. Failures in this script can masquerade as element location errors if asset URLs are extracted but the files cannot be retrieved.

  • README.md: Provides high-level usage instructions and context for the /clone-website skill.

Summary

  • Verify MCP connectivity before debugging selectors—extraction requires an active Chrome MCP or Playwright MCP endpoint.
  • Always wait for networkidle and set explicit viewports to match the target's responsive breakpoints.
  • Use scroll-into-view plus visibility waits to handle dynamically rendered content and lazy-loaded components.
  • Switch to iframe contexts when targeting elements inside cross-origin or sandboxed frames.
  • Reference docs/research/INSPECTION_GUIDE.md to ensure all required design tokens are captured; missing data points abort the spec generation.

Frequently Asked Questions

Why does the MCP script fail to find elements that are clearly visible in the browser?

The element likely renders after the initial DOM load via JavaScript or requires a specific viewport size. The script executes document.querySelector before the framework hydrates the component. Add an explicit waitForSelector with { state: "visible", timeout: 15000 } and ensure you called page.goto with { waitUntil: "networkidle" } to allow JavaScript execution to complete.

How do I extract elements that are inside an iframe or shadow DOM?

Standard MCP selectors cannot pierce cross-origin iframes or shadow DOM boundaries. For iframes, use page.frame({ url: /pattern/ }) to get a frame object, then call waitForSelector on that frame. For shadow DOM, you must first query the host element, then access its shadowRoot property before running subsequent queries inside the shadow tree.

What does "Browser automation is required" mean in the clone workflow?

This error appears when the skill defined in .windsurf/workflows/clone-website.md cannot detect an available MCP tool at line 26. Run opencode list-mcp to confirm your agent has an active Chrome MCP or Playwright MCP connection. Without this protocol endpoint, the skill cannot drive browser automation and aborts the extraction process.

Why are my extracted CSS values empty or incorrect?

Empty computed styles usually indicate the element was located but is not visible or fully rendered in the viewport. Ensure you scrolled the element into view using scrollIntoView() and waited for the visible state before calling getComputedStyle. Also verify the viewport dimensions match the breakpoint where the target styles apply; responsive designs often hide or alter elements at different screen sizes.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →