Core API¶
The core module provides the main user-facing API for LayoutLens.
LayoutLens Class¶
- class layoutlens.LayoutLens(api_key=None, model='gpt-4o-mini', provider='openai', output_dir='layoutlens_output', cache_enabled=True, cache_type='memory', cache_ttl=3600, api_base=None, temperature=None)[source]¶
Bases:
objectSimple API for AI-powered UI testing with natural language.
This class provides an intuitive interface for analyzing websites and screenshots using natural language queries, designed for developer workflows and CI/CD integration.
Examples: >>> lens = LayoutLens(api_key=”sk-…”) >>> result = lens.analyze(”https://example.com”, “Is the navigation clearly visible?”) >>> print(result.answer)
>>> # Compare two designs >>> result = lens.compare( ... ["before.png", "after.png"], ... "Are these layouts consistent?" ... )
- Parameters:
- async analyze(source: str | Path, query: str, viewport: Viewport | str = 'desktop', context: dict[str, Any] | None = None, instructions: Instructions | None = None, max_concurrent: int = 5) AnalysisResult[source]¶
- async analyze(source: list[str | Path], query: str | list[str], viewport: Viewport | str = 'desktop', context: dict[str, Any] | None = None, instructions: Instructions | None = None, max_concurrent: int = 5) BatchResult
- async analyze(source: str | Path, query: list[str], viewport: Viewport | str = 'desktop', context: dict[str, Any] | None = None, instructions: Instructions | None = None, max_concurrent: int = 5) BatchResult
Smart analyze method that handles single or multiple sources and queries.
- Parameters:
source (str | Path | list[str | Path]) – Single URL/path or list of URLs/paths to analyze.
query (str | list[str]) – Single question or list of questions about the UI.
viewport (Viewport | str) – Viewport for capture (Viewport.DESKTOP, “desktop”, etc.).
context (dict[str, Any] | None) – Additional context for analysis (user_type, browser, etc.). Legacy format.
instructions (Instructions | None) – Rich instruction set with expert personas and structured context. Takes precedence over context if both provided.
max_concurrent (int) – Maximum concurrent operations for batch analysis.
- Returns:
AnalysisResult for single source+query, BatchResult for multiple.
- Return type:
Examples
# Single analysis >>> result = await lens.analyze(”https://github.com”, “Is it accessible?”)
# Multiple queries on one source >>> result = await lens.analyze(”https://github.com”, [“Is it accessible?”, “Mobile-friendly?”])
# Multiple sources, one query >>> result = await lens.analyze([“page1.html”, “page2.html”], “Is it good?”)
# Multiple sources and queries >>> result = await lens.analyze([“page1.html”, “page2.html”], [“Accessible?”, “Mobile?”])
- async compare(sources, query='Are these layouts consistent?', viewport='desktop', context=None, instructions=None)[source]¶
Compare multiple URLs or screenshots.
- Parameters:
sources (list[str | Path]) – List of URLs or screenshot paths to compare.
query (str) – Natural language question for comparison.
viewport (Viewport | str) – Viewport for captures (Viewport.DESKTOP or string).
context (dict[str, Any] | None) – Additional context for analysis.
instructions (Instructions | None) – Rich instructions for expert analysis.
- Returns:
Comparison analysis with overall assessment.
- Return type:
Example
>>> result = await lens.compare([ ... "https://example.com/before", ... "https://example.com/after" ... ], "Did the redesign improve the user experience?")
- async capture(source: str | Path, viewport: Viewport | str = 'desktop', wait_for_selector: str | None = None, wait_time: int | None = None, max_concurrent: int = 3) str[source]¶
- async capture(source: list[str | Path], viewport: Viewport | str = 'desktop', wait_for_selector: str | None = None, wait_time: int | None = None, max_concurrent: int = 3) dict[str, str]
Smart capture method that handles single or multiple sources uniformly.
- Parameters:
source (str | Path | list[str | Path]) – Single URL/path or list of URLs/paths to capture.
viewport (Viewport | str) – Viewport for capture (Viewport.DESKTOP, “desktop”, etc.).
wait_for_selector (str | None) – CSS selector to wait for before capturing.
wait_time (int | None) – Additional wait time in milliseconds.
max_concurrent (int) – Maximum concurrent captures for multiple sources.
- Returns:
Returns screenshot path as string. Multiple sources: Returns dict mapping source to screenshot path.
- Return type:
Single source
Examples
# Single URL >>> path = await lens.capture(”https://example.com”) # Returns: “/path/to/screenshot.png”
# Multiple URLs >>> paths = await lens.capture([”https://example.com/page1”, “https://site2.com”]) # Returns: {”https://example.com/page1”: “/path1.png”, “https://site2.com”: “/path2.png”}
# HTML files >>> path = await lens.capture(“page.html”) >>> paths = await lens.capture([“page1.html”, “page2.html”])
# Existing images (validation) >>> path = await lens.capture(“screenshot.png”)
- async judge(image_path, prompt, *, max_tokens=AUTO, timeout=120.0)[source]¶
Send
promptVERBATIM with an image and return a parsed verdict.This is the faithful judge interface for external evaluation harnesses (e.g. UIJudgeBench). Unlike
analyze(), LayoutLens adds NOTHING to the prompt: no system persona, no scaffolding, no appended JSON-format instruction. The caller owns the entire prompt, including any response contract. The call always hits the model (no caching) and honors the per-model parameter policy (Claude 4.6+/5 omit temperature).- Parameters:
image_path (str | Path) – Path to an existing image file (mime inferred from the extension:
.jpg/.jpeg-> JPEG, otherwise PNG).prompt (str) – The exact text to send as the sole text block.
max_tokens (int | _Auto) – Maximum tokens to generate. Defaults to
AUTO, which resolves to 8000 for reasoning/thinking models (they spend thinking tokens inside this budget) and 300 otherwise. Pass an explicit integer to override.timeout (float) – Per-call timeout in seconds (default 120 — reasoning models can take well over 30s on a single judgment).
- Returns:
JudgeResult with the parsed answer/confidence/rationale, the raw text, a refusal flag, per-model usage split, and the parse mode.
- Raises:
ValidationError – If
image_pathdoes not exist.AuthenticationError – If no API key is configured for a mapped provider.
- Return type:
- async judge_batch(requests, *, max_tokens=AUTO, resume=True, manifest_path=None, poll_interval=10.0, poll_timeout=86400.0, reasoning_effort=None, image_detail='auto')[source]¶
Judge many image+prompt requests over a provider batch transport.
The batched counterpart to
judge(): each request sends its prompt VERBATIM with the same image bytes asjudge(), honors the reasoning-awaremax_tokensdefault and the per-model parameter policy, and is parsed into aJudgeResult. Batch APIs are ~50% cheaper and the right transport for bulk offline evaluation (e.g. UIJudgeBench). LayoutLens is thus the reference batched judge.The backend is chosen from an explicit provider/model combination:
provider="gemini"withgemini/*uses the google-genai inline batch (optional extralayoutlens[gemini]); native OpenAI uses the official Responses Batch API, and supported non-Gemini/non-OpenAI providers use the litellm file-based batch. All backends are resumable via a manifest.- Parameters:
requests (list[BatchRequest]) – The batch items. Each
idmust be unique and keys its result. A request whose image is missing yields an"unknown"result rather than aborting the batch.max_tokens (int | _Auto) – Per-request token budget. Defaults to
AUTO(8000 for reasoning models, else 300); an explicit integer overrides.resume (bool) – When True (default), collect any prior jobs from the manifest first and submit only uncovered ids. When False, the selected manifest path must not already exist.
manifest_path (str | Path | None) – Where submitted job ids persist for resume. Defaults to a content-addressed path under
output_dir/batchkeyed by the backend, endpoint, model, token budget, reasoning effort, image detail, exact prompts, image MIME types, and image bytes.poll_interval (float) – Seconds between batch-status polls.
poll_timeout (float) – Max seconds to wait for a single batch job.
reasoning_effort (str | None) – Native OpenAI reasoning effort.
Noneretains the model default; otherwise one ofnone,low,medium,high,xhigh, ormax. Rejected for other providers so a requested setting is never silently ignored.image_detail (str) – Native OpenAI image-detail setting:
auto,low,high, ororiginal. Non-default values are rejected for other providers.
- Returns:
{request_id: JudgeResult}for every request.- Raises:
AuthenticationError – If no API key is configured for a mapped provider.
ImportError – If a
gemini/*model is used withoutgoogle-genai.ValidationError – If request ids repeat or an existing resume manifest does not match the exact request.
- Return type:
- async check_accessibility(source, standards=None, compliance_level='AA', viewport='desktop', mode='hybrid')[source]¶
Accessibility audit: deterministic axe-core, LLM vision, or both.
- Parameters:
standards (list[str] | None) – Accessibility standards to apply (default: WCAG 2.1, Section 508)
compliance_level (ComplianceLevel | str) – WCAG compliance level (ComplianceLevel.AA or string)
viewport (Viewport | str) – Viewport for analysis (Viewport.DESKTOP or string)
mode (Literal['hybrid', 'axe', 'llm']) –
"hybrid"(default) combines deterministic axe-core checks with LLM analysis (axe violations force a “no” verdict)."axe"runs axe-core only (no API key required)."llm"runs the legacy vision-only audit. The axe run honorscompliance_level: A ->wcag2a, AA ->wcag2a``+``wcag2aa, AAA additionally includeswcag2aaa.
- Returns:
Detailed accessibility assessment with specific WCAG guidance
- Raises:
ValueError – If compliance_level is not a valid WCAG level
- Return type:
- async check_layout(source, viewport='desktop', mode='hybrid', scorer=None)[source]¶
Layout check: deterministic geometry/contrast scan, LLM vision, or both.
The deterministic scan measures contrast, sibling overlap, clipped content, viewport protrusion, page-level horizontal overflow, truncated text, WCAG-aware target spacing, complete focus obscuration, and text occlusion — directly off the rendered page, with no LLM and no API key.
- Parameters:
source (str | Path) – URL or HTML file to check (images have no DOM to measure — use
mode="llm"for pre-rendered screenshots).viewport (Viewport | str) – Viewport for the scan/capture.
mode (Literal['hybrid', 'deterministic', 'llm']) –
"hybrid"(default) runs the deterministic scan AND LLM vision, forcing a “no” verdict when the scan measures any defect."deterministic"runs the scan only — keyless."llm"is vision-only.scorer (LayoutScorer | None) – Optional pre-configured
LayoutScorer(custom thresholds).
- Returns:
AnalysisResult. In deterministic/hybrid modes
metadata["layout"]holds the full layout report with per-finding measurements.- Raises:
ValidationError – In
deterministicmode whensourceis an image, which has no DOM to measure.- Return type:
- async optimize_conversions(source, business_goals=None, industry=None, target_audience=None, viewport='desktop')[source]¶
Conversion rate optimization analysis using CRO expert knowledge.
- Parameters:
business_goals (list[str] | None) – Business objectives (e.g., reduce_cart_abandonment)
industry (str | None) – Industry context for specialized recommendations
target_audience (str | None) – Target audience for optimization focus
viewport (Viewport | str) – Viewport for analysis (Viewport.DESKTOP or string)
- Returns:
Detailed CRO recommendations with A/B testing suggestions
- Return type:
- async analyze_mobile_ux(source, device_types=None, performance_focus=True)[source]¶
Mobile UX analysis using mobile expert knowledge.
- async audit_ecommerce(source, page_type='product_page', business_model='b2c', viewport='desktop')[source]¶
E-commerce UX audit using retail expert knowledge.
- Parameters:
- Returns:
E-commerce specific recommendations for conversion improvement
- Return type:
- async analyze_with_expert(source, query, expert_persona, focus_areas=None, user_context=None, viewport='desktop')[source]¶
Analyze using a specific domain expert persona.
- Parameters:
query (str) – Question to analyze
expert_persona (Expert | str) – Expert to use (Expert.ACCESSIBILITY or string)
focus_areas (list[str] | None) – Specific areas to focus analysis on
user_context (dict[str, Any] | None) – Rich context about users and requirements
viewport (Viewport | str) – Viewport for analysis (Viewport.DESKTOP or string)
- Returns:
Expert-level analysis with domain-specific recommendations
- Return type:
- async compare_with_expert(sources, query, expert_persona, focus_areas=None, viewport='desktop')[source]¶
Compare multiple sources using domain expert knowledge.
- Parameters:
sources (list[str | Path]) – List of URLs or file paths to compare
query (str) – Comparison question
expert_persona (Expert | str) – Expert to use for comparison (Expert.ACCESSIBILITY or string)
focus_areas (list[str] | None) – Specific areas to focus comparison on
viewport (Viewport | str) – Viewport for analysis (Viewport.DESKTOP or string)
- Returns:
Expert comparison with domain-specific insights
- Return type:
- async run_test_suite(suite, parallel=False, max_workers=4)[source]¶
Run a test suite and return one result per test case.
- Parameters:
suite (UITestSuite) – The test suite to run.
parallel (bool) – Run test cases concurrently instead of serially.
max_workers (int) – Maximum concurrent test cases when
parallel.
- Returns:
List of
UITestResultobjects, in suite order.- Return type:
Result Classes¶
- class layoutlens.AnalysisResult(source, query, answer, confidence, reasoning, screenshot_path=None, viewport='desktop', timestamp=<factory>, execution_time=0.0, metadata=<factory>)[source]¶
Bases:
objectResult from analyzing a single URL or screenshot.
- Parameters:
- class layoutlens.ComparisonResult(sources, query, answer, confidence, reasoning, individual_analyses=<factory>, screenshot_paths=<factory>, timestamp=<factory>, execution_time=0.0, metadata=<factory>)[source]¶
Bases:
objectResult from comparing multiple sources.
- Parameters:
- individual_analyses: list[AnalysisResult]¶
- class layoutlens.BatchResult(results, total_queries, successful_queries, average_confidence, total_execution_time, total_prompt_tokens=0, total_completion_tokens=0, total_tokens=0, estimated_cost_usd=None, timestamp=<factory>)[source]¶
Bases:
objectResult from batch analysis.
- Parameters:
- results: list[AnalysisResult]¶
Test Suite Classes¶
- class layoutlens.UITestCase(name, html_path, queries, viewports=<factory>, metadata=<factory>, expected_results=None, expected_confidence=0.7)[source]¶
Bases:
objectRepresents a single test case for UI testing.
expected_resultsdeclares what the analysis must assert against and is required (seeUITestSuite.from_dict). Schema:expected_results: answer: "yes" # or "no" — compared against the # parsed yes/no of the analysis answer contains: ["nav", "contrast"] # optional; each term must appear # (case-insensitively) in answer + reasoning
Both keys are individually optional, but at least one of them must be present — an empty or missing
expected_resultsis a load-time error.expected_confidencesets the minimumresult.confidencerequired in addition to any content assertions.- Parameters:
- class layoutlens.UITestSuite(name, description, test_cases, metadata=<factory>)[source]¶
Bases:
objectRepresents a collection of test cases.
- test_cases: list[UITestCase]¶
- classmethod from_dict(data)[source]¶
Create test suite from dictionary.
- Parameters:
- Returns:
Validated test suite.
- Raises:
ValidationError – If any test case is missing
expected_results(or declares neither “answer” nor “contains”). Assertions are required per case — there is no confidence-only fallback.- Return type:
- classmethod load(filepath)[source]¶
Load a test suite from a JSON or YAML file (by extension).
- Parameters:
filepath (Path)
- Return type:
- classmethod from_yaml(filepath)[source]¶
Load a test suite from a YAML file.
- Parameters:
- Return type:
- classmethod from_specs(name, description, test_cases)[source]¶
Create a test suite from test-case spec dicts.
Each spec follows the same shape as a YAML test case, including a required
expected_results(see theUITestCasedocstring for schema) — validated identically to, and via the same helper as,from_dict().- Parameters:
- Returns:
Validated test suite.
- Raises:
ValidationError – If any spec is missing
expected_results.- Return type: