# UX Evidence Auditor — Website UX & Regression API (`invincible_nova/deterministic-ux-auditor`) Actor

Audit public web pages on desktop and mobile with deterministic UX checks, element-level evidence, screenshots, and regression tracking for releases and SEO workflows.

- **URL**: https://apify.com/invincible\_nova/deterministic-ux-auditor.md
- **Developed by:** [Sergei Pechenov](https://apify.com/invincible_nova) (community)
- **Categories:** Developer tools, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

Audit public web pages on desktop and mobile with reproducible, non-AI checks. Every finding includes a stable issue ID, affected selector, measured evidence, severity, methodology, and recommendation.

Use this Actor for release checks, scheduled UX monitoring, agency QA, technical SEO workflows, and machine-readable evidence for agents or CI.

### What it checks

The Actor combines two deterministic layers:

- WCAG 2.x A/AA checks from axe-core, including accessible names, labels, language, document title, alternative text, ARIA validity, contrast, and other rules that can be decided automatically.
- Browser-rendered UX checks for horizontal overflow, mobile viewport metadata, undersized and crowded touch targets, very small leaf text, broken images, heading hierarchy, main landmarks, and HTTP errors.

The touch-target check follows the WCAG 2.2 minimum of 24 × 24 CSS pixels plus spacing geometry. Exceptions that require context are named in the finding instead of being silently treated as certain failures.

To keep results usable, the Dataset contains at most 10 element examples per rule and viewport. Repeated instances do not multiply the score penalty.

### Try it

```json
{
  "startUrls": [{ "url": "https://example.com" }],
  "auditDesktop": true,
  "auditMobile": true
}
```

One Dataset item is produced for each page × viewport audit. A failed page is isolated as a `status: "failed"` item so other URLs can still finish.

Useful options:

- `saveScreenshots` stores one JPEG of the visible viewport per audit. Screenshots provide visual evidence and do not affect findings or scoring.
- `waitAfterLoadMs` gives client-rendered interfaces time to settle.
- `maxPages` and `maxConcurrency` control run size. Effective concurrency is capped at roughly one browser page per 1 GB of Actor memory.
- `monitorKey` compares stable issue IDs with a previous run.
- `updateBaseline` saves the current IDs as the next regression baseline.

Only public HTTP(S) pages are accepted. URLs with credentials, local/private/reserved targets, and hostnames resolving to private networks are blocked. Login sessions, cookies, CAPTCHA bypass, and private-network auditing are intentionally unsupported.

### Output

```json
{
  "status": "ok",
  "url": "https://example.com/checkout",
  "finalUrl": "https://example.com/checkout",
  "httpStatus": 200,
  "viewport": "mobile",
  "score": 76,
  "issueCount": 4,
  "issues": [
    {
      "issueId": "touch_target_size-ef452bb1e13d8d2a",
      "ruleId": "TOUCH_TARGET_SIZE",
      "severity": "minor",
      "selector": "main > form > button:nth-of-type(1)",
      "bbox": { "x": 24, "y": 612, "width": 18, "height": 18 },
      "metrics": { "widthPx": 18, "heightPx": 18, "minimumPx": 24 },
      "methodology": "Automated geometry check for WCAG 2.2 SC 2.5.8; exceptions may require review"
    }
  ],
  "coverage": {
    "customRulesEvaluated": 8,
    "axeViolationRules": 1,
    "axePassedRules": 22,
    "axeIncompleteRules": 2,
    "axeInapplicableRules": 31
  },
  "regression": {
    "baselineFound": true,
    "newIssueIds": ["touch_target_size-ef452bb1e13d8d2a"],
    "resolvedIssueIds": [],
    "persistentIssueIds": []
  },
  "screenshotUrl": "https://api.apify.com/v2/key-value-stores/.../records/...",
  "screenshotFullPage": false,
  "engineVersion": "0.2.0"
}
```

Viewport screenshots and a compact `SUMMARY` record are stored in the default Key-value store. Set `saveScreenshots` to `false` for machine-only runs that do not need visual evidence.

### Regression monitoring

1. Choose a hard-to-guess `monitorKey` for one site or deployment pipeline.
2. Run with `updateBaseline: true` to establish the baseline.
3. Reuse the same key and URL set on later runs.
4. Read `newIssueIds`, `resolvedIssueIds`, and `persistentIssueIds`.

Stable IDs use normalized final URL, viewport, rule ID, and DOM selector. A major template refactor can therefore resolve an old selector and introduce a new one.

### Scoring

The score is a prioritization aid, not a universal UX grade. Custom rule families have fixed weights; all axe WCAG violations contribute through one accessibility score family so a long page is not punished merely for having more DOM nodes. Critical findings cap the score at 60, and three or more major rule families cap it at 75.

Use issue evidence, axe incomplete counts, and regression diffs for decisions. Do not use the score alone as a compliance claim.

### What automation cannot prove

A clean report means that no implemented deterministic rule found a violation. It does not certify WCAG compliance and does not replace:

- moderated usability research or task-completion testing;
- judgment about business goals, persuasion, clarity, or user intent;
- keyboard workflows and interactive states that were not opened during this URL-level run;
- legal accessibility review.

axe-core itself reports cases that need human review. Their count is exposed as `coverage.axeIncompleteRules` rather than converted into fabricated failures.

### Privacy and operational limits

- No screenshot or page content is sent to an AI provider.
- Screenshots remain in the run's Apify storage and are optional.
- The Actor requests only supplied public pages and their public subresources.
- Up to 50 input pages and two viewports are supported per run.
- Each page failure is isolated; the run summary records requested, completed, and failed audits.

### Automation examples

- Run after a deployment and alert on new critical issue IDs.
- Schedule weekly desktop/mobile audits in Apify Console.
- Send Dataset items to Make, Zapier, n8n, Google Sheets, Slack, or a webhook.
- Compare a fixed set of landing pages for an agency after each release.

### Local development

```bash
npm install
npm test
npm run benchmark -- https://example.com/
apify run --purge
```

The test suite includes unit tests plus a real headless-Chrome fixture for custom and axe-core rules.

### Support

Report reproducible bugs and feature requests in the public [UX Evidence Auditor support tracker](https://github.com/invincible/ux-evidence-auditor-support/issues). Include the public URL, viewport, rule ID, and run ID; never post credentials or private page content.

# Actor input Schema

## `startUrls` (type: `array`):

Public HTTP(S) pages. No login or cookies are used.

## `auditDesktop` (type: `boolean`):

Run at 1440 × 900.

## `auditMobile` (type: `boolean`):

Run at 390 × 844 with mobile-like browser settings.

## `saveScreenshots` (type: `boolean`):

Save one visible-viewport JPEG for every audited page and viewport. Screenshots do not affect findings or scoring.

## `waitAfterLoadMs` (type: `integer`):

Extra wait for client-rendered interfaces, in milliseconds.

## `maxPages` (type: `integer`):

Safety limit before desktop/mobile expansion.

## `maxConcurrency` (type: `integer`):

Requested parallel browser pages. The Actor automatically caps this at roughly one page per 1 GB of allocated memory.

## `monitorKey` (type: `string`):

Optional private identifier. Reuse it on later runs to receive new, resolved, and persistent issue IDs.

## `updateBaseline` (type: `boolean`):

Save the current issue IDs as the next baseline when a monitor key is supplied.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://example.com"
    }
  ],
  "auditDesktop": true,
  "auditMobile": true,
  "saveScreenshots": true,
  "waitAfterLoadMs": 1000,
  "maxPages": 10,
  "maxConcurrency": 2,
  "updateBaseline": true
}
```

# Actor output Schema

## `results` (type: `string`):

Structured page reports with evidence and regression status.

## `screenshots` (type: `string`):

Run artifacts stored in the default key-value store.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        {
            "url": "https://example.com"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("invincible_nova/deterministic-ux-auditor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "startUrls": [{ "url": "https://example.com" }] }

# Run the Actor and wait for it to finish
run = client.actor("invincible_nova/deterministic-ux-auditor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://example.com"
    }
  ]
}' |
apify call invincible_nova/deterministic-ux-auditor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,invincible_nova/deterministic-ux-auditor"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/5H01hq7HdIZxKdRE1/builds/a6eWqhL7i0HSuvXsR/openapi.json
