Skip to main content
Resolve from HTML turns page bytes your application captures into a product object. Where Product Lookup takes a URL and lets Octogen find or fetch the product, 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.
Prefer Product Lookup whenever a URL is on a domain Octogen covers — indexed results are strictly richer, with enriched attributes, CDN-hosted images, and a stable product identity. Check coverage with 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:
Two rules make captures reliable:
  • Capture the live DOM, not the server response. document.documentElement.outerHTML serializes 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.href at capture time so the URL always matches the DOM you serialize.
Your platform API key is an organization-scoped, server-to-server secret. Never embed it in client-side code — a page, an extension, or any code that runs on your users’ devices. Send the capture from your client to your own backend, and have your backend call Octogen:user's browser → your backend → api.octogen.ai
Your backend then forwards the capture unchanged:
A successful response is the familiar lookup envelope with 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

The url 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:
  1. Anchors relative URLs. Pages routinely reference images as /media/photo.jpg; without a base URL those references are dropped.
  2. 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 submitted url is echoed back as requestedUrl, making it the only variant-qualified identity in the response: page-declared canonicals deliberately drop variant parameters, so keying products on canonicalUrl collapses every variant into one. And when a page’s markup does declare per-variant URLs, the extractor uses your url to pick the matching node.
  3. Provides fallback identity. Every product needs a productUrl. Without your url, the page must declare its own canonical (JSON-LD url, og:url, or link rel="canonical") or resolution fails with 404 product_not_found.
When a request arrives without a URL, resolution falls back to the URL the page declares about itself (JSON-LD 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-LD schema.org/Product, then Open Graph, then HTML meta — with no JavaScript execution and no inference. The resolution block reports what the document actually contained:
  • method names the strongest source found (json_ld, open_graph, html_meta).
  • completeness is complete when title, brand, images, price, and currency were all found; otherwise partial, with missingFields naming the gaps.
  • rendered is always false — it describes Octogen’s processing, not your capture.
A live-DOM capture of a well-marked-up storefront typically yields 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

  • html is capped at 5 MiB — comfortably above real product page sizes — and the raw request body at 8 MiB (413 beyond that).
  • HTML resolution has its own rate limit and concurrency gate, separate from lookup’s on-demand budget. A 429 carries Retry-After; a 504 means 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.
See the API reference for the complete error table and Rate limits for the general budgeting model.