Skip to main content

Snapshot a URL

Point preset AI at a public URL. The scanner renders the page in headless Chromium, walks every visible element, and synthesizes a DesignSystemSnapshot you can refine into your own design system. Useful when you do not have a codebase to scan: agencies onboarding from a client's live product, brand teams capturing a launched site, designers extracting tokens from a reference.

When to use the URL lane

You havePick
A repo with components and tokens in sourceThe codebase lane
A live URL but no source accessThe URL lane (this page)
A brand-guidelines PDFThe PDF lane
A screenshot or moodboard imageThe image lane (see comparison)

The four lanes produce the same shape of output. They differ in what signal they can reach. The URL lane is the only one that captures rendered values: what the browser actually paints, including resolved CSS variables, theme overrides, and runtime-computed styles.

Run the snapshot

From your terminal:

preset snapshot --url https://stripe.com

The first run downloads Chromium via Playwright (~120MB, one-time). After that, a snapshot typically completes in 10-30 seconds depending on the page.

Typical output:

✓ Rendering stripe.com and capturing computed styles...
✓ Snapshot generated in 18,420ms (3,847 nodes visited)

Coherence score: 67 / 100
Colors:        24 primitives, 8 semantic roles
Typography:    6 type styles
Spacing:       8 distinct values
Components:    37 candidate patterns

Flags

FlagDefaultWhat it does
--url <url>requiredThe URL to snapshot. Must start with http:// or https://.
--output <file>stdoutWrite the snapshot JSON or narrative to a file instead of stdout.
--format <type>narrativenarrative for a readable summary, json for the full snapshot.
--threshold <n>1Minimum usage count to keep a token. Filters out one-off observations.
--color-threshold <n>0.005Cluster distance threshold (0-1). Lower = more granular palette.
--ignore-robotsoffSkip the robots.txt pre-flight. Use only for sites you own.
-v, --verboseoffPrint per-stage timing and observation counts.

What the scanner captures

For every visible element on the page, the scanner reads the computed-style values for these properties:

  • Color: color, background-color, the four border-*-color channels, plus SVG fill and stroke (filtered to elements actually inside an <svg> so unrelated nodes don't pollute the palette).
  • Radius: the four border-*-radius corners.
  • Typography: font-family, font-size, font-weight, line-height, letter-spacing.
  • Spacing: padding-top/right/bottom/left, margin-top/right/bottom/left, gap, row-gap, column-gap.
  • Effects: box-shadow.

Each observation carries a surface context, element tag, parent tag, class list, ARIA role, position type, viewport coverage, which the surface-type classifier uses downstream to distinguish core-UI tokens from illustration, brand, marketing, and data-viz palettes. The primitive palette comes from core-UI observations only, so a brand wordmark or a chart's color scheme cannot accidentally become a primitive.

Visibility filter

Hidden elements are skipped. An element is visible if it has display !== 'none', visibility !== 'hidden', opacity > 0, and a non-zero bounding box.

Scroll-and-wait

After initial network-idle, the scanner scrolls the page in 200px increments (up to 6 seconds) to fire lazy-loaded content, then settles for 1.5s before sampling. Pages with heavy hero animations or IntersectionObserver-driven content reveal will still be captured.

CSS-variable name recovery

The scanner also reads every accessible stylesheet's source CSS and recovers symbolic variable names (--brand-primary, --surface-bg) so that a captured rgb(99, 102, 241) traces back to its declared name. Cross-origin stylesheets are fetched server-side. Sites that declare tokens on :root (shadcn/ui, most design-token codebases) get high recovery rates.

What it cannot capture

LimitationWhyWorkaround
Auth-gated pagesThe scanner has no session cookiesSnapshot a public page on the same product, or use the codebase lane
Content inside <iframe>Same-origin only; cross-origin frames refuse accessSnapshot the iframed page directly
Component identityThe scanner sees rendered DOM, not the React/Vue component treeUse the codebase lane for component-level analysis
Behind a paywall, captcha, or geofenceSame as auth-gatedSnapshot a comparable open page
Single-page-app routes that need interactionThe scanner waits for network-idle but does not clickPass the deep URL of the loaded view

Accuracy expectations

The URL lane gives you the rendered view, not the source view. Two things to keep in mind when comparing a URL snapshot to a codebase snapshot of the same product:

  1. Values are computed, not symbolic. A button with background: var(--brand-primary) shows up as rgb(99, 102, 241) until variable-name recovery resolves it. Recovery works for :root-declared variables on accessible stylesheets; theme-scoped overrides (.dark { --brand-primary: ... }) won't always round-trip.
  2. Coherence scores will differ. The codebase lane sees bg-primary 47 times across Button, Link, and Badge and reports high reuse. The URL lane sees 47 instances of rgb(99, 102, 241) and reports it as a frequently-observed color. Both are true; they measure different things. Don't compare scores across lanes: they're not the same metric.
  3. Rendered state is a moment in time. The page you snapshot today may show different content tomorrow. The tokens it exposes (palette, type scale, spacing rhythm) are usually stable; the specific observation counts are not.

For most use cases, bootstrapping a starter DS from a live product, capturing a reference, comparing two brands, the URL lane gives you the right starting point in a few seconds. For deep audit work on your own product, prefer the codebase lane.

robots.txt and the user agent

The scanner identifies itself with the user-agent token PresetBootstrapper. Before rendering, it consults <origin>/robots.txt and respects Disallow rules. If the target path is disallowed, the scan returns a structured opt-out (exit 0 on CLI, 403 robots_opt_out on the API): not a failure.

If your site uses preset AI internally and you want to allowlist the scanner:

User-agent: PresetBootstrapper
Allow: /

If you want to block the scanner:

User-agent: PresetBootstrapper
Disallow: /

If your robots.txt is missing, empty, or unreachable, the scanner treats that as "no restrictions stated" per the Robots Exclusion Protocol: it does not punish a flaky CDN.

The CLI's --ignore-robots flag bypasses the check. It exists for the user's own sites (private staging, internal tools where robots.txt is generic) and is intentionally not exposed in the web UI.

How the four lanes compare

CodebaseURLImagePDF
InputRepo directoryhttps://...PNG, JPG, or screenshotbrand.pdf
What it readsAST of components + token sourcesComputed styles of every visible elementPixels via vision LLM + histogramText-declared hexes + per-page vision
Symbolic namesDirect from sourceRecovered from stylesheets (best effort)Inferred from labels in the imageMined from text adjacent to hex literals
Component identityYesNoNoNo
Coherence scoresSource-level (truth)Render-level (observation)Inference-level (estimate)Mixed (text exact, vision estimate)
Best forYour own product, deep auditReference products, agency onboardingBrand decks, moodboards, single screensBrand guidelines, agency client onboarding
Speed~5s for a mid-size repo10-30s per page5-10s per image~30-60s for 15 pages
CostFreeFree locally; Browserless quota on the dashboardLLM tokens (~$0.001 per scan with Gemini Flash)LLM tokens (~$0.005/page on Flash, hard cap at 15 pages)

The PDF lane is the most recent addition. Pick it when you have a brand-guidelines PDF but no public site or codebase yet.

What's next

Was this page helpful?

Last reviewed by @jschuyler
All systems operationalDocsDevelopersPlatformPricing
PrivacyTerms© 2026 fndd, LLC