POST /v1/products/resolve-from-html takes the HTML itself — typically captured from the product page your user is viewing in your client application. Octogen never fetches the page, never reads its index, and never stores what you send.
Use it when:
- Your users browse product pages your servers never fetch — resolve exactly what they see, at the moment they see it.
- You need the page’s state at the moment the user saw it: the live price, the flash-sale moment, the product exactly as the page declared it.
GET /v1/domains.
Capture from your client, resolve from your backend
The capture itself is two values, read in your client application while the user is on the product page:- Capture the live DOM, not the server response.
document.documentElement.outerHTMLserializes the page after the storefront’s JavaScript has run — which is exactly what you want, because many storefronts inject their product JSON-LD client-side. A capture of the raw server response often extracts worse (see what the resolution block tells you). - Capture after the page settles. Wait for the page to finish loading plus a short delay. On storefronts that navigate client-side, re-capture after each route change, and read
location.hrefat capture time so the URL always matches the DOM you serialize.
source: "client_html", plus a resolution block that tells you how the extraction went — see the API reference for the full field-by-field contract.
Captures from signed-in sessions can include user-specific markup such as an account name or cart contents. Octogen reads only product metadata from the document and stores none of it, but as a rule, capture product pages only — not checkout or account surfaces.
What the URL does
Theurl field is optional — but sending it is strongly recommended: read location.href at the same instant you serialize the DOM, and send it on every request. HTML alone can still resolve, but on many storefronts the URL carries information that exists nowhere in the document. It does three jobs:
- Anchors relative URLs. Pages routinely reference images as
/media/photo.jpg; without a base URL those references are dropped. - Preserves the variant your user chose. When a shopper picks a size or color without leaving the page, most storefronts record that choice only in the URL (
?size=L,?sizeCode=120,?color=45739) — the page’s product markup keeps describing the variant it loaded with. Your submittedurlis echoed back asrequestedUrl, making it the only variant-qualified identity in the response: page-declared canonicals deliberately drop variant parameters, so keying products oncanonicalUrlcollapses every variant into one. And when a page’s markup does declare per-variant URLs, the extractor uses yoururlto pick the matching node. - Provides fallback identity. Every product needs a
productUrl. Without yoururl, the page must declare its own canonical (JSON-LDurl,og:url, orlink rel="canonical") or resolution fails with404 product_not_found.
url, og:url, or link rel="canonical"), the response carries a source_url_missing warning, and only absolute image URLs survive. Treat that as a fallback for HTML whose source you don’t know, not something to design for. The url is caller-asserted and unverified — it is a parsing hint, not proof of where the HTML came from, which is why these results carry source: "client_html" rather than "on_demand".
A capture is the page’s declared state, not its widget state. Storefronts handle variant selection three ways: some navigate to a per-variant page (the URL and HTML both identify the variant), most rewrite only the URL (send it and the identity survives as
requestedUrl), and a few record the selection nowhere — there, no parser can recover it, and even the captured URL may still reflect the variant the page loaded with. When variant precision matters, re-read location.href after the selection and re-capture; if the URL didn’t change, treat the result as the page’s default variant.What the resolution block tells you
Extraction reads standardized metadata in priority order — JSON-LDschema.org/Product, then Open Graph, then HTML meta — with no JavaScript execution and no inference. The resolution block reports what the document actually contained:
methodnames the strongest source found (json_ld,open_graph,html_meta).completenessiscompletewhen title, brand, images, price, and currency were all found; otherwisepartial, withmissingFieldsnaming the gaps.renderedis alwaysfalse— it describes Octogen’s processing, not your capture.
json_ld / complete. If your captures consistently come back open_graph / partial with price missing, you are almost certainly serializing before the storefront’s JavaScript injects its JSON-LD — capture later, after the page settles.
Testing the API before your capture path exists? Open any product page in your own browser and run
copy(document.documentElement.outerHTML) in the DevTools console — that is a faithful stand-in for a client capture. Saving the page with Save Page As or fetching it with curl gives you the pre-render server response instead, which extracts worse on storefronts that hydrate their metadata.Limits and errors
htmlis capped at 5 MiB — comfortably above real product page sizes — and the raw request body at 8 MiB (413beyond that).- HTML resolution has its own rate limit and concurrency gate, separate from lookup’s on-demand budget. A
429carriesRetry-After; a504means the extraction could not start within the service’s deadline. Both are retryable. - A page with no credible product metadata returns
404 product_not_found— the same signal lookup uses, so shared handling code works unchanged.