Docs

Read this before you build anything.

A reading order for a human who has never seen this API, and a map for the agent you point at it.

UXXRAY x-rays real marketing and e-commerce funnels into measured facts: the conversion tactics they run, the exact on-page language, a deterministic /100 score, and a screenshot of every step. Every worked example below is a real, live URL, not a {slug} placeholder: each one is checked at build time, and the build fails if any of them stop resolving.

Generated from endpoint-registry.js (49 public endpoints) and verified live against 1,777 measured funnels at build time.

1What UXXRAY measures

Every fact this API returns comes from a real headless-browser crawl and deterministic DOM/CSS extraction, never an LLM opinion. A detected conversion tactic always carries the exact on-page string that triggered it; if a rule can't decide, the signal is reported as unknown, never guessed. That rule is why the corpus is citable: 1,777 funnels measured, 2,703 pages analyzed. Full method and the explicit limits: /methodology.

2The ontology: funnel → page → section → element

Four sizes of thing, and the API's shape follows them directly:

Every specimen, in the API or on those pages, carries a specimen_ref shaped slug:archetype: the stable identity that survives a re-crawl.

3Get one funnel

Score a URL you don't have yet:

curl -X POST https://api.uxxray.com/api/v1/scan -d '{"url":"https://example.com"}'
# → { "jobId": "...", "status": "queued" }

curl https://api.uxxray.com/api/v1/scan/{jobId}
# poll until { "status": "done", "slug": "..." }

Or read back a funnel already measured: every field below comes from one real, currently-scored funnel, ainexfinder (ainexfinder.com, 100/100):

curl https://api.uxxray.com/api/v1/teardown/ainexfinder/bundle
Open the real response → /api/v1/teardown/ainexfinder/bundle

One self-contained JSON: the score and why, every detected tactic with its evidence string, design tokens, per-step screenshots, and a generated agent brief. Related, single-purpose reads on the same funnel:

4Get specimens: the Specimen Library

This is the AI-native path: ask in design-task language, get measured references with receipts back, never a blank page. Start at the whole shelf:

curl https://api.uxxray.com/api/v1/library/index
Open the real response → /api/v1/library/index

It answers with every facet and real counts. Right now, hero is the largest section archetype at 2,237 specimens. Pick a facet and fetch it:

curl "https://api.uxxray.com/api/v1/library/specimens?kind=section&archetype=hero&scope=narrow"
Open the real response → /api/v1/library/specimens?kind=section&archetype=hero&scope=narrow

Or start from a task instead of a facet. resolve turns design-task language into the corpus's own vocabulary, and brief goes straight to a shortlist:

curl "https://api.uxxray.com/api/v1/library/resolve?task=build_review_section"
Open the real response → /api/v1/library/resolve?task=build_review_section

Building for real: pass exclude_seen_project (with the x-uxxray-visitor header) on every round after the first, so the corpus keeps feeding new material instead of re-serving round one.

5The Design Factory: get it reviewed, download the result

UXXRAY doesn't design. It hands you references with receipts and hosts the review; the original work is yours.

curl -X POST https://api.uxxray.com/api/v1/factory/sessions -d '{"task":"build_review_section"}'
# → { "session_id": "...", "session_token": "..." }  (token shown ONCE)

curl -X POST https://api.uxxray.com/api/v1/factory/sessions/{session_id}/concepts \
  -H "x-uxxray-session-token: {session_token}" \
  -d '{"concept_id":"v1-tight-proof","artifact":{"html":"...","css":"..."}}'

# hand a human the review link:
# https://uxxray.com/factory/sessions/?id={session_id}

curl https://api.uxxray.com/api/v1/factory/sessions/{session_id}/feedback
# → starred/rated verdicts, refine and repeat

