Prophecy
Install Orbital Vision's embeddable room-visualisation SDK for OV25 configurators or any product catalogue.
Prophecy adds a complete View it in your room experience to a product page. It can discover the current OV25 configuration automatically, or accept one to four images of any other product.
Version
These examples load @orbital.vision/prophecy@1, the major version. Fixes and new features reach your site without you editing anything, and a breaking change would be a deliberate move to @2. If you would rather freeze one exact build, pin the full version instead and update it yourself.
Installation
Script tag with OV25
One line, with nothing in it:
Prophecy detects the configurator.orbital.vision iframe, reads the organisation, public key and product from its URL, and follows the shopper's selections. You do not pass an organisation ID, key, product ID, product images, configurator selector, or button.
The script does not need to come after the iframe. Prophecy waits for the configurator, so a page that mounts it after hydration, or on a later route of a single-page site, still works. That is true even when the tag has attributes such as data-prophecy-session-endpoint. Include the line once; a second copy will not add a second launcher.
The running instance is available as window.prophecy. Use data-prophecy-configurator only if the page contains multiple configurators.
The dialog carries a small footer reading "Powered by OV25 from Orbital Vision". It is part of the experience and is not configurable.
Placing the launcher
By default Prophecy adds its own button, fixed to the corner of the page. To place it yourself, mark a button in your own markup:
Prophecy attaches to the first marked element and follows one that a single-page site mounts and unmounts per route. Once a page has marked a launcher, Prophecy stops offering its own. The button stays hidden until Prophecy has confirmed the shop can generate, so a shopper never sees a control that cannot work.
The widget on the configurator
Prophecy also puts a small control in the top right corner of the configurator itself, so a shopper can add what they are looking at to their room without opening the dialog.
Before they have made anything it is a single pill reading "View this product in your room". After that it becomes a stack of the previews they have made with a plus over the corner. Pressing the plus starts a preview of the current product in the room they last used, without opening anything: the plus becomes a filling ring, then a tick, and the new picture joins the stack. Pressing the stack opens the dialog on their previews.
The plus appears only when the product on screen has no preview yet, and only once the configurator has finished changing to it. Changing the fabric while one is being made offers to make that one too, up to the number of previews your account allows at once.
The widget comes with the script tag. A page that sets data-prophecy-button gets the launcher on that element and no widget:
From npm, add the widget yourself with one call:
npm
Use the package when Prophecy is part of your application bundle or you need programmatic control.
Prophecy.create() does not wait for the configurator. The iframe must already be on the page, or it throws. On a page that mounts the configurator later, create Prophecy after it:
The npm package ships an ES module, an IIFE browser bundle, source maps, and TypeScript declarations. jsDelivr is the recommended browser CDN; npm itself is not a browser asset server.
Non-OV25 products
Pass a stable catalogue reference and one to four JPEG, PNG, or WebP images of the exact same product. Images may be CORS-readable HTTP(S) URLs or browser Blob values, with a maximum of 12 MB per image.
For a declarative integration, provide data-prophecy-product-reference, data-prophecy-product-images, data-prophecy-product-url, and data-prophecy-session-endpoint on the script tag.
Who can generate
The organisation chooses one access mode in the dashboard. It decides whether the section below applies to you at all.
| Mode | Who can generate | What your site needs |
|---|---|---|
| Anyone | Any shopper on an authorised domain | The script tag |
| A few free, then sign in | Anyone, up to a daily allowance per browser, then signed-in customers | The script tag and the session endpoint below |
| Signed-in customers only | Only customers your server has identified | The session endpoint below |
In free-trial mode, a shopper who has used their allowance does not get an error. Prophecy tells your page, and you send them to your login:
The free allowance is a prompt, not a limit
It is counted against a marker Prophecy keeps in the browser, so a shopper who clears their browser data starts again. Its job is to move people towards signing in. Spending is capped by the organisation's daily limits and token balance, which are enforced on our servers.
Server-side session exchange
The browser calls a same-origin endpoint on your site. That endpoint authenticates the shopper with your normal session, validates the product being viewed, then exchanges your Prophecy server key for a short-lived, product-bound browser session.
Keep the server key on the server
Never expose ORBITAL_PROPHECY_SERVER_KEY in HTML, JavaScript, a public environment variable, or Prophecy options. Orbital derives organizationId from the key and returns it in the short-lived session.
Create the key on your API Keys page and pick the Prophecy Server Key type. It only buys previews. The general Private API Key also reads your product list and swatches, which is more than a preview integration should be able to do if the key ever leaks.
Your route must:
- accept only authenticated, same-origin JSON
POSTrequests; - derive
customerIdfrom the signed-in account, never from request input; - validate
productIdorproductReferenceagainst the page being viewed; - keep the Prophecy server key in a server-only environment variable;
- return Orbital's status and session JSON without caching it.
OV25 products use productSource: 'ov25-configurator'. Supplied-image products use productSource: 'external-images' and may have a null productId.
Availability and token balance
Before showing anything, Prophecy asks whether the site may offer previews at all. Orbital checks the public key against the organisation, that the requesting origin is on the authorised domains list, and that Prophecy is switched on.
That check opens no session and uses none of the shopper's allowance. It does not depend on the product, so one cached answer covers your whole catalogue and it is asked once per page. A session begins only when a shopper opens the dialog.
If the answer is no, Prophecy keeps the launcher hidden, emits availability-change and error, and logs the reason to the console instead of showing a broken interface. Localhost uses development behaviour by default: the launcher stays visible and a failed session shows its message inside the dialog, so errors remain visible while integrating.
On localhost, Prophecy still calls the live API. Until that origin is on your authorised domains list, the dialog shows the live API's refusal. To use a staging host instead:
From npm, pass endpoint: 'https://staging.example' to Prophecy.create().
How long we keep things
| What | Kept for |
|---|---|
| The room photo a shopper uploads | Deleted the moment the preview is generated |
| A room photo uploaded but never used | Under a day |
| The generated preview | 30 days from generation |
Copy a preview you need to keep
The 30 days is a download window, not storage. It does not extend because you saved your own copy, so a URL of ours linked from your records will stop working after 30 days. Copy the file into your own storage when you save the result.
The room photo is the sensitive half, and it does not survive generation: it is deleted as soon as the generator reads it, before the preview exists.
Account-owned history
For signed-in customers, keep room photos and generated results in your database and private object storage rather than local storage. Every history route should derive ownership from your signed session instead of accepting an account ID from the browser.
| Data | Recommended fields | Storage rule |
|---|---|---|
| Room photos | ID, private object key, dimensions, created time | Return short-lived same-origin or CORS URLs |
| Results | Orbital job ID, product identity, selection, result key | Verify the job server-side before saving |
| Ownership | Your internal customer ID | Always derive it from the signed session |
Adapters should honour the supplied AbortSignal. Returned room-photo URLs must be same-origin or CORS-enabled. accountKey is only a stable, non-sensitive browser-side change marker; never use an email address, customer ID, access token, or session token.
Verify results before persistence
Do not trust result metadata posted by the browser. Retrieve the job from Orbital with the same private key and customer identity, then persist only the verified server fields.
Events and hooks
Subscribe with a named option callback, onEvent, prophecy.on(), a wildcard listener, or the bubbling prophecy DOM event emitted from the launcher.
| Event | Option callback | When it fires |
|---|---|---|
ready | onReady | Initialisation completes |
availability-change | onAvailabilityChange | Preflight availability changes |
sign-in-required | onSignInRequired | A shopper has used their free allowance and needs to sign in |
order | onOrder | The shopper pressed Order this product |
open / close | onOpen / onClose | Dialog visibility changes |
view-change | onViewChange | Upload, library, phone, preview, generating, or result view changes |
product-change | onProductChange | Product identity or source changes |
account-change | onAccountChange | Account context is replaced |
selection-change | onSelectionChange | OV25 configuration selections change |
photo-selected / photo-cleared | onPhotoSelected / onPhotoCleared | The active room photo changes |
phone-handoff-start | onPhoneHandoffStart | Phone capture handoff begins |
phone-photo-received | onPhonePhotoReceived | A phone photo reaches the desktop |
generation-start | onGenerationStart | A generation request starts |
generation-progress | onGenerationProgress | Polling returns generation progress |
generation-complete | onResult | A browser result is ready |
generation-error | onGenerationError | Generation fails or times out |
history-load / history-save | onHistoryLoad / onHistorySave | Account history reads or writes |
history-error | onHistoryError | A history adapter operation fails |
error | onError | Any integration or runtime error |
destroyed | onDestroy | The instance is permanently removed |
Order this product
Every preview remembers two things: the configurator's SKU for that exact configuration, and the page it was generated from, query string and all. When a shopper presses Order this product, Prophecy tells your page first.
Call preventDefault() to keep the shopper on the page and take the order yourself. If you do not, they go to the page the preview was made from.
With the script tag, set the hook before the script loads:
What order carries:
| Field | Meaning |
|---|---|
sku | The configurator's SKU for the configuration in the preview |
pageUrl | The page the preview was made from, query string and all |
productUrl | Where Prophecy sends the shopper unless you call preventDefault() |
productReference / selectionString | The product and its configuration |
resultUrl / jobId | The preview image and the job that made it |
sku and pageUrl are also on every generation-complete result and every saved preview.
Instance API
| Method | Purpose |
|---|---|
checkAvailability() | Preflight setup, origin access, entitlement, and token balance |
open() / close() / isOpen() | Control and inspect dialog visibility |
mount(target) | Mount Prophecy's default launcher |
mountOverlay(target?) | Put the widget on the configurator, or another element; the script tag does this for you |
useLauncher(target) / releaseLauncher() | Move the launcher to another element, or detach it |
setProductId(id) | Synchronise an OV25 product change in an SPA |
setProduct(product) | Atomically switch an external product, its images, and URL |
setAccountContext(key) | Invalidate sessions and memory on login, logout, or account switching |
getState() | Read the current public state without subscribing |
refreshHistory() / clearHistory() | Reload or remove customer-owned history |
on(name, handler) / off(name, handler) | Add or remove event handlers |
destroy() | Abort work and remove UI, listeners, and temporary object URLs |
Core options
| Option | Type | Purpose |
|---|---|---|
sessionEndpoint | string | Same-origin retailer route returning a short-lived session |
sessionProvider | function | Programmatic alternative to sessionEndpoint |
endpoint | string | Orbital API host for a staging environment; normally omit |
configurator | selector | iframe | Disambiguate multiple configurators; normally omit |
button | selector | button | Attach Prophecy to an existing site-owned control |
productReference | string | Stable SKU, variant ID, or product handle for external images |
productImages | (string | Blob)[] | One to four CORS-readable URLs or image blobs |
productUrl | string | Result call-to-action and history URL |
resolution | '1K' | '2K' | '4K' | Requested output resolution, subject to entitlement |
history | HistoryAdapter | Account-backed load, save, and clear operations |
accountKey | string | null | Non-sensitive browser marker for account changes |
localHistory | boolean | Opt device history in or out |
development | boolean | Override automatic localhost development behaviour |
timeoutMs | number | Generation polling timeout; default four minutes |
buttonLabel | string | Wording on Prophecy's own launcher button |
Declarative attributes
| Attribute | Purpose |
|---|---|
data-prophecy-session-endpoint | Same-origin browser-session endpoint |
data-prophecy-configurator | Selector for a specific OV25 iframe |
data-prophecy-button | Selector for a site-owned launcher |
data-prophecy-endpoint | Orbital API host for a staging environment; normally omit |
data-prophecy-product-id | Explicit OV25 product ID for migration cases |
data-prophecy-product-reference | Stable external product reference |
data-prophecy-product-images | JSON array containing one to four product-image URLs |
data-prophecy-product-url | Product page URL used by results and history |
data-prophecy-resolution | Requested 1K, 2K, or 4K resolution |
data-prophecy-local-history | Explicitly enable or disable device history |
data-prophecy-auto | Enable or disable automatic initialisation |
Go-live checklist
- Test against the version you ship. The
@1URL follows fixes automatically; pin an exact version only if you want to control updates yourself. - Keep the Prophecy server key on your server only.
- Ask Orbital Vision to authorise every production origin.
- Confirm Prophecy is switched on and the organisation has enough tokens.
- Test login, logout, account switching, and anonymous-to-account transitions.
- Keep room photos and results in account-owned private storage.
- Verify completed jobs from your server before saving result metadata.
- Exercise the unavailable state so your launcher never exposes a broken feature.
For access, private API keys, authorised origins, or billing setup, contact Orbital Vision.