---
name: Page Analysis
slug: page-analysis
category: Automation
description: Page Analysis analyzes a web page’s content, structure, metadata, and interactive elements using browser automation and Python. Use it to inspect a site, summarize what’s on it, or map its layout.
github: "https://github.com/billy-enrizky/openbrowser-ai/tree/main/plugin/skills/page-analysis"
language: Python
stars: 241
forks: 21
install: "npx degit https://github.com/billy-enrizky/openbrowser-ai/tree/main/plugin/skills/page-analysis ~/.claude/skills/page-analysis"
installs_to: ~/.claude/skills/page-analysis
source_path: plugin/skills/page-analysis/SKILL.md
collection_size: 7
category_size: 1648
collection_url: "https://dirskills.com/collections/billy-enrizky/openbrowser-ai"
added: 2026-09-02T05:21:55.363Z
last_synced: 2026-09-02T05:21:55.363Z
canonical_url: "https://dirskills.com/skills/page-analysis"
---

# Page Analysis

Page Analysis analyzes a web page’s content, structure, metadata, and interactive elements using browser automation and Python. Use it to inspect a site, summarize what’s on it, or map its layout.

**Install:**

```bash
npx degit https://github.com/billy-enrizky/openbrowser-ai/tree/main/plugin/skills/page-analysis ~/.claude/skills/page-analysis
```

## README

# Page Analysis

Analyze and understand web page content, structure, and interactive elements using Python code execution. Produces a comprehensive breakdown of what is on the page and how it is organized.

All code runs via `openbrowser-ai -c`. The daemon starts automatically and persists variables across calls. All browser functions are async -- use `await`.

The CLI daemon also persists cookies and login state in `~/.config/openbrowser/profiles/daemon/storage_state.json`, so authenticated sessions can be reused across later runs.

## Setup

Before running, verify openbrowser-ai is installed:

```bash
openbrowser-ai --help
```

If not found, install:

```bash
# macOS/Linux
curl -fsSL https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.sh | sh

# Windows (PowerShell)
irm https://raw.githubusercontent.com/billy-enrizky/openbrowser-ai/main/install.ps1 | iex
```

## Workflow

### Step 1 -- Navigate and get overview

```bash
openbrowser-ai -c - <<'EOF'
await navigate("https://example.com")
state = await browser.get_browser_state_summary()
print(f"Title: {state.title}")
print(f"URL: {state.url}")
print(f"Interactive elements: {len(state.dom_state.selector_map)}")
print(f"Tabs: {len(state.tabs)}")
EOF
```

### Step 2 -- Extract page metadata

```bash
openbrowser-ai -c - <<'EOF'
meta = await evaluate("""
(function(){
  return {
    title: document.title,
    description: document.querySelector("meta[name='description']")?.content,
    canonical: document.querySelector("link[rel='canonical']")?.href,
    ogTitle: document.querySelector("meta[property='og:title']")?.content,
    ogImage: document.querySelector("meta[property='og:image']")?.content,
    lang: document.documentElement.lang,
    charset: document.characterSet
  };
})()
""")

import json
print(json.dumps(meta, indent=2))
EOF
```

### Step 3 -- Detect frameworks and technologies

```bash
openbrowser-ai -c - <<'EOF'
tech = await evaluate("""
(function(){
  const t = [];
  if (window.__NEXT_DATA__) t.push("Next.js");
  if (window.__NUXT__) t.push("Nuxt.js");
  if (document.querySelector("[data-reactroot]") || document.querySelector("#__next")) t.push("React");
  if (document.querySelector("[ng-version]")) t.push("Angular");
  if (window.jQuery) t.push("jQuery");
  if (window.Vue) t.push("Vue.js");
  if (document.querySelector("[data-svelte]")) t.push("Svelte");
  return t;
})()
""")
print(f"Technologies detected: {tech}")
EOF
```

### Step 4 -- Content summary and statistics

```bash
openbrowser-ai -c - <<'EOF'
stats = await evaluate("""
(function(){
  return {
    headings: document.querySelectorAll("h1,h2,h3,h4,h5,h6").length,
    paragraphs: document.querySelectorAll("p").length,
    images: document.querySelectorAll("img").length,
    links: document.querySelectorAll("a").length,
    forms: document.querySelectorAll("form").length,
    tables: document.querySelectorAll("table").length,
    lists: document.querySelectorAll("ul,ol").length,
    buttons: document.querySelectorAll("button,[role='button']").length,
    inputs: document.querySelectorAll("input,textarea,select").length,
    iframes: document.querySelectorAll("iframe").length,
    scripts: document.querySelectorAll("script").length,
    stylesheets: document.querySelectorAll("link[rel='stylesheet']").length
  };
})()
""")

import json
print("Content statistics:")
print(json.dumps(stats, indent=2))
EOF
```

