LayoutLens Quick Start Guide¶
Get started with AI-powered UI testing in 5 minutes.
🚀 Installation¶
pip install layoutlens
playwright install chromium # For screenshot capture
🔑 Setup¶
export OPENAI_API_KEY="sk-your-openai-key"
Get your API key from OpenAI Platform
Only needed for LLM-backed analysis. The deterministic axe-core accessibility
mode (below) needs no API key at all — LayoutLens() itself never requires
one at construction either; a missing key only raises when an LLM call is
actually made.
♿ Deterministic Accessibility Checks (No API Key Required)¶
LayoutLens vendors axe-core and runs it against a real rendered page for actual WCAG 2.1 A/AA violations:
layoutlens page.html --a11y axe
import asyncio
from layoutlens import AxeAuditor
async def main():
report = await AxeAuditor().audit("page.html")
print(report.summary())
print(report.ok) # True if zero violations
asyncio.run(main())
check_accessibility(source, mode="hybrid") (the default) combines this with
LLM vision analysis: axe grounds the LLM’s assessment and deterministically
forces a “no” verdict if it finds any violation. Pass mode="axe" for the
keyless deterministic-only check, or mode="llm" for the legacy vision-only
check.
Deterministic Layout and WCAG 2.2 Checks (No API Key Required)¶
The layout scanner measures geometry, contrast, WCAG 2.5.8 target spacing, WCAG 2.4.11 complete focus obscuration, and text occlusion such as a chart line painted across its label:
layoutlens page.html --layout deterministic
from layoutlens import LayoutScorer
report = await LayoutScorer().scan("page.html", viewport="mobile")
for finding in report.findings:
print(finding.defect_class, finding.selector, finding.measured)
These checks automate only their documented rendered-page scope. Their reports are evidence, not a site-wide WCAG conformance claim.
💡 Basic Usage¶
LayoutLens’s API is async — call it with await from an async def, or wrap
top-level calls in asyncio.run(...).
Analyze a Website¶
import asyncio
from layoutlens import LayoutLens
async def main():
lens = LayoutLens()
# Test any live website
result = await lens.analyze("https://example.com", "Is the navigation easy to use?")
print(f"Answer: {result.answer}")
print(f"Confidence: {result.confidence:.1%}")
asyncio.run(main())
Analyze Screenshots¶
# Test an existing screenshot image
result = await lens.analyze(
"screenshot.png", "Are the buttons large enough for mobile users?"
)
Compare Designs¶
# Compare two pages (URLs, local HTML files, or screenshot images)
result = await lens.compare(
["https://old-design.com", "https://new-design.com"],
"Which design is more user-friendly?",
)
📱 Built-in Checks¶
Mobile-Friendly Check¶
result = await lens.analyze_mobile_ux("https://your-site.com")
Accessibility Check¶
result = await lens.check_accessibility(
"https://your-site.com"
) # mode="hybrid" by default
Conversion Optimization¶
result = await lens.optimize_conversions("https://your-site.com")
🤖 CI Integration¶
There is no bundled GitHub composite action — call the CLI directly in your workflow:
name: UI Quality Check
on: [pull_request]
jobs:
ui-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install LayoutLens
run: |
pip install layoutlens
playwright install chromium
- name: Deterministic accessibility check (no API key needed)
run: layoutlens ${{ env.PREVIEW_URL }} --a11y axe
- name: AI quality check
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
layoutlens ${{ env.PREVIEW_URL }} "Is the layout professional and trustworthy?"
🎯 Common Use Cases¶
E-commerce Testing¶
queries = [
"Is the 'Add to Cart' button prominent and trustworthy?",
"Does the checkout process look simple?",
"Are product images clear and appealing?",
]
SaaS Dashboard Testing¶
queries = [
"Is the dashboard easy to navigate for new users?",
"Are the data visualizations clear?",
"Is the overall layout professional?",
]
Blog/Content Testing¶
queries = [
"Is the article easy to read?",
"Is the navigation helpful?",
"Does the layout encourage engagement?",
]
⚡ Advanced Usage¶
Batch Analysis¶
analyze() handles single or multiple sources/queries directly — pass lists
to fan out concurrently:
urls = ["https://page1.com", "https://example.com/page2", "https://example.com/page3"]
queries = ["Is navigation consistent?", "Is mobile experience good?"]
result = await lens.analyze(source=urls, query=queries) # returns a BatchResult
print(f"Average confidence: {result.average_confidence:.1%}")
Cross-Browser Testing¶
# Compare pre-captured screenshots from different browsers
result = await lens.compare(
sources=["chrome.png", "firefox.png", "safari.png"],
query="Are these layouts consistent across browsers?",
)
Custom Context¶
result = await lens.analyze(
"https://example.com/dashboard",
"Is this suitable for elderly users?",
context={
"user_type": "elderly",
"accessibility": True,
},
)
YAML Test Suites¶
Every test case requires expected_results (breaking change in v1.7.0 — see
the main README
for the full schema):
import yaml
from layoutlens import LayoutLens, UITestSuite
with open("test_suite.yaml") as f:
suite = UITestSuite.from_dict(yaml.safe_load(f))
lens = LayoutLens()
results = await lens.run_test_suite(suite)
🎨 Customization¶
Custom Queries for Your Domain¶
E-commerce:
“Does this product page increase purchase confidence?”
“Is the pricing clear and competitive-looking?”
“Are trust signals visible (security, reviews, guarantees)?”
SaaS:
“Would new users understand how to get started?”
“Are upgrade prompts balanced (not annoying)?”
“Is the feature hierarchy clear?”
Content:
“Is this article layout engaging and readable?”
“Are social sharing options visible?”
“Does the design encourage newsletter signup?”
🔧 Troubleshooting¶
Common Issues¶
“API key required” error:
export OPENAI_API_KEY="sk-your-key"
# Or pass directly: LayoutLens(api_key="sk-your-key")
This only happens when an LLM call is actually made — LayoutLens()
construction and mode="axe" accessibility checks never require a key.
Playwright install error:
playwright install chromium
Screenshot capture fails:
Check the URL is accessible
Try with
wait_timeparameter for slow-loading pages
Getting Help¶
🎯 Next Steps¶
Try the examples in
examples/(e.g.python examples/simple_api_usage.py)Set up CI for your repository
Customize queries for your specific use case
Integrate with your deployment pipeline
Ready to improve your UI quality with AI? Start with a simple analysis and expand from there! 🚀