The v1 module

What the first-generation widget is, what it still supports, and how it differs from Saphere Scan v2.

New integrations should use Saphere Scan v2. This section exists for products already running the v1 module in production, and documents it as it is.

The v1 module, called rjcaducy internally, is the original embeddable widget. It is a React application, bundled into a single file and served from the CDN, that renders the whole measurement journey inside a container you provide.

It remains served and it remains functional. It is no longer where new work happens.

What it does

The same thing v2 does, by a different route: it explains the measurement, collects consent, guides the user into frame, captures for thirty seconds, and shows a result. It reports progress to your page through an onEvent callback.

It is customisable through a large options object — an eleven-colour palette, per-screen toggles, and a complete override of every string in ten languages.

How it differs from v2

The two widgets do not share an API. Migrating means rewriting the integration, not renaming a few fields.

v1 (Handler)v2 (SaphereScan)
Entry pointwindow.Handler, or the handler-ready eventimport SaphereScan from …
MountingHandler.load(container, options)SaphereScan.create(root, options) then await bootstrap()
CredentialYour API key, or a measure id you fetch yourselfA short-lived, scoped access token
Events8 event types40, namespaced domain:event
Refusing a transitiononEvent returning falseA separate hooks API, with a guard delay
Colours11 numbered slots (color01color11)Per-screen and per-variable options
IsolationOptional shadow DOM (useShadow)Always a shadow root

Two differences matter more than the rest.

The credential model changed. In v1 you either put an API key where the widget could reach it, or you created the measure yourself and handed the widget its identifier. In v2 the widget asks your server for a token that is scoped to one thing, expires within 48 hours, and can be made single-use. That is the main reason to migrate.

The event channel does not block. In v1, the widget waited for your onEvent handler, and a returned false cancelled a screen change. A slow handler could therefore hold the interface. v2 never waits on onEvent; the power to refuse moved to hooks, where it is bounded by a timeout.