Repository navigation
Adapter url
The url adapter checks live web pages: your deployed pricing page, a landing page, anything a customer or crawler actually sees. It fetches the page, pulls out the visible text, social meta tags and JSON-LD, and checks them for stale and missing fact values. It is read-only by design. There is no apply, and no setting changes that. This page covers the binding, URL resolution, text extraction, audit semantics and error handling.
Source: adapters/url.ts.
- id: web:live-pricing
binding: { adapter: url, url: /pricing }
embeds: [addon:pro.price.usd]
after: [web:pricing-page]| Field | Required | Meaning |
|---|---|---|
adapter |
yes | url |
url |
yes | An absolute http(s):// URL, or a path relative to site in .starchart/config.yaml
|
A binding without url throws <id>: url binding needs a "url", which audit reports under errors.
Absolute URLs are used as-is. Relative URLs resolve against the top-level site setting (the engine merges site into every adapter's settings):
# .starchart/config.yaml
site: https://nebula.example.comLeading slashes are stripped and site gets a trailing slash, so a base path is kept:
site |
url |
Fetched |
|---|---|---|
https://nebula.example.com |
/pricing |
https://nebula.example.com/pricing |
https://example.com/base |
/pricing |
https://example.com/base/pricing |
| (unset) | /pricing |
error: relative url "/pricing" needs "site" in .starchart/config.yaml
|
The Reality X-Ray payload resolves relative binding URLs the same way (leading slashes stripped, the site's base path kept), so both see the same page.
extractPageText(html) builds the text a reader or crawler sees:
| Included | Excluded |
|---|---|
<title> |
<script> (other than JSON-LD), <style>, <noscript>, <template>, <svg>
|
Visible body text, with tags stripped and block tags (p, div, li, tr, h1–h6, section, article, header, footer, br) turned into line breaks |
HTML comments |
<meta> content for og:*, twitter:*, product:* and description
|
the rest of <head>
|
Every <script type="application/ld+json"> block, raw |
Named and numeric HTML entities are decoded (&, , €, $, € and friends), and whitespace runs collapse to single spaces.
So a stale price in og:description or in your JSON-LD Offer is caught even if the visible page is correct. That's often where old prices hide.
The adapter parses HTML with regular expressions, not a DOM. It sees the server-rendered HTML only. Content injected by client-side JavaScript after load is invisible to it.
- Collect leaf facts reached through
embeds,mirrorsandrenders(containers expand to leaves).describesedges are semantic and never checked here. -
GETthe URL withuser-agent: starchart-auditandaccept: text/html,*/*, following redirects. - Run the shared text audit (the same rules as Adapter fs): an old value from the lock still present is
stale. Otherwise a current value that is absent ismissing.
where includes a snippet of the extracted text around the first hit, so you can find it on the page. Here the demo's site points at a local server whose /pricing page still says $4.99 in both the body and og:description, after the fact moved to 5.99:
$ starchart audit --ids web:live-pricing
! stale web:live-pricing http://127.0.0.1:4511/pricing near "pricing Nebula Pro Now only $4.99 /mo Nebula Pro for $4.99 a month" still shows old value 4.99 (2 occurrences); expected 5.99
1 checked · 1 diff(s) · 0 error(s) · 0 skipped
If the artifact carries no leaf facts, the page is still fetched (so a 404 is still a break) but no text is checked.
A page that is gone is drift: the chart says it exists and the world says it doesn't. A page you can't reach right now is a problem with the check, not with the page. The adapter keeps the two apart:
| Failure | Result | Message |
|---|---|---|
| HTTP 404 or 410 |
break diff |
https://…/pricing: HTTP 404 Not Found |
| Any other non-2xx (500, 503, 403, …) | thrown, listed under audit errors | https://…/pricing: HTTP 503 Service Unavailable |
| Network error, DNS failure, TLS error | thrown, listed under audit errors | https://…/pricing: request failed: <reason> |
Errors still make audit exit 1, but they don't show up as a diff and don't pretend the page is broken. The demo's site is a placeholder domain, so auditing it offline shows the error path:
error web:live-pricing [url] https://nebula.example.com/pricing: request failed: fetch failed
Requests run with the rest of the audit, at most 4 artifacts in flight. There is no per-request timeout beyond what the runtime's fetch applies.
capabilities: { read: true, write: false } and no apply. A url artifact that embeds a changed fact is always planned as manual (adapter "url" cannot write). The usual pattern is to pair it with the fs artifact that produces the page and order the live check after it:
- id: web:pricing-page # fs: apply fixes the source
binding: { adapter: fs, path: apps/web/app/pricing/page.tsx }
embeds: [addon:pro.price.usd]
- id: web:live-pricing # url: audit confirms the deploy
binding: { adapter: url, url: /pricing }
embeds: [addon:pro.price.usd]
after: [web:pricing-page]After you deploy, run starchart audit --ids web:live-pricing to confirm the new price is live, then starchart ack web:live-pricing to re-pin it.
★ STARCHART
☠ a Space Pirate Zero joint
STARCHART Every dependency. Code to cosmos.
Guides
Concepts
- Three-Layer Model
- Facts and Entities
- Artifacts and Bindings
- Edge Types
- Node IDs
- Impact Analysis
- Lockfile and Drift
- Rollout Ordering
Authoring
Code layer
Commands & API
Adapters & engine
- Adapters Overview
- Adapter: fs
- Adapter: url
- Adapter: Stripe
- Adapter: App Store Connect
- Writing an Adapter
- Audit and Break Detection
- Apply, Revert and Journals
- Future Universe Preview
- Viewer and Serve
- Reality X-Ray
Rules & analysis
Integrations
Project