Telemetry

What the player sends.

The JEEX player sends a small amount of anonymous data about how it runs, so that we can make it faster, fix its errors and see which of its features are used, and on which sites. This page lists everything it sends. Nothing else leaves the player.

The data is anonymous and is used only to improve the player. It is never sold, never used for advertising and never linked to people.

How to turn it off

  • On the element: <jeex-viewer analytics="off">. It fails closed: only a missing attribute or exactly on sends; any other value turns it off.
  • On the iframe page: embed.html?analytics=off, or analytics: 'off' in embedViewer(...).
  • In code: mountViewer(el, { analytics: { mode: 'off' } }).
  • A visitor whose browser sends Global Privacy Control (navigator.globalPrivacyControl === true) is never counted.

Off means no request at all. Everything else the player does is unchanged: it still loads its scene and models from wherever they are served.

analytics-endpoint (?analyticsEndpoint=, analytics.endpoint) sends the same data to another address instead: an https: URL, or http: on localhost/127.0.0.1. Any other value turns telemetry off.

Where it goes

Every request is a POST of one JSON object to https://telemetry.jeex.org/v1/player, made with fetch and keepalive, without credentials (credentials: 'omit'), without a referrer (referrerPolicy: 'no-referrer'), without custom headers and without retries. A failed request is ignored. A site with a Content Security Policy must allow the endpoint in connect-src; otherwise the requests are refused silently.

Like any web request, a request reaches the server with the visitor's IP address and the browser's standard headers. The player cannot remove them; the player itself never sends them in the body, and the receiving server's own policy covers what it keeps of them.

What is never sent

No cookies and nothing read from or written to any browser storage. No visitor or visit identifier, not even a temporary one: two requests of the same visit share no field beyond the shared context below. No user-agent string, no GPU vendor or renderer string, no fonts, no screen size, no time zone. No camera position, no path through the apartment, no order of events, no timestamps. No query string or fragment of the page address. No error message and no raw stack. No form data or other content of the page.

What is sent

Each request belongs to one group (group) and carries the shared context. Every field of every request is in the tables below; a field that is not in them is never sent.

Shared context

FieldMeaningExample
schemaversion of this payload format"1.1.0"
playerversion of the player"0.1.0"
embedhow the player is embedded: element, iframe or script"element"
siteorigin of the page; for the iframe page, the embedding page's origin as the browser reports it or as the host's verified messages prove it; null when not known"https://agency.example"
pagepath of the page without query and fragment; a segment that looks like an email, a handle, a UUID, a token or a long number becomes :id; at most 200 characters; null when not known"/flats/:id"
subjectwhat is played: the three ids below{"project": "0192…", "bake": "0192…", "scene": "0192…"}
langlanguage of the player's interface: en, de, fr, it, es, sr-Latn, ru, or other"en"
groupwhich group the request belongs to: lifecycle, actions, rooms, device, error"lifecycle"

subject, each a UUID of the document on screen, or null when not known:

FieldMeaningExample
projectthe baked project"0192f5c4-7a1b-7c3d-8e9f-0a1b2c3d4e51"
bakethis bake of the project"0192f5c4-7a1b-7c3d-8e9f-0a1b2c3d4e52"
scenethe scene document"0192f5c4-7a1b-7c3d-8e9f-0a1b2c3d4e53"

lifecycle

FieldMeaningExample
eventview (the player mounted), ready (the first frame was drawn), models_loaded (the 3D models finished loading), engaged (the view ended: the page was hidden, the scene replaced or the player removed)"ready"
loadready and models_loaded: time since the mount or the scene change: <1s, 1-3s, 3-10s, 10-30s, >30s"1-3s"
outcomemodels_loaded: complete, partial (some failed), budget (stopped by the size limit), none (nothing to load)"complete"
failedmodels_loaded: models that could not load, at most 500
assetsmodels_loaded: UUIDs of the project's library assets, at most 50["0192…"]
engagedengaged: time while the page was visible and the player was running, since the view began or since the last engaged, in every view mode: <10s, 10-30s, 30s-2m, 2-5m, 5-15m, >15m; never sent for no time at all"2-5m"

