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

> Fix extraction failures in AI-Website-Cloner-Template. Learn how to debug browser MCP element location issues caused by dynamic rendering, endpoint problems, and more.

- Repository: [JCodesMore/ai-website-cloner-template](https://github.com/JCodesMore/ai-website-cloner-template)
- Tags: how-to-guide
- Published: 2026-06-24

---

**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`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.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`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.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`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.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`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/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:

```javascript
// 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:

```javascript
// 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:

```javascript
// 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:

```javascript
// 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`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.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`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/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`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/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`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/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`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/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`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.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.