CLI Reference
Complete reference for uiMatch CLI commands and options.
Commands Overview
uiMatch provides the following commands:
compare- Compare a single Figma design with implementationsuite- Run multiple comparisons from a JSON suite filetext-diff- Compare two text strings and show similarity scoredoctor- Diagnose installation and configuration issuessettings- View or reset project comparison settingsversion- Display CLI version information
compare Command
Compare a Figma design with your implementation.
Basic Syntax
Note: This assumes @uimatch/cli is already installed (globally or as a dev dependency).
npx @uimatch/cli compare \
figma=<FIGMA_REFERENCE> \
story=<URL> \
selector=<CSS_SELECTOR> \
[options]
Run Once Without Installing
If you want to try uiMatch without adding it to your project:
npx -p @uimatch/cli uimatch compare \
figma=<FIGMA_REFERENCE> \
story=<URL> \
selector=<CSS_SELECTOR> \
[options]
This explicitly tells npx which package to install (@uimatch/cli) and which binary to run (uimatch).
Required Parameters
| Parameter | Description | Example |
|---|---|---|
figma | Figma file and node reference | FILE_KEY:NODE_ID or full URL |
story | URL to compare | http://localhost:3000 |
selector | CSS selector for target element | #my-component |
Common Options
Output Control
outDir=<path> # Output directory (files not saved by default)
Size Handling
size=strict # Sizes must match exactly (default)
size=pad # Pad smaller image with letterboxing
size=crop # Compare common area only
size=scale # Scale implementation to Figma size
Quality Gates
profile=component/strict # Pixel-perfect (pixelDiffRatio: 0.01, deltaE: 3.0)
profile=component/dev # Development (pixelDiffRatio: 0.08, deltaE: 5.0)
profile=page-vs-component # Padded comparison (pixelDiffRatio: 0.12)
profile=lenient # Prototyping (pixelDiffRatio: 0.15, deltaE: 8.0)
# Fine-grained thresholds (overrides profile)
areaGapCritical=<0..1> # Critical area gap threshold (default: 0.15)
areaGapWarning=<0..1> # Warning area gap threshold (default: 0.05)
See Quality Gate Profiles for detailed threshold settings.
Browser Options
viewport=<WxH> # Custom viewport size (e.g., "1920x1080")
Use environment variable UIMATCH_HEADLESS=false to show browser window during execution.
Text Matching (Experimental)
Enable text content comparison alongside pixel-based comparison to detect copy differences, typos, and missing text.
text=true # Enable text matching (default: false)
textMode=self|descendants # Text collection scope (default: self)
# self: Element's own text only
# descendants: Include child elements
textNormalize=none|nfkc|nfkc_ws # Normalization mode (default: nfkc_ws)
# none: No normalization
# nfkc: Unicode NFKC normalization
# nfkc_ws: NFKC + whitespace collapsing
textCase=sensitive|insensitive # Case sensitivity (default: insensitive)
textMatch=exact|contains|ratio # Matching mode (default: ratio)
# exact: Exact match required
# contains: Substring matching
# ratio: Similarity scoring
textMinRatio=0..1 # Minimum similarity threshold (default: 0.98)
# Only applies when textMatch=ratio
textGate=true|false # Use text match for quality gate (default: false)
--textGate # Alternative flag format (same as textGate=true)
# When enabled, CI passes/fails based on text match
# instead of visual differences
# Visual differences are still reported
Note: Text matching results appear in the textMatch section of report.json when outDir is specified.
See Text Matching for detailed information on normalization, similarity scoring, and use cases.
Examples
Basic Comparison
npx @uimatch/cli compare \
figma=abc123:1-2 \
story=http://localhost:3000 \
selector="#button"
With Strict Quality Profile
npx @uimatch/cli compare \
figma=https://figma.com/file/abc123?node-id=1-2 \
story=http://localhost:6006/iframe.html?id=button--primary \
selector=".storybook-button" \
profile=component/strict
Mobile Viewport
npx @uimatch/cli compare \
figma=abc123:1-2 \
story=http://localhost:3000 \
selector="#mobile-nav" \
viewport=375x667
With Text Matching
Compare both visual appearance and text content to detect typos and copy differences:
npx @uimatch/cli compare \
figma=abc123:1-2 \
story=http://localhost:6006/iframe.html?id=accordion--default \
selector="[data-testid='accordion']" \
text=true \
textMode=descendants \
textMinRatio=0.95 \
outDir=./comparison-results
Results include a textMatch section in report.json:
{
"textMatch": {
"enabled": true,
"ratio": 0.42,
"equal": false,
"details": {
"missing": ["accordion", "vertically", "stacked"],
"extra": ["is", "it", "accessible"]
}
}
}
Text-Heavy Pages (Text Gate Mode)
For text-heavy pages like Terms of Service or Privacy Policy, you can use text gate mode to pass CI based on text accuracy while still monitoring visual differences:
npx @uimatch/cli compare \
figma=abc123:1-2 \
story=http://localhost:3000/terms \
selector="#terms-content" \
text=true \
--textGate \
profile=page/text-doc \
outDir=./comparison-results
In this mode:
- CI passes if text content matches (exit code 0)
- Visual differences are reported but don't fail the build
- Useful when content accuracy is more important than pixel-perfect layout
suite Command
Run multiple comparisons from a JSON configuration file.
Basic Syntax
npx @uimatch/cli suite path=<suite-file.json> [options]
Suite File Format
{
"name": "Component Library Tests",
"defaults": {
"profile": "component/dev"
},
"items": [
{
"name": "Button Primary",
"figma": "abc123:1-2",
"story": "http://localhost:3000/components/button",
"selector": "#button-primary"
},
{
"name": "Navigation Header",
"figma": "abc123:3-4",
"story": "http://localhost:3000/",
"selector": "header.nav"
}
]
}
Options
path=<suite.json> # Path to suite file
outDir=<path> # Output directory (default: .uimatch-suite)
concurrency=<number> # Run comparisons in parallel (default: 4)
Example
npx @uimatch/cli suite path=tests/visual-regression.json concurrency=3
text-diff Command
Compare two text strings and show similarity score with classification.
Basic Syntax
npx @uimatch/cli text-diff <expected> <actual> [options]
Positional Arguments
| Argument | Description | Example |
|---|---|---|
expected | The expected text (e.g., from Figma design) | "Sign in" |
actual | The actual text (e.g., from implementation) | "SIGN IN" |
Options
--case-sensitive # Perform case-sensitive comparison (default: case-insensitive)
--threshold=<number> # Similarity threshold (0-1, default: 0.9)
Note: Options must use = syntax (e.g., --threshold=0.8). Space-separated format (--threshold 0.8) is not supported.
Output Format
Returns a JSON object with the following fields:
{
kind: 'exact-match' | 'whitespace-or-case-only' | 'normalized-match' | 'mismatch',
similarity: number, // 0-1 range
expected: string, // Original expected text
actual: string, // Original actual text
normalizedExpected: string, // Normalized expected text
normalizedActual: string, // Normalized actual text
equalRaw: boolean, // True if raw texts are identical
equalNormalized: boolean // True if normalized texts are identical
}
Classification Types
| Kind | Description | Example |
|---|---|---|
exact-match | Texts are identical without any modification | "Login" vs "Login" |
whitespace-or-case-only | Texts differ only in whitespace, case, or NFKC normalization | "Sign in" vs "SIGN IN" |
normalized-match | Similarity is at or above the selected threshold | "Save changes now" vs "Save changes later" at 0.6 |
mismatch | Similarity is below the selected threshold | The same pair at 0.7 |
Text Normalization
The comparison applies the following normalization steps:
- NFKC Unicode normalization - Converts full-width characters to half-width
- Whitespace collapsing - Collapses consecutive whitespace into single space
- Trim - Removes leading/trailing whitespace
- Case normalization - Converts to lowercase (unless
--case-sensitiveis used)
Examples
Basic Comparison
npx @uimatch/cli text-diff "Sign in" "SIGN IN"
Output:
{
"kind": "whitespace-or-case-only",
"similarity": 1.0,
"equalRaw": false,
"equalNormalized": true
}
Case-Sensitive Comparison
npx @uimatch/cli text-diff "Submit" "submit" --case-sensitive
Output:
{
"kind": "normalized-match",
"equalRaw": false,
"equalNormalized": false
}
The similarity remains above the default threshold, so the result is a
normalized-match even though case normalization is disabled.
With Custom Threshold
npx @uimatch/cli text-diff "Save changes now" "Save changes later" --threshold=0.6
Output:
{
"kind": "normalized-match",
"equalRaw": false,
"equalNormalized": false
}
This pair is above 0.6 and below 0.7; selecting 0.7 therefore classifies
the same input as a mismatch.
Full-Width Character Handling
npx @uimatch/cli text-diff "Button123" "Button123"
Output:
{
"kind": "whitespace-or-case-only",
"similarity": 1.0,
"equalRaw": false,
"equalNormalized": true
}
Use Cases
- Text label validation - Compare Figma text labels with implementation
- Copy review - Compare intentional wording changes against an explicit threshold
- Typography debugging - Identify subtle text differences (case, whitespace, unicode)
- Component testing - Validate text content in UI components
@uimatch/core is an internal package and is not a supported public API. Use this
command when text comparison is required in scripts or CI.
settings Command
View the effective project configuration or remove .uimatchrc.json and return
to defaults.
npx @uimatch/cli settings get
npx @uimatch/cli settings reset
Running settings without an action is equivalent to settings get. The
command does not provide a set action; edit .uimatchrc.json and inspect the
effective result with settings get.
version Command
Display the current version of the CLI.
Basic Syntax
npx @uimatch/cli version
Alternatives
You can also use standard flags:
npx @uimatch/cli --version
# or
npx @uimatch/cli -v
Environment Variables
Set these in .env or your environment:
FIGMA_ACCESS_TOKEN=your_token_here # Required for Figma API access
UIMATCH_LOG_LEVEL=debug|info|warn|error|silent # Logging verbosity (default: info)
UIMATCH_HEADLESS=true|false # Playwright headless mode (default: true)
# Set to 'false' to show browser window
# Applies to compare/suite/doctor commands
UIMATCH_CHROMIUM_SANDBOX=true|false # Chromium sandbox (default: true)
# Use false only when the runtime cannot support it
UIMATCH_SELECTOR_PLUGIN_TIMEOUT_MS=30000 # Plugin deadline (1..2147483647 ms)
Exit Codes
0- All comparisons passed1- One or more comparisons failed2- Invalid arguments or configuration error
Exit code 2 means the invocation itself has to change — an unknown command, an
invalid argument, a malformed suite file, a missing environment variable.
Anything the comparison detected exits with 1.
Failures that carry a stable code print it on stderr as
❌ Error [<code>]: <message>:
| Code | Exit | Meaning |
|---|---|---|
UIMATCH_CONFIG_INVALID_FIGMA_REF | 2 | figma is not current, fileKey:nodeId, or a URL |
UIMATCH_CONFIG_MISSING_FIGMA_TOKEN | 2 | FIGMA_ACCESS_TOKEN is required but not set |
UIMATCH_SELECTOR_NOT_FOUND | 1 | The selector was not found or never became visible |
UIMATCH_IMAGE_SIZE_MISMATCH | 1 | Image dimensions differ while size=strict |
Programmatic callers can match the same codes:
import { uiMatchCompare, UiMatchError } from '@uimatch/cli';
try {
await uiMatchCompare({ figma, story, selector });
} catch (error) {
if (error instanceof UiMatchError) {
console.error(error.code, error.category);
}
}
Advanced Usage
Content Basis
Control which area to use for calculating pixel difference ratio:
contentBasis=union # Union of both content areas (default)
contentBasis=intersection # Intersection of both areas (recommended for pad mode)
contentBasis=figma # Use Figma's content area only
contentBasis=impl # Use implementation's content area only
Best Practice: Use intersection with size=pad to exclude letterboxing from metrics.
Custom Anchor Plugins
Use custom selector resolution plugins:
selectorsPlugin=@my-company/custom-anchor-plugin
Selector anchor files and the source paths they reference must stay within the project root. uiMatch uses an explicit projectRoot=<path> when provided, otherwise the nearest Git root, and finally the current working directory. Paths are resolved through symlinks before this boundary is checked.
selectors=.uimatch/anchors.json projectRoot=/path/to/project
See Plugins for details on creating custom plugins.
Quality Gate Profiles
uiMatch uses quality gate profiles to manage thresholds instead of individual CLI flags.
| Profile | Use Case | pixelDiffRatio | deltaE | Description |
|---|---|---|---|---|
component/strict | Design system components | 0.01 (1%) | 3.0 | Pixel-perfect comparison |
component/dev | Development workflow | 0.08 (8%) | 5.0 | Relaxed for iteration |
page-vs-component | Padded comparisons | 0.12 (12%) | 5.0 | Accounts for letterboxing |
page/text-doc | Text-heavy pages | 0.20 (20%) | 6.0 | Terms, privacy, documentation |
lenient | Prototyping | 0.15 (15%) | 8.0 | Very relaxed thresholds |
custom | Custom settings | - | - | Uses .uimatchrc.json |
Using Profiles
# Pixel-perfect comparison
npx @uimatch/cli compare figma=... story=... selector=... profile=component/strict
# Development workflow
npx @uimatch/cli compare figma=... story=... selector=... profile=component/dev
# Text-heavy pages (Terms, Privacy Policy, etc.)
npx @uimatch/cli compare figma=... story=... selector=... profile=page/text-doc
Custom Configuration
For fine-grained control, create .uimatchrc.json:
{
"comparison": {
"colorDeltaEThreshold": 3.0,
"acceptancePixelDiffRatio": 0.01,
"acceptanceColorDeltaE": 3.0
}
}
colorDeltaEThreshold controls StyleDiff significance and SFS normalization.
acceptanceColorDeltaE controls the aggregate color quality gate. Profiles
provide a single deltaE value that overrides both stages for that run.
Tips
- Start with lenient profile (
profile=lenient) and tighten as needed - Use
UIMATCH_HEADLESS=falseduring development to see browser window - Name your comparisons for easier debugging in CI logs
- Group related comparisons in suite files for organization
See Also
- Concepts - Understanding anchors and quality gates
- Troubleshooting - Common issues
- Plugins - Extending uiMatch