### Step 5 -- Analyze heading structure

```bash
openbrowser-ai -c - <<'EOF'
headings = await evaluate("""
(function(){
  return Array.from(document.querySelectorAll("h1,h2,h3,h4,h5,h6")).map(h => ({
    tag: h.tagName,
    text: h.textContent.trim().substring(0, 80)
  }));
})()
""")

for h in headings:
    htag = h["tag"]
    htext = h["text"]
    indent = "  " * (int(htag[1]) - 1)
    print(f"{indent}{htag}: {htext}")
EOF
```

### Step 6 -- Analyze interactive elements

```bash
openbrowser-ai -c - <<'EOF'
state = await browser.get_browser_state_summary()
elements_by_tag = {}
for idx, el in state.dom_state.selector_map.items():
    tag = el.tag_name
    elements_by_tag.setdefault(tag, []).append({
        "index": idx,
        "text": el.get_all_children_text(max_depth=1)[:50],
        "type": el.attributes.get("type", ""),
        "href": el.attributes.get("href", "")[:50] if el.attributes.get("href") else "",
    })

for tag, elems in sorted(elements_by_tag.items()):
    print(f"\n{tag} ({len(elems)} elements):")
    for e in elems[:5]:
        eidx = e["index"]
        etxt = e["text"]
        etype = e["type"]
        ehref = e["href"]
        print(f"  [{eidx}] text=\"{etxt}\" type={etype} href={ehref}")
    if len(elems) > 5:
        print(f"  ... and {len(elems) - 5} more")
EOF
```

### Step 7 -- Page dimensions and scroll analysis

```bash
openbrowser-ai -c - <<'EOF'
dims = await evaluate("""
(function(){
  return {
    viewportWidth: window.innerWidth,
    viewportHeight: window.innerHeight,
    scrollHeight: document.body.scrollHeight,
    scrollWidth: document.body.scrollWidth,
    scrollable: document.body.scrollHeight > window.innerHeight
  };
})()
""")

import json
print(json.dumps(dims, indent=2))
if dims["scrollable"]:
    pages = dims["scrollHeight"] / dims["viewportHeight"]
    print(f"Page is approximately {pages:.1f} viewport heights long")
EOF
```

### Step 8 -- Search for specific content patterns

```bash
openbrowser-ai -c - <<'EOF'
import re

# Get page text for Python-side analysis
text_content = await evaluate("document.body.innerText")

# Find emails
emails = re.findall(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", text_content)
print(f"Emails found: {emails}")

# Find phone numbers
phones = re.findall(r"\+?\d[\d\s()-]{7,}", text_content)
print(f"Phone numbers found: {phones}")

# Find dates
dates = re.findall(r"\d{4}-\d{2}-\d{2}|\w+ \d{1,2},? \d{4}", text_content)
print(f"Dates found: {dates}")
EOF
```

## Tips

- Code is piped via stdin using heredoc (`-c - <<'EOF'`), so all Python syntax works without shell escaping issues.
- Start with `evaluate()` for metadata and DOM statistics -- gives a fast structured overview.
- Use `browser.get_browser_state_summary()` for interactive element analysis.
- Use Python regex on extracted text for pattern matching (emails, phones, dates, prices).
- For long pages, use `await scroll(down=True)` and re-extract to analyze below-fold content.
- Variables persist between `-c` calls while the daemon is running, so you can build a comprehensive analysis incrementally.

## Cleanup

This step is **mandatory**. Run it after the analysis finishes, whether extraction succeeded or the page failed to load. Without it, the daemon keeps Chrome running until its 10-minute idle timeout, leaving a stale browser process, a locked profile, and (on macOS/Linux desktop) a visible window.

Stop the daemon, then verify it is gone:

```bash
openbrowser-ai daemon stop
openbrowser-ai daemon status
```

`daemon stop` closes every tab, exits Chrome, flushes saved cookies/login state to the profile, and shuts down the daemon process. `daemon status` should report the daemon is not running. If it still reports running, the daemon is wedged, force-kill it:

```bash
pkill -f 'openbrowser.*daemon' || true
```

If your invocation can fail mid-workflow (timeout, navigation error, malformed DOM), guarantee cleanup with a shell trap so the browser is never left orphaned:

```bash
trap 'openbrowser-ai daemon stop >/dev/null 2>&1 || true' EXIT
# ... openbrowser-ai -c calls here ...
```

Do not rely on the idle timeout. Do not call `done()` as a substitute, `done()` only marks the task complete inside the agent loop, it does not close the browser.
