browse-seo: SEO Audit for AI Agents
Goal
Run a complete on-page SEO audit for a target URL using the browse CLI. Extract technical
SEO signals, analyze them, and produce a report with findings and recommendations.
Step 0: Consider stealth setup (optional)
If the audit target is behind bot detection (Cloudflare, competitor sites), use camoufox:
browse --runtime camoufox --headed goto <url>
For most public pages, the default Chromium runtime is sufficient. Skip unless you hit blocks.
Step 1: Navigate to the target URL
browse goto <url>
browse wait --network-idle
Verify the page loaded. Note any redirects -- redirect chains matter for SEO. If the page
returns 403 or a challenge, switch to camoufox (Step 0).
Step 2: Extract meta tags
browse meta
Returns title, description, canonical, OG tags, Twitter Card, robots, and viewport. Check:
- Title: present, under 60 chars, contains target keywords
- Description: present, 120-160 chars, compelling and unique
- Canonical: present, correct URL (trailing slashes, www vs non-www)
- Robots: no accidental
noindex or nofollow
- Viewport:
width=device-width, initial-scale=1 for mobile
- OG tags:
og:title, og:description, og:image, og:url all present
- Twitter Card:
twitter:card, twitter:title, twitter:description present
Step 3: Check heading structure
browse headings
Returns H1-H6 hierarchy with counts. Check:
- Exactly one H1: multiple H1s dilute the primary topic signal
- H1 matches topic: should contain the primary keyword
- Logical nesting: H2 under H1, H3 under H2 -- no skipped levels
- Keyword presence: target keywords in H1 and H2 tags
Step 4: Extract structured data
browse schema
Extracts JSON-LD, Microdata, and RDFa from the page. Check:
- Presence: at least one schema type (Article, Product, Organization, etc.)
- Required properties: each type needs required fields per Google's docs
- Valid JSON-LD: no syntax errors or malformed objects
- Correct @type: matches actual page content
- Missing opportunities: FAQ, HowTo, Breadcrumb, Review where content supports it
Step 5: Check performance
browse perf
Returns navigation timing (DNS, TTFB, DOM load, full load). Check:
- TTFB: under 200ms good, over 600ms problem
- DOM Content Loaded: under 1.5s acceptable
- Full load: under 3s for good UX
- DNS: near zero with proper prefetching
Use browse network to inspect render-blocking resources, large assets, and request counts.
Step 6: Analyze link structure
browse links
Returns all anchor elements with text and href. Check:
- Internal links: sufficient linking for crawlability
- Anchor text: descriptive, not "click here" or bare URLs
- External links: appropriate outbound links, nofollow where needed
- Broken links: anything pointing to 404 or error pages
Step 7: Check mobile rendering
browse responsive
Captures screenshots at mobile (375px), tablet (768px), and desktop (1440px). Review for:
- Mobile layout: no horizontal scrolling, readable without zooming
- Tap targets: 48px minimum for touch
- Content parity: mobile has same critical content as desktop
- Font size: 16px minimum base font
Use browse screenshot for a single full-page capture if needed.
Step 8: Custom checks via JavaScript
Run targeted checks the built-in commands do not cover:
# Image alt tags
browse js "const imgs=[...document.querySelectorAll('img')]; const missing=imgs.filter(i=>!i.alt&&!i.getAttribute('role')); JSON.stringify({total:imgs.length,missingAlt:missing.length,examples:missing.slice(0,5).map(i=>i.src.slice(-60))})"
# Duplicate meta tags
browse js "JSON.stringify({titles:document.querySelectorAll('title').length,descriptions:document.querySelectorAll('meta[name=description]').length,canonicals:document.querySelectorAll('link[rel=canonical]').length})"
# Hreflang tags
browse js "JSON.stringify([...document.querySelectorAll('link[rel=alternate][hreflang]')].map(t=>({lang:t.hreflang,href:t.href})))"
# Lazy images without dimensions
browse js "const lazy=[...document.querySelectorAll('img[loading=lazy]')]; const noDims=lazy.filter(i=>!i.width&&!i.height&&!i.getAttribute('width')); JSON.stringify({lazyImages:lazy.length,missingDimensions:noDims.length})"
Check robots.txt and sitemap:
browse goto <origin>/robots.txt
browse text
browse goto <origin>/sitemap.xml
browse text
Step 9: Generate the audit report
After collecting data from Steps 2-8, produce a structured report:
- Summary: one-paragraph overview with pass/fail/warning counts
- Meta Tags: title, description, canonical, robots, OG, Twitter -- each rated
- Heading Structure: H1 count, nesting issues, keyword presence
- Structured Data: schema types found, missing opportunities, validation issues
- Performance: TTFB, load times, blocking resources
- Link Analysis: internal/external ratio, broken links, anchor text quality
- Mobile Friendliness: viewport tag, responsive screenshots, tap target issues
- Images: alt tag coverage, lazy loading, dimension attributes
- Recommendations: prioritized fixes (critical, important, nice-to-have)
Rate each section as PASS, WARNING, or FAIL. Prioritize recommendations by impact.
Important Rules
- The browser persists between commands. Cookies, tabs, and session state carry over.
- After
goto, always wait --network-idle before extracting data.
- The agent interprets all results. Browse extracts raw data; analysis is your job.
- Do not install anything automatically.
- Save screenshots under
.browse/ directories.
- For sites that block bots, use
--runtime camoufox --headed.
1---2name: browse-seo3description: Run a full on-page technical SEO audit from a LIVE render — real rendered signals, not source guesses — extracting meta tags, heading hierarchy, structured data, navigation timing, link structure, and multi-viewport mobile rendering via the `browse` CLI (meta/headings/schema/perf/ links/responsive plus targeted JS checks), then rating each area PASS/WARNING/FAIL with prioritized fixes. The agent interprets the raw signals browse extracts; no scores are invented. Use to audit a page's technical/on-page SEO health.4---5
6# browse-seo: SEO Audit for AI Agents
7
8## Goal
9
10Run a complete on-page SEO audit for a target URL using the `browse` CLI. Extract technical
11SEO signals, analyze them, and produce a report with findings and recommendations.
12
13## Step 0: Consider stealth setup (optional)
14
15If the audit target is behind bot detection (Cloudflare, competitor sites), use camoufox:
16
17```bash
18browse --runtime camoufox --headed goto <url>
19```
20
21For most public pages, the default Chromium runtime is sufficient. Skip unless you hit blocks.
22
23## Step 1: Navigate to the target URL
24
25```bash
26browse goto <url>
27browse wait --network-idle
28```
29
30Verify the page loaded. Note any redirects -- redirect chains matter for SEO. If the page
31returns 403 or a challenge, switch to camoufox (Step 0).
32
33## Step 2: Extract meta tags
34
35```bash
36browse meta
37```
38
39Returns title, description, canonical, OG tags, Twitter Card, robots, and viewport. Check:
40
41- **Title**: present, under 60 chars, contains target keywords
42- **Description**: present, 120-160 chars, compelling and unique
43- **Canonical**: present, correct URL (trailing slashes, www vs non-www)
44- **Robots**: no accidental `noindex` or `nofollow`
45- **Viewport**: `width=device-width, initial-scale=1` for mobile
46- **OG tags**: `og:title`, `og:description`, `og:image`, `og:url` all present
47- **Twitter Card**: `twitter:card`, `twitter:title`, `twitter:description` present
48
49## Step 3: Check heading structure
50
51```bash
52browse headings
53```
54
55Returns H1-H6 hierarchy with counts. Check:
56
57- **Exactly one H1**: multiple H1s dilute the primary topic signal
58- **H1 matches topic**: should contain the primary keyword
59- **Logical nesting**: H2 under H1, H3 under H2 -- no skipped levels
60- **Keyword presence**: target keywords in H1 and H2 tags
61
62## Step 4: Extract structured data
63
64```bash
65browse schema
66```
67
68Extracts JSON-LD, Microdata, and RDFa from the page. Check:
69
70- **Presence**: at least one schema type (Article, Product, Organization, etc.)
71- **Required properties**: each type needs required fields per Google's docs
72- **Valid JSON-LD**: no syntax errors or malformed objects
73- **Correct @type**: matches actual page content
74- **Missing opportunities**: FAQ, HowTo, Breadcrumb, Review where content supports it
75
76## Step 5: Check performance
77
78```bash
79browse perf
80```
81
82Returns navigation timing (DNS, TTFB, DOM load, full load). Check:
83
84- **TTFB**: under 200ms good, over 600ms problem
85- **DOM Content Loaded**: under 1.5s acceptable
86- **Full load**: under 3s for good UX
87- **DNS**: near zero with proper prefetching
88
89Use `browse network` to inspect render-blocking resources, large assets, and request counts.
90
91## Step 6: Analyze link structure
92
93```bash
94browse links
95```
96
97Returns all anchor elements with text and href. Check:
98
99- **Internal links**: sufficient linking for crawlability
100- **Anchor text**: descriptive, not "click here" or bare URLs
101- **External links**: appropriate outbound links, nofollow where needed
102- **Broken links**: anything pointing to 404 or error pages
103
104## Step 7: Check mobile rendering
105
106```bash
107browse responsive
108```
109
110Captures screenshots at mobile (375px), tablet (768px), and desktop (1440px). Review for:
111
112- **Mobile layout**: no horizontal scrolling, readable without zooming
113- **Tap targets**: 48px minimum for touch
114- **Content parity**: mobile has same critical content as desktop
115- **Font size**: 16px minimum base font
116
117Use `browse screenshot` for a single full-page capture if needed.
118
119## Step 8: Custom checks via JavaScript
120
121Run targeted checks the built-in commands do not cover:
122
123```bash
124# Image alt tags
125browse js "const imgs=[...document.querySelectorAll('img')]; const missing=imgs.filter(i=>!i.alt&&!i.getAttribute('role')); JSON.stringify({total:imgs.length,missingAlt:missing.length,examples:missing.slice(0,5).map(i=>i.src.slice(-60))})"
126
127# Duplicate meta tags
128browse js "JSON.stringify({titles:document.querySelectorAll('title').length,descriptions:document.querySelectorAll('meta[name=description]').length,canonicals:document.querySelectorAll('link[rel=canonical]').length})"
129
130# Hreflang tags
131browse js "JSON.stringify([...document.querySelectorAll('link[rel=alternate][hreflang]')].map(t=>({lang:t.hreflang,href:t.href})))"
132
133# Lazy images without dimensions
134browse js "const lazy=[...document.querySelectorAll('img[loading=lazy]')]; const noDims=lazy.filter(i=>!i.width&&!i.height&&!i.getAttribute('width')); JSON.stringify({lazyImages:lazy.length,missingDimensions:noDims.length})"
135```
136
137Check robots.txt and sitemap:
138
139```bash
140browse goto <origin>/robots.txt
141browse text
142browse goto <origin>/sitemap.xml
143browse text
144```
145
146## Step 9: Generate the audit report
147
148After collecting data from Steps 2-8, produce a structured report:
149
1501. **Summary**: one-paragraph overview with pass/fail/warning counts
1512. **Meta Tags**: title, description, canonical, robots, OG, Twitter -- each rated
1523. **Heading Structure**: H1 count, nesting issues, keyword presence
1534. **Structured Data**: schema types found, missing opportunities, validation issues
1545. **Performance**: TTFB, load times, blocking resources
1556. **Link Analysis**: internal/external ratio, broken links, anchor text quality
1567. **Mobile Friendliness**: viewport tag, responsive screenshots, tap target issues
1578. **Images**: alt tag coverage, lazy loading, dimension attributes
1589. **Recommendations**: prioritized fixes (critical, important, nice-to-have)
159
160Rate each section as PASS, WARNING, or FAIL. Prioritize recommendations by impact.
161
162## Important Rules
163
164- The browser persists between commands. Cookies, tabs, and session state carry over.
165- After `goto`, always `wait --network-idle` before extracting data.
166- The agent interprets all results. Browse extracts raw data; analysis is your job.
167- Do not install anything automatically.
168- Save screenshots under `.browse/` directories.
169- For sites that block bots, use `--runtime camoufox --headed`.