Develop

Gaze Interactions

Updated: Sep 9, 2026

Overview

Gaze interactions let users target virtual objects with their eyes. The user looks at an object, then confirms the action with a pinch or a controller button. You can combine gaze with hand tracking and controllers. Gaze suits menus, buttons, and other user interface work.

Architecture of a gaze interaction

A gaze interaction starts with the user’s gaze ray. Interaction SDK derives that ray from eye tracking and head tracking. A hit-test mechanism casts the ray against the gaze targets in the scene. The target that wins the hit test then receives interaction events such as hover and select.
Four components make up the stack:
ComponentRole
EyeGaze
Supplies the gaze pose and the tracking state.
GazeConecaster
Hit-tests the gaze ray against the registered targets.
GazeInteractor
Drives the interaction and applies the selection.
GazeInteractable
Marks an object as a gaze target.
Diagram of the gaze interaction stack. EyeGaze supplies the gaze pose to GazeConecaster, which hit-tests the gaze ray against registered targets and hands the winning candidate to GazeInteractor, which sends hover and select events to GazeInteractable.

GazeInteractor

GazeInteractor drives the gaze interaction. It reads a candidate from its hit-test provider. It then hovers that candidate and selects it when the selector fires.
Serialized memberDescription
Pointer Transform
The transform whose pose delta offsets generated pointer events during selection.
Selector
The ISelector that enters the selected state. This is typically a pinch or a controller button.
Candidate Provider
The hit-test mechanism that picks the target. This is typically a GazeConecaster.

GazeInteractable

A GazeInteractable marks an object as a gaze target. Targets are often virtual objects such as a door or a button. They can also be menus and user interface elements.
Serialized memberDescription
Surface
Required. The ISurface used for gaze hit testing.
Selection Surface
Optional. An override surface to raycast against while the target is selected.
Movement Provider
Optional. An IMovementProvider that sets how the object moves while selected. It applies to gaze grab interactions, where the provider drives the object as the grab is held. Leave it empty for a target that does not move.
Tiebreaker Score
The priority used when all other factors are equal. A higher value wins.
Root Canvas
Optional. The top-level ConecastableCanvas, if this target sits on a canvas panel.
MultiGrab scaling support
Enabled by default. The interactable wraps its pointable element in a MultiGrabPointableElement, so a grab held by two or more pointers pivots and scales about the interactable’s own transform. Disable it to drive the pointable element directly, with no multi-grab scaling.
Selection Surface and Movement Provider sit inside the collapsed Optionals foldout rather than in the main property list.
The Gaze Interactable component in the Inspector with the Optionals foldout expanded to show Selection Surface and Movement Provider.

GazeConecaster

GazeConecaster is the default hit-test mechanism. It implements GazeInteractor.IGazeCandidateProvider. It casts a cone from the gaze pose against the registered targets. A consensus filter then picks the target held longest inside the dwell window.
To extend this mechanism, implement IGazeCandidateProvider. Inherit from the base Conecaster class to change only how candidates are ranked. You can also write a completely new provider, for example a GazeSpherecaster of your own.
Serialized memberDescription
Gaze
The IGaze that supplies the center eye pose. This pose is the cone origin.
Cone Angle
The largest angle, in degrees, between the gaze ray and a candidate.
Cone Length
The length of the cone in meters, measured along the gaze ray.
Dwell Timespan Seconds
The window used to choose a target. The target hovered longest in this window wins.
Default Comparer
The comparer that sorts conecast results. Override it with SetOverrideComparer().
Enable Debug Visuals
Draws an axis gizmo at the hit point. This gizmo works in the headset.
The Gaze Conecaster component in the Inspector on the EyeGaze prefab, showing Cone Angle, Cone Length, Default Comparer, Gaze, Dwell Timespan Seconds, and Enable Debug Visuals.
Cone Angle is measured from the gaze ray to a candidate, and Cone Length is measured along the gaze ray from the cone origin.
Illustration of a gaze conecast. A cone opens from the center eye pose along the gaze ray. Cone Angle labels the angle between the gaze ray and the cone edge, and Cone Length labels the reach of the cone in meters. A target inside the cone is a candidate and a target outside it is ignored.

EyeGaze

EyeGaze sits at the top of the gaze input stack. It plays the role that the Hand component plays for hand input. EyeGaze implements IGaze, so wire it to fields that take an IGaze dependency unless you need further modifiers.
EyeGaze also implements IActiveState. Its Active property reports true when the gaze data is valid. Interaction SDK treats this as the gaze active state. The Gaze quick actions bind an ActiveStateTagSetFilter to EyeGaze, which lets ray interactors take over when gaze is not available.
Note
Valid gaze data does not prove that eye tracking produced it. The pose can be emulated from the headset pose. To tell the two apart, read EyeGaze.IsSyntheticPose.
Serialized memberDescription
Emulate Gaze With Camera Pose
Replaces the gaze pose and tracking state with the center eye anchor pose. Downstream components then see an active gaze source.

Eye tracking active states

Two components report whether the runtime supports eye tracking. Both are MonoBehaviour components that implement IActiveState, so you can wire either one into a field that takes an IActiveState dependency. Which one you use depends on your rig.
ComponentDescription
OVREyeTrackingActiveState
For an OVR player rig. Active is true when OVRPlugin reports that the runtime supports eye gaze interactions. This component ships in the com.meta.xr.sdk.interaction.ovr package.
UnityXREyeTrackingActiveState
For a Unity XR player rig. Active is true when the XR_EXT_eye_gaze_interaction OpenXR extension is enabled and the EyeGazeInteraction feature is enabled in the project’s OpenXR settings. A project that is not built against OpenXR reports false. This component ships in the com.meta.xr.sdk.interaction package.
For UnityXREyeTrackingActiveState to report true, go to Edit > Project Settings > XR Plug-in Management > OpenXR and add Eye Gaze Interaction Profile to Enabled Interaction Profiles.
Each component resolves its answer on the first read of Active and caches it for the lifetime of the component.
Note
These components report platform support, not live tracking. Active tells you whether the runtime supports eye tracking. It does not tell you whether the gaze pose is valid this frame, and it does not tell you whether eye tracking produced that pose. For the per-frame signal, read EyeGaze.Active. For the source of the pose, read EyeGaze.IsSyntheticPose.

EyeGazeRef

EyeGazeRef is the gaze equivalent of HandRef. Use it to reference an EyeGaze source from elsewhere in the scene.

Learn more