Vision360
Developer API
Every published tour ships a small JavaScript API. Use it to drive the tour from your own page — jump to a scene, aim the camera, react to what the visitor does.
Which one do I need?
There are two ways in, and they expose the same methods and the same events.
- Embedding the tour in an iframe — the usual case. Use
vision360-embed.jsfrom the page around it. Every call returns a Promise, because the answer crosses the iframe boundary. - Running your code inside the tour page itself — a self-hosted export, or your own wrapper around the viewer. Use
window.Vision360directly. Calls return values, not Promises.
Embedding: a complete example
Copy this into any HTML page. Replace the iframe srcwith your tour’s embed link (you’ll find it under Share in the editor).
<iframe
id="tour"
src="https://your-vision360-host/embed/my-tour"
width="100%"
height="480"
style="border:0"
allowfullscreen
allow="fullscreen; accelerometer; gyroscope; xr-spatial-tracking"
></iframe>
<script src="https://your-vision360-host/vision360-embed.js"></script>
<script>
const tour = Vision360Embed.connect(document.getElementById('tour'));
// What's in this tour?
tour.getTour().then(({ name, scenes }) => {
console.log(name, scenes.map((s) => s.name));
});
// React to the visitor moving around.
tour.on('scenechange', (scene) => {
document.title = scene.name;
});
tour.on('hotspotclick', (hotspot) => {
console.log('clicked hotspot', hotspot.hotspotId);
});
// Drive it from your own UI.
document.querySelector('#go-to-kitchen').onclick = () => {
tour.goToScene('kitchen');
};
</script>In-page: window.Vision360
Present on the hosted tour page, inside the embed, and in the offline ZIP export. Wait for ready before the first call — the viewer installs it once the tour has loaded.
await window.Vision360.ready;
const { scenes } = window.Vision360.getTour();
window.Vision360.goToScene(scenes[1].id);
window.Vision360.on('cameramove', ({ theta, phi, fov }) => {
// Fired at most ~10 times a second.
});Methods
getTour(): { id, name, scenes: { id, name, kind }[] }
The tour’s scenes in order. kind is pano, flat, spin or video360.
getCurrentScene(): { id, name, kind } | null
The scene on screen right now.
goToScene(id, view?)
Navigate, optionally arriving at a specific heading: { theta, phi } in radians. An unknown id raises an error event rather than leaving the viewer mid-transition.
getCamera(): { theta, phi, fov } | null
Where the camera is pointing. Angles in radians, fov in degrees. Null while a scene is still loading.
setCamera({ theta?, phi?, fov? })
Aim the camera. Omitted fields are left alone. FOV is clamped to the range the viewer’s own zoom uses (30–110°).
setAutoRotate(on)
Start or stop the idle rotation.
openHotspot(id): boolean
Open a hotspot’s info panel. Returns false if that hotspot is not in the current scene.
on(event, handler): () => void
Subscribe. The return value unsubscribes; off(event, handler) does the same.
Events
| Event | Payload |
|---|---|
| ready | { version } — the API is installed and usable |
| scenechange | { id, name, kind } — a new scene is on screen |
| hotspotclick | { hotspotId, sceneId } |
| hotspotclose | { id } — the info panel was dismissed |
| cameramove | { theta, phi, fov } — throttled to ~10 Hz |
| mediaplay | { hotspotId, mediaType } |
| mediaended | { hotspotId, mediaType } |
| leadsubmit | the submitted contact form fields |
| fullscreenchange | { fullscreen: boolean } |
| error | { message } |
REST API
Separately from the in-page SDK, there is a server-side REST API for reading your own tours, leads and analytics. Create a key under Settings → API keys and send it as a bearer token.
curl https://your-vision360-host/api/v1/tours \
-H "Authorization: Bearer v360_your_key_here"| Endpoint | Scope |
|---|---|
| GET /v1/tours | tours:read |
| GET /v1/tours/:id | tours:read |
| GET /v1/tours/:id/analytics?days=30 | analytics:read |
| GET /v1/tours/:id/leads | leads:read |
| POST /v1/tours/:slug/leads | leads:write |
A key only ever reaches its own account’s tours, and a key without the listed scope gets a 403 rather than a partial result. Revoking a key takes effect on the next request.
What the API can and cannot see
Everything reachable through the API is already in the published tour the visitor is looking at: scene names and ids, the camera, which hotspot was clicked. There is no method that reads the author’s account, an unpublished draft, lead submissions, or analytics.
For embeds, replies and events are posted to the specific origin that asked for them — never '*'. A page that never sends a command is never sent anything.
A password-protected tour is protected before any of this applies: the embed shows the password prompt, and no tour data — including scene names — reaches the API until the visitor unlocks it.