view is sent once per player, when its first scene has loaded or failed, at most 2 seconds after the mount, with the subject known then (a failed load names the project and bake when its manifest was read); ready is sent at once (the iframe page holds both up to 2 seconds for its host to name the page first); engaged is sent when the page is hidden, the scene is replaced or the player is removed, for the scene the time was spent on; everything else is sent when the page is hidden or closed, every 5 minutes, and when the scene changes.

actions

FieldMeaningExample
countshow often each action below was done since the last request; each at most 50 over the whole view{"mode": 3, "door": 1, …}

The actions in counts:

FieldMeaningExample
modethe view mode changed, from the start mode on (opening in one mode is not a change)3
interioran interior style was applied0
select_furniturea piece of furniture was selected (when the site enables selection)0
select_openinga door or window was selected0
select_walla wall was selected0
select_rooma room was selected0
panela selection panel was opened1
doora door was opened or shut1
fullscreenfullscreen was entered0
minimapthe mini-map was used to move2
camera_stepthe camera stepped to a tour camera4
tour_startthe tour started1
tour_completethe tour played to its end0

rooms

FieldMeaningExample
roomsthe rooms the camera was in during a walk or a tour, sorted by room id, never in visit order, at most 100[{"room": "0192…", "dwell": "30s-2m"}]
roomthe room's UUID from the scene"0192f5c4-7a1b-7c3d-8e9f-0a1b2c3d4e54"
dwelltime spent there: <5s, 5-30s, 30s-2m, 2-10m, >10m"30s-2m"

device

FieldMeaningExample
fpsshare of drawn time per frame-rate range, in whole tenths of percent{"<20": 0, "20-30": 10, "30-50": 30, ">50": 60}
<20share below 20 frames per second0
20-30share from 20 to 3010
30-50share from 30 to 5030
>50share above 5060
gpucapability class from what WebGL supports (texture size, multisampling, float colour buffers), not a performance ranking: low, mid, high, none"mid"
widthwidth of the player: <480, 480-1024, 1024-1600, >1600"1024-1600"
inputtouch or pointer"pointer"
fullscreenshare of drawn time in fullscreen, in whole tenths of percent0

error

One request per distinct error, at most 10 per view; repeats of the same error are counted, not sent again.

FieldMeaningExample
codenetwork, scene_format, manifest_format, model_format, webgl_unavailable, context_lost, size_limit, exception, rejection, other"network"
stagescene_load, model_load, capture, mode, tour, embed, bridge, runtime"scene_load"
namestandard class name of the error, otherwise Error: Error, TypeError, RangeError, ReferenceError, SyntaxError, EvalError, URIError, AggregateError, InternalError, ViewerLibError, SceneValidationError, AbortError, NetworkError, NotSupportedError, NotAllowedError, InvalidStateError, SecurityError, QuotaExceededError, DataCloneError, EncodingError, TimeoutError, OperationError, UnknownError"TypeError"
framesup to 5 top stack frames in the player's own published files only[{"file": "jeex-viewer.iife.js", "line": 1, "column": 52310}]
filethe frame's file name, without its directory, query or fragment"jeex-viewer.iife.js"
linethe frame's line1
columnthe frame's column52310
browserbrowser family and major version range"chromium-14x"
counthow often it happened since the last request, 1 to 502

An exception whose stack has no frame in the player's own files (the site's code, a browser extension, or a player bundled into a site's own script) is not reported at all.

Schema

telemetry.schema.json is the exact JSON Schema of every request body, generated from the schema the player checks each request against before it is sent. It is also published at https://player.jeex.org/schema/telemetry/1.1.0.json and in the package as jeex-viewer/schema/telemetry.json. Any change to these fields changes the schema version and is listed in CHANGELOG.md.