viewa/docs
Widget

Embedding the widget

Drop the visualizer into any storefront as a web component.

The widget is a framework-agnostic web component: one script tag and one element, no build-tool integration required. It handles the photo upload, the corner editor for marking areas, and displaying the finished render — your product customizer drives it through the JS API.

The shape of it

<script src="https://your-instance.example/viewa-widget.js" async></script>

<viewa-visualizer publishable-key="pk_…"></viewa-visualizer>

Load the script from your API base URL — the same host you call the API on. That is a complete embed. The widget authenticates with your publishable key — safe in the browser because keys are domain-locked — and walks the customer through the whole journey on its own.

If you are serving viewa-widget.js yourself — from your own CDN or asset pipeline rather than from us — add base-url. It defaults to the origin the script came from, which in the embed above is the API host; served from your own domain, that default points every call at your storefront. Your origin also has to be on the key's allowlist, or every call answers 403 origin_not_allowed.

Add a product and it visualizes that product with no JavaScript at all:

<viewa-visualizer publishable-key="pk_…" product="YOUR-SKU-123"></viewa-visualizer>

Attributes

AttributeWhat it does
publishable-keyRequired. A pk_ key whose allowlist includes this origin
base-urlThe API host. Defaults to the origin the script itself came from
capabilitiesWhich pipeline steps this instance may take. Defaults to all three
productThe product to render: a prod_… id or a registered SKU alias
materialsslot:material pairs, comma or space separated. Omitted slots use the product's default
product-nameOverrides the name in the upload prompt. Optional — the widget looks it up
unitsm (default), cm or in. Display only; the API always measures in meters
auto-renderon (default) or off. Off means you call visualize()
max-areasHow many areas the customer may mark, 1–20. 1 is single-area mode
uiWhich controls the widget draws for itself. See Theming
logoThe mark on the upload panel: a URL for your own, or none. Defaults to the Viewa lockup
imageResume from a photo you already have (img_…)
area-setResume from areas already measured (aset_…)

Only publishable-key and base-url reset the widget when they change. Everything else is presentation, so a customizer can rewrite product on every product change without throwing away the photo the customer just uploaded.

materials is the markup half of setSelection, for a page that has one product and one finish rather than a picker:

<viewa-visualizer
  publishable-key="pk_…"
  product="YOUR-SKU-123"
  materials="slot_fabric:CHARCOAL-LINEN"
></viewa-visualizer>

Both halves take refs, so a registered SKU alias works in either position. The slot is required: a material on its own does not say which part of the product it dresses.

Splitting the journey across pages

capabilities is a subset of upload, areas and render. It is how a storefront spreads the flow over more than one page — and what a plugin's settings screen maps checkboxes onto.

<!-- page one: collect the photo and stop -->
<viewa-visualizer publishable-key="pk_…" capabilities="upload"></viewa-visualizer>

<!-- page two: mark up the photo page one captured -->
<viewa-visualizer
  publishable-key="pk_…"
  capabilities="areas render"
  image="img_…"
></viewa-visualizer>

The set is contiguous, and it also says where to begin. A run that does not start at upload cannot obtain its own photo, so it has to be handed one:

Hand itAnd the widget resumes at
imageThe corner editor, on that photo
area-setThe measured areas, ready to render

An area set carries the id of the image it was measured on, so resuming a fully marked-up scene needs one attribute, not two. Setting both only makes the widget resume twice.

Where those ids come from is your session, cart line or order record. Read them off getStatus() when the customer finishes and store them against the line.

A widget whose capabilities start after upload with no image or area-set has nothing to show, and says so. That is a template mistake rather than a customer-facing one, so it also logs to the console instead of leaving you guessing.

What the widget owns vs what you own

The widget handlesYour page handles
Photo upload and validationProduct and material choice UI
Corner editing and measurementPassing the selection via setSelection(…)
Render request, polling, displayWhere the widget sits in your layout
Visitor token storagePersisting ids against the cart line

The widget never reads your catalog. Product choice is your customizer's job, which is why there is no picker inside it — see Catalog for building one.

Where to put it

The widget fills the width of its container and holds one height across every step of the journey, so it drops into a product gallery slot without the page shifting as the customer works through it. Set --viewa-aspect to match your slot.

Next

  • JS API — pushing selections in, reading state back out
  • Theming — colors, shape, and which controls it draws

On this page