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_time parameter for slow-loading pages

Getting Help

🎯 Next Steps

  1. Try the examples in examples/ (e.g. python examples/simple_api_usage.py)

  2. Set up CI for your repository

  3. Customize queries for your specific use case

  4. Integrate with your deployment pipeline


Ready to improve your UI quality with AI? Start with a simple analysis and expand from there! 🚀