Skip to content

Tracking Data

XRXP supports both discrete events and continuous spatial tracking.

Object tracking

Add XRXPObjectTracker to any GameObject you want to follow during a session.

Common uses:

  • head and hands
  • tools and props
  • gaze targets or UI objects
  • experiment-specific interactables

Key tracker fields

Field Meaning
Category Group name such as Body, Prop, or UI
ObjectName Stable identifier for the tracked object
TraceFrequency Number of frames between samples; 1 means every frame, 0 disables recording
TracingEnabled Enable or disable capture

Example

var tracker = gameObject.AddComponent<XRXPObjectTracker>();
tracker.Category = "Body";
tracker.ObjectName = "RightHand";
tracker.TraceFrequency = 5;

The tracker automatically calls AddInternalEvent with SystemType.WorldPosition on LateUpdate. It only records when XRXPManager.IsReady, TracingEnabled is true, and a session is active.

Event types you will usually combine

  • Log events — discrete actions formatted as Actor, Verb, Object with optional properties
  • Internal events — continuous system or transform data recorded at a point in time, grouped under a system
  • Questions — questionnaire answers with optional properties
  • Media events — files (images, audio, video, documents) produced during the experiment

How internal systems and events work

When you call AddInternalEvent, the SDK:

  1. checks if an InternalSystem with that systemName already exists for the current session
  2. if not, creates one (linked to the session, user, and system type) and sends it as a trace
  3. creates an InternalEvent record with the timestamp, property name, and value, linked to that system

One system groups many events. For example, a "BodyTracking" system with SystemType.WorldPosition can have events for "Head", "LeftHand", and "RightHand" — all under the same system.

using XRXP.Recorder.Models;

// All three events belong to the same "BodyTracking" system
XRXPManager.Recorder.AddInternalEvent(
    SystemType.WorldPosition, "BodyTracking", "Head",
    new WorldPosition(head.position, head.rotation)
);
XRXPManager.Recorder.AddInternalEvent(
    SystemType.WorldPosition, "BodyTracking", "LeftHand",
    new WorldPosition(leftHand.position, leftHand.rotation)
);
XRXPManager.Recorder.AddInternalEvent(
    SystemType.WorldPosition, "BodyTracking", "RightHand",
    new WorldPosition(rightHand.position, rightHand.rotation)
);

System types

SystemType Value class Use case
WorldPosition WorldPosition(Vector3, Quaternion) Track position and rotation of objects, body parts, gaze
QuantitativeValue Any class implementing Jsonable Track numeric signals: speed, heartbeat, score, distance

Jsonable is an interface with a single method string ToJSON(). WorldPosition implements it. For QuantitativeValue, create your own class:

using XRXP.Recorder.Models;

public class QuantitativeValue : Jsonable
{
    public float Value;
    public string Unit;

    public QuantitativeValue(float value, string unit)
    {
        Value = value;
        Unit = unit;
    }

    public string ToJSON()
    {
        return UnityEngine.JsonUtility.ToJson(this);
    }
}

Then use it:

XRXPManager.Recorder.AddInternalEvent(
    SystemType.QuantitativeValue, "Biometrics", "HeartRate",
    new QuantitativeValue(72f, "bpm")
);

Naming guidance

Use a stable schema from the start of a study:

  • actors: User, System, NPC_Guide
  • verbs: clicked, grabbed, entered, completed
  • objects: specific object or state names

Consistent naming makes the dashboard much easier to filter and export later.