Viewrium Docs
Guides

Generate from images

Turn one or more product photos into catalog images and a GLB model with image_urls.

Pass a list of image URLs to products.create. Viewrium reads the product, plans the catalog positions it can produce, prices the work, and parks. Commit the quote and it cuts the images out and reconstructs the 3D model.

Ask for the quote

Python
from viewrium import ModelDimensions, ProductCreateRequest, ProductDraft, ProductOrder, Viewrium

client = Viewrium("sk_live_...")

parked = client.products.create(
    ProductCreateRequest(
        image_urls=[
            "https://cdn.example.com/lamp-front.jpg",
            "https://cdn.example.com/lamp-side.jpg",
            "https://cdn.example.com/lamp-back.jpg",
        ],
        draft=ProductDraft(
            title="Brass floor lamp",
            dimensions=ModelDimensions(height=150),   # cm, for AR real-size display
        ),
        order=ProductOrder(images=True, model=True),
    )
)

print(parked.cost.total_credits, [row.view for row in parked.plan])
print(parked.model.allowed, parked.model.unseen_views)
TypeScript
import { Viewrium } from "@viewrium/sdk";

const client = new Viewrium({ apiKey: "sk_live_..." });

const parked = await client.products.create({
  image_urls: [
    "https://cdn.example.com/lamp-front.jpg",
    "https://cdn.example.com/lamp-side.jpg",
    "https://cdn.example.com/lamp-back.jpg",
  ],
  draft: { title: "Brass floor lamp", dimensions: { height: 150 } }, // cm
  order: { images: true, model: true },
});

Commit it

Python
from viewrium import ProductParked

product = client.products.create(ProductCreateRequest(resume_token=parked.resume_token))
assert not isinstance(product, ProductParked)   # a resume always commits
print(product.id, product.display_status)       # -> "<uuid>", "generating"
TypeScript
if (parked.status !== "parked") throw new Error("unexpected: already committed");
const product = await client.products.create({ resume_token: parked.resume_token });

Tips for good results

  • Multiple angles help. Front, side, and back give the analysis more to work with than a single hero shot - and they are what keeps viewpoints out of model.unseen_views.
  • Clean, uncluttered images of a single product read best. Avoid busy backgrounds and multiple products in one frame.
  • Use direct image URLs (.jpg, .png, .webp) that are publicly reachable - not a gallery page. To work from a product page, use source_url instead.
  • Give dimensions (any one to three axes, cm by default - send unit for anything else) so the model shows at true size in AR.
  • Read the quote before you commit. plan names every position and why; flags.reasons are the analysis's own sentences about the product, meant to be shown as written.

If the model is refused

model.allowed: false with blocked_by: ["unseen_views"] means two or more of the viewpoints the model needs would be invented - nothing in your photographs shows them. The honest fix is another photograph. To take it anyway, quote again with overrides.force_model:

Python
from viewrium import ProductOverrides

parked = client.products.create(
    ProductCreateRequest(
        image_urls=["https://cdn.example.com/lamp-front.jpg"],
        draft=ProductDraft(title="Brass floor lamp"),
        overrides=ProductOverrides(force_model=True),
    )
)
TypeScript
const parked = await client.products.create({
  image_urls: ["https://cdn.example.com/lamp-front.jpg"],
  draft: { title: "Brass floor lamp" },
  overrides: { force_model: true },
});

The override belongs to the request that is analyzed, so it goes on the quote, not on the resume. See the model verdict.

Then

The commit returns the product at display_status: "generating". Wait for it to settle by polling or with webhooks, then read product.model.glb_url and product.images.

On this page