Session creation and concept registration are illustrative here (they create real state, so this page doesn't fire them at build time). Everything else on this page is a live, verified GET. Listing public sessions is: Try it → /api/v1/factory/sessions?limit=1

6Full endpoint reference

Every public endpoint, grouped by what you're trying to do rather than by path. 49 total, generated directly from endpoint-registry.js so it cannot go stale without the registry test noticing.

Find the corpus 4

What exists, and how big it is right now.

GET /api/v1

This self-describing API root: endpoint catalog, corpus counts, links

Try it →
GET /api/v1/openapi.json

OpenAPI 3.1 document for this API

Try it →
GET /api/v1/league

Ranked list of teardowns (?funnel_type=, ?limit=, ?offset=). Paginated: a full page does NOT mean the whole corpus: check the x-uxxray-has-more response header and follow Link rel="next" until it reads false

Try it →
GET /api/v1/corpus/stats

Corpus-wide aggregates (pct_lack, avg_tactics, evidence)

Try it →

Get one funnel 12

Score a URL on demand, or read back everything measured for one already-scored funnel: score, tactics, tokens, screenshots.

POST /api/v1/scan-request

Request a new site be scanned (queued for manual/batch capture): body {url, email?}

POST /api/v1/scan

Live on-demand x-ray: real Browser Rendering capture, async. Body {url, mode?, steps?, maxSteps?, force?}. mode="auto" (default) auto-discovers the funnel (entry → pricing/product → signup/checkout); "single" scans just the entry page; "defined" walks the exact same-domain URLs in steps[]. maxSteps caps auto/defined (default 4, max 6). Returns 202 {jobId,status} or 200 {status:done,slug} if cached within 24h; {"force":true} bypasses the cache.

GET /api/v1/scan/{jobId}

Poll a live scan job: {status, slug?, score?, band?, blocked?, error?}

GET /api/v1/vs/{a}/{b}

Deterministic side-by-side compare page (HTML) for two teardowns

Try it →
GET /api/v1/teardown/{slug}

Full teardown: all device variants, score, funnel steps

Try it →
GET /api/v1/teardown/{slug}/bundle

One self-contained JSON with everything for one site (?include=, ?exclude=): the recommended single fetch for agents

Try it →
GET /api/v1/teardown/{slug}/tokens

Design tokens (?format=json|w3c|tailwind|css). The json form carries the five-slot `tokens` export UNCHANGED plus a `design` object holding what those slots were derived from: the full palette ordered by usage with usage_pct, weighted ink candidates, the real type scale and weights, EVERY radius, and the measured roles with any collisions NAMED rather than resolved by inventing a colour. Page-scoped. No spacing field: nothing measures spacing

Try it →
GET /api/v1/teardown/{slug}/brief

Machine-generated build-brief markdown

Try it →
GET /api/v1/teardown/{slug}/favicon

Favicon image, streamed from R2

Try it →
GET /api/v1/teardown/{slug}/report

Pre-rendered shareable report HTML (self-heals from D1/R2 if not yet rendered)

Try it →
GET /api/v1/teardown/{slug}/og.png

Branded 1200x630 social card image, composed on demand from the latest hero screenshot

Try it →
GET /api/v1/teardown/{slug}/screenshot/{path}

One step screenshot/crop, streamed from R2 (e.g. path="01-home/hero.png")

Get specimens (the Specimen Library) 10

Design-task language in, real cropped references with receipts out: the AI-native path this API is built around.

GET /api/v1/library/index

THE WHOLE SHELF: every facet, every legal value, real counts, no specimens. Call this FIRST. The inventory is lumpy (hero is in the hundreds, stat_proof is single digits) and these counts are how you find that out before asking for 20 and getting 7

Try it →
GET /api/v1/library/specimens

FACETED SPECIMEN RETRIEVAL: you choose the breadth. scope=narrow (5, full receipts incl. verbatim evidence) | broad (20, the band's cropped image + tactic ids: the DEFAULT) | full (the whole roster for the facet: identity + score only). Select on ONE axis: kind (+archetype/template) OR playbook; funnel_type filters either. Every response publishes how many exist, so "showing 7 of 7 available" can never be misread as a page of many. exclude_seen_project stops a later round re-serving what you already built from. A ranked response is ONE specimen per domain by default (score is funnel-scoped, so a 4-page walk would otherwise take 4 slots) and does not rank bands with no possible crop; both reductions are disclosed and per_domain= lifts the cap

Try it →
GET /api/v1/library/resolve

DESIGN TASK → CORPUS VOCABULARY. "build_review_section" → the section archetypes, measured patterns and ready-made queries to use. Exact-match lookup: an unsupported task is reported as unsupported, never guessed

Try it →
GET /api/v1/library/sections

SECTION SPECIMENS with receipts: real bands from real funnels, each with crop_url (a real ~1440px webp of the band, or null with a stated reason) plus crop coords onto its full-page screenshot, the funnel's measured /100, and the verbatim on-page evidence for every tactic it runs. Ranked by score. The crops are cut at BUILD time over the listed corpus; scanning a site does not produce them (see steps[].crops_note on a bundle)

Try it →
GET /api/v1/library/elements

ELEMENT SPECIMENS: the atomic UI pieces real funnels are built from (price anchors, ratings, guarantees, no-card notes, countdowns), each a REAL CROPPED IMAGE cut at BUILD time from the funnel's own full-page screenshot, plus the verbatim on-page text of that element. Scanning a site does not produce this material: a walk cuts at most two regions per step and they are a different tier (see steps[].crops_note on a bundle). Unlike section receipts, the text is element-scoped: the detector recorded the rect and the string from the same DOM node on the same crawl. Ranked by the funnel's measured /100

Try it →
GET /api/v1/library/pages

PAGE SPECIMENS: one real crawled page per specimen, grouped by the MEASURED section sequence it shares with others (the shape). Carries the above-the-fold crop, the whole-page screenshot, the section skeleton the shape was clustered on, and the funnel's measured /100. Ranked by score

Try it →
GET /api/v1/library/engagement

Batch engagement counts for the specimens on one page. Fetched at RUNTIME and never baked into the static build, because a build-time number is a claim about when the page was generated dressed up as a current one. A ref with no row is OMITTED rather than returned as 0: never counted and measured-zero are different facts. Carries the definition of the number

Try it →
POST /api/v1/library/engagement

Record ONE deduped engagement event for a specimen. Deduplicated per visitor per day on a one-way, day-scoped IP hash: no cookie, no device storage, no identity. Agent visits COUNT (this is an agent-oriented product); 2000 pings in five seconds count once. Build, canary and internal traffic are excluded. The response carries the exact definition of the number, and returns recorded:false when the visitor was already counted today: that is a normal outcome, not an error

GET /api/v1/library/search

SPECIMEN SEARCH: free text resolved into explicit MEASURED filters (archetype, tactic, funnel type, min score), then real specimens with receipts. Deterministic, not semantic: any term it does not understand is REPORTED as unmatched rather than silently ignored

Try it →
GET /api/v1/library/brief

THE INSPIRATION BRIEF: a SHORTLIST for one design task: resolved taxonomy, 2-3 selected specimens with receipts, what to read them for, and the originality instruction. Deterministic, so asking twice returns the same specimens; the response names its own pool size and links the full roster. For the whole library start at /api/v1/library/index instead

Try it →

Design case law (patterns, templates, playbooks) 9

The corpus read as structure and strategy instead of single funnels: which tactics recur, which page shapes recur, which named playbooks a funnel matches.

GET /api/v1/patterns

The Conversion Pattern Library: every detected tactic, prevalence, quoted evidence, examples (?funnel_type=)

Try it →
GET /api/v1/patterns/{pattern_id}

One conversion pattern, machine-readable: up to 60 verbatim on-page examples

Try it →
GET /api/v1/templates

Page Template Library: recurring section-skeletons real pages are built from, clustered by exact structure

Try it →
GET /api/v1/sections

Section-archetype prevalence across fully-crawled pages: how common each band is, where it typically sits, example sites; ?archetype=X returns every real instance with screenshot crop coords (the SECTION layer)

Try it →
GET /api/v1/playbooks

Funnel-playbook registry + which crawled funnels match each (measured surface matches, quoted evidence; bundles carry per-funnel matches as bundle.playbooks)

Try it →
GET /api/v1/playbooks/{id}

One funnel playbook, machine-readable: model summary + cheat sheet + how to unlock the prompt templates

Try it →
GET /api/v1/curriculum

THE AGENT STUDY PATH (markdown): how to learn conversion design from this corpus: top scorers → bundles → screenshots → playbook → page → section → copy

Try it →
POST /api/v1/playbooks/unlock

Unlock a playbook's full prompt templates: body {email, playbook, source?}; returns {playbook:{prompts_md, cheat_md}}

POST /api/v1/playbooks/feedback

Report whether a playbook was useful: body {playbook, useful, comment?, email?, via?}

The Design Factory (build, review, export) 11

Register original concepts, hand a human one review link, read the verdict, download a stack-neutral artifact.

POST /api/v1/visitors

Issue a VISITOR CAPABILITY TOKEN: the continuity layer. It powers YOUR work (factory projects, likes) and is deliberately NOT an analytics identity: view counts deduplicate on a day-scoped IP hash and never read it. Returned ONCE and stored only as a SHA-256 hash, so it cannot be re-read. Send it back as the x-uxxray-visitor header: a header rather than a cookie so agents, which hold config but not cookies, use the same primitive as browsers

GET /api/v1/visitors/me

Your factory projects, resolved from the x-uxxray-visitor header. Returns a completeness note stating what is NOT listed: work from another device, from before the token existed, or created after clearing it is unreachable here and recoverable only by its own review link. Claiming full history would be a fabrication

PATCH /api/v1/factory/sessions/{session_id}

Change a session's visibility and/or record sources discovered mid-work (#177): body needs privacy, source_specimens, or both. REQUIRES the write credential (x-uxxray-session-token header): editing is an owner action, and the review link alone must not authorise it. private means UNLISTED, not access-controlled: the id is still a capability. source_specimens APPENDS to what is already stored, it never replaces: a worker that discovers a specimen it used in round 2 does not need to resend round 1's list

GET /api/v1/factory/sessions

List Design Factory sessions. Anonymous callers see ONLY sessions explicitly created with privacy:"public": private sessions are reachable solely by someone who already holds the id

Try it →
POST /api/v1/factory/sessions

Create a Design Factory session: PRIVATE by default; returns a write credential ONCE that is required to register concepts (header x-uxxray-session-token). The session_id alone is the review link: safe to hand a human, allows reading and feedback, not writing. Create: body {task, project?, target?, source_specimens?, agent?, privacy?}; external AI agents register concepts into it

GET /api/v1/factory/sessions/{session_id}

Get one Design Factory session, its registered concepts, latest feedback, and agent contract

POST /api/v1/factory/sessions/{session_id}/concepts

Register an original concept into a session. REQUIRES the write credential from session creation, sent as the x-uxxray-session-token header; the review link alone will not authorise it. artifact must carry non-empty html or css

GET /api/v1/factory/sessions/{session_id}/feedback

Get latest session-scoped feedback as both raw verdicts and an agent-ready refinement summary

POST /api/v1/factory/sessions/{session_id}/feedback

Record session-scoped concept feedback: body {concept_id, starred?, rating?, comment?, tags?}

PATCH /api/v1/factory/sessions/{session_id}/concepts/{concept_id}

Commit a round's winner (#159 PART B): body {status:"selected"}. REQUIRES the write credential (x-uxxray-session-token header), same as concept registration: the review link alone must not decide a session. Marks this concept selected, archives every OTHER direction's root, stamps the session's decided_concept_id/decided_at, and returns round_two_seed: the winner's brief + comment, every REJECTED concept's comment labelled as such, the source specimens already used, and both round-two branches (evolve the winner vs fresh alternatives). The human chooses the branch, never the agent

GET /api/v1/factory/sessions/{session_id}/concepts/{concept_id}/artifact

Get the portable artifact bundle for one generated concept: HTML/CSS/tokens/adapters/source provenance when registered

Rate and correct 3

Close the loop: rate any result, or dispute a tactic the detector missed.

POST /api/v1/rate

★ Rate any result 1-5: body {rating, context?, via: "user"(relayed human)|"agent", comment?}. Terminal responses carry the ask as _rate

GET /api/v1/rate

Rating summary: overall count/avg + breakdown by context

Try it →
POST /api/v1/report/dispute

Report a tactic we missed on a report: body {slug, tactic_id, url?, note?, email?, via?}; logged for detector review, not auto-applied

7For your agent

Point your agent at the machine artifacts, not this page

This page is written for a human's first read. An agent already working with UXXRAY should read the machine-first versions instead: /llms.txt (routing + ontology + endpoint index, compact) and /llms-full.txt (the same, plus the complete corpus listing).

Also: OpenAPI 3.1 · hosted MCP server at https://api.uxxray.com/mcp (tools generated from this same registry, so they can't drift from it) · the agent study path, one fetch.

Free, no signup

Try it on your own funnel.

Every endpoint above is open · no key, no login, CORS open