Develop

Interaction Broadcaster

Updated: Sep 8, 2026
An Interaction Broadcaster is a scene-level singleton that observes registered interaction state changes from both 3D and UI sources. It rebroadcasts them by using an InteractionEventChannel ScriptableObject asset and a static C# event. This helps centralize a data source for analytics, tutorials, global UI, and systems like the Feedback Manager.
This page assumes you have a camera rig with interactors already set up in your scene.
This page draws on two separate packages. The Meta XR Interaction SDK Essentials package provides the broadcaster, the Feedback Manager, and the ripple cursor effect. The Meta XR Interaction SDK package provides MicrogestureScroll.prefab. Install both if you plan to follow the Migrate an existing scene steps.

Overview

Most interactions adhere to a unified Pointer Lifecycle and Pointer Events model (Identifier, Type, Pose, Data). The Broadcaster listens to those changes across interactors and interactables, normalizes them into an InteractionEvent struct, and raises:
  • InteractionEventChannel.OnEventRaised (shared ScriptableObject asset, raised only when a channel asset is assigned)
  • InteractionBroadcaster.OnEventRaised (C# static event)
This pattern avoids tight coupling and lets you monitor behavior across the whole scene from one place.

How it works

The Interaction Broadcaster uses auto-registration to automatically set up connections between Interactors (hands, controllers, and rays) and Interactables (buttons, panels, and grabbable objects). This makes setup less error-prone. Auto-registration wires eight interactor-interactable pairs: Grab, Poke, Ray, HandGrab, HandGrabUse, DistanceGrab, DistanceHandGrab, and TouchHandGrab.
The Interaction Broadcaster uses an event flow that lets you handle interaction events in a modular and decoupled way. This lifecycle consists of the following flow:
  1. The interactable object, such as a button or grabbable item, detects an interaction event, such as hover, grab, or poke.
  2. A handler processes the interaction event, determining the event type.
  3. The broadcaster raises the event on the static C# event, and, if a channel asset is assigned, on the InteractionEventChannel as well.
  4. All scripts, components, and systems that subscribed receive the event and can respond.
You can extend the Interaction SDK to define your own Interactor and Interactable pairs and add custom logic to handle the new types.

Setup

You can add the Interaction Broadcaster to your scene in three ways.
The FeedbackManager prefab includes an InteractionBroadcaster component.
  1. In the Project panel, navigate to Packages > Meta XR Interaction SDK Essentials > Runtime > Prefabs > Feedback.
  2. Drag FeedbackManager.prefab into the root of your scene Hierarchy.
The prefab is a single GameObject with three components: Transform, FeedbackManager, and InteractionBroadcaster. It ships with the Event Channel field already assigned and with Auto Register Interaction Types enabled.

Use the standalone broadcaster prefab

If you only need event broadcasting without the Feedback Manager, add the pre-wired broadcaster prefab.
  1. In the Project panel, navigate to Packages > Meta XR Interaction SDK Essentials > Runtime > Prefabs > Feedback.
  2. Drag InteractionBroadcaster.prefab into the root of your scene Hierarchy.
InteractionBroadcaster.prefab ships with the default event channel asset already assigned to its Event Channel field, and with Auto Register Interaction Types enabled.

Create the broadcaster manually

  1. In the Hierarchy panel, right-click an empty area and select Create Empty.
  2. Name the GameObject “InteractionBroadcaster”.
  3. In the Inspector, click Add Component and search for InteractionBroadcaster.
  4. Assign an InteractionEventChannel ScriptableObject asset to the Event Channel field, or leave it null to use only the static C# event. Interaction SDK ships a default asset in the Project panel at Packages > Meta XR Interaction SDK Essentials > Runtime > DefaultSettings. To make your own, select Assets > Create > Meta > Interaction SDK > Feedback > Interaction Event Channel.
InteractionEventChannel is not a component. It is a ScriptableObject asset that ships with Interaction SDK and is referenced by the broadcaster’s Event Channel field.
Auto Register Interaction Types is enabled by default on a newly added InteractionBroadcaster component. If no events reach your subscribers, see Troubleshooting.

Subscribe to events

Use whichever option fits your use case:
  • ScriptableObject channel to share one event source across systems without referencing each other. Assign the same channel asset in the Inspector and subscribe to OnEventRaised in code.
  • Static C# event for low-overhead subscription.
To filter events in your subscription, use one of the following:
  • InteractionType, such as HoverStart or UISelectEnd. For the complete list of values, see InteractionType.
  • Source GameObject, to watch a single object.
  • Interactor, matched on InteractorView, or on _pointerId for pointer-based interactions.
The following component subscribes to the static event, filters for selections from both 3D and UI sources, and unsubscribes when disabled:
using Oculus.Interaction.Feedback;
using UnityEngine;

public class SelectionLogger : MonoBehaviour
{
    private void OnEnable() => InteractionBroadcaster.OnEventRaised += HandleInteraction;
    private void OnDisable() => InteractionBroadcaster.OnEventRaised -= HandleInteraction;

    private void HandleInteraction(InteractionEvent evt)
    {
        bool isSelectStart = evt._type == InteractionType.SelectStart
            || evt._type == InteractionType.UISelectStart;

        if (!isSelectStart || evt._source == null)
        {
            return;
        }

        // InteractorView is null for UI-origin events.
        Debug.Log($"Selected {evt._source.name}, from UI: {evt.InteractorView == null}");
    }
}
Attach this component to any active GameObject in your scene.
Note:_type, _source, and _pointerId are public fields on the InteractionEvent struct despite the underscore prefix.

Example: Surface ripple cursor effect

The surface ripple cursor effect demonstrates how to use the Interaction Broadcaster to produce input-agnostic poke feedback, rendering a ripple on the poked surface.
In the Project panel, navigate to Packages > Meta XR Interaction SDK Essentials > Runtime > Sample > Prefabs and add RippleCursorEffect.prefab to your scene. The prefab pools and spawns instances of its child Cursor object. It requires a PokeInteractor in your rig and an Interaction Broadcaster in the scene.
For a working example, see the UISetExamples scene in Creating UIs with UISet.

Best practices

  • Always unsubscribe in OnDisable to prevent memory leaks and handle domain reloads, as shown in the SelectionLogger example.
  • Use a ScriptableObject channel when you need designer-configurable event routing. Use static events for performance-critical code paths.
  • Always null-check _source or InteractorView before accessing.
  • For systems that monitor interactions, such as tutorials, analytics, and achievements, subscribe to the centralized broadcaster and filter events rather than attaching listeners to individual interactable objects.

API reference

The Interaction Broadcaster exposes the following API for event monitoring.

InteractionBroadcaster

  • static InteractionBroadcaster Instance { get; } – Singleton instance of the InteractionBroadcaster
  • static event Action<InteractionEvent> OnEventRaised – Static C# event fired when any registered interaction occurs
  • static void RegisterCustomInteractionType<TInteractor, TInteractable>() – Registers a custom interactor-interactable pair for automatic event broadcasting
  • static void UnregisterCustomInteractionType<TInteractor, TInteractable>() – Stops monitoring a custom interactor-interactable pair
  • void RegisterInteractionType<TInteractor, TInteractable>() – Instance method to register a custom interaction type
  • void UnregisterInteractionType<TInteractor, TInteractable>() – Instance method to stop monitoring an interaction type

InteractionEventChannel

  • event Action<InteractionEvent> OnEventRaised – C# event raised by Raise. Subscribe in code. The channel asset itself is assignable in the Inspector, which is how systems share one channel without referencing each other.
  • void Raise(in InteractionEvent interactionEvent) – Manually raises an interaction event

InteractionEvent

  • InteractionType _type – The type of interaction. See InteractionType for the complete list of values.
  • IInteractorView InteractorView – The interactor that triggered the event. This is null for UI-origin events.
  • GameObject _source – The source GameObject that was interacted with. This can be null.
  • int _pointerId – Identifier for pointer-based interactions. Defaults to -1 when not applicable.

InteractionType

Values 1 through 4 originate from 3D interactors. Values 10 through 13 originate from Unity UI (Canvas) sources, for which InteractorView is null. None is a default sentinel and does not originate from an interactor.
NameNumeric value
None
0
HoverStart
1
HoverEnd
2
SelectStart
3
SelectEnd
4
UIHoverStart
10
UIHoverEnd
11
UISelectStart
12
UISelectEnd
13

Microgesture scroll and the Interaction Broadcaster

Microgesture scrolling runs through DiscreteScrollInputProvider, which ships in the Meta XR Interaction SDK Essentials package in the Oculus.Interaction namespace. The caller supplies the scroll direction, so the component works with any input source.
Note:DiscreteScrollInputProvider is marked [Experimental]. Experimental types can change or be removed without a deprecation cycle.
DiscreteScrollInputProvider exposes the following members:
MemberDescription
Scroll(Vector2 direction)
Scrolls the current target in the given direction. A zero vector cancels in-flight momentum.
ScrollUp(), ScrollDown(), ScrollLeft(), ScrollRight()
Convenience wrappers around Scroll.
The component exposes the following Inspector fields:
Inspector fieldDefault
Interactor
None. Assign the interactor that drives scrolling.
Scroll Speed
2
Stop Momentum On Target Change
Off

Migrate an existing scene

If you wired microgesture scrolling through the broadcaster before v207, update your scene:
  1. Delete the obsolete MicrogestureScrollProvider component, along with the MicrogestureScrollProvider prefab instance if you used it.
  2. Delete any MicrogestureScrollSettings components. These components are obsolete. Any per-ScrollRect overrides they set are ignored.
  3. In the Project panel, navigate to Packages > Meta XR Interaction SDK > Runtime > Prefabs > Microgestures and drag MicrogestureScroll.prefab into your Hierarchy. The prefab is a single GameObject carrying DiscreteScrollInputProvider, OVRMicrogestureEventSource, and MicroGestureUnityEventWrapper, with the four swipe events already bound to ScrollUp, ScrollDown, ScrollLeft, and ScrollRight.
  4. Assign the interactor that drives scrolling to the Interactor field on DiscreteScrollInputProvider, and your scene’s OVRHand to the Hand field on OVRMicrogestureEventSource. Both ship unset. DiscreteScrollInputProvider asserts at Start() if Interactor is empty.

Troubleshooting

The broadcaster is not emitting any events after triggering interactions

Solution: Verify the following:
  1. Ensure the InteractionBroadcaster component is active in your scene.
  2. Check that Auto Register Interaction Types is enabled on the InteractionBroadcaster component in the Inspector.
    Note: The tooltip reads “If true, standard interaction types (Grab, Poke, Ray) will be automatically registered on enable.” That names a representative subset. For the full set of registered pairs, see How it works.
  3. If using custom interactor types, verify you called RegisterCustomInteractionType<TInteractor, TInteractable>() after the broadcaster starts.
  4. Add a debug listener to confirm events are firing:
     InteractionBroadcaster.OnEventRaised += (evt) => Debug.Log($"Event: {evt._type}");
    

Custom interactor types are not broadcasting events

Solution: Register your custom types properly:
  1. Ensure you call RegisterCustomInteractionType<TInteractor, TInteractable>() in your script’s Start() method, after the broadcaster has initialized.
  2. Verify that your custom interactor derives from Interactor<TInteractor, TInteractable> and your custom interactable derives from Interactable<TInteractor, TInteractable>. RegisterCustomInteractionType constrains both type parameters to these base classes, so a type that only implements IInteractor or IInteractable will not compile.

UI pointer events are not being received

Solution: Verify the broadcaster, the scene-scoped, and the Canvas-scoped parts of the setup:
  1. On the InteractionBroadcaster component, confirm Auto Register Interaction Types is enabled. The UI pointer hooks are registered alongside the standard interaction types, so no UI events broadcast while this option is off.
  2. Select the EventSystem GameObject in the Hierarchy and confirm it has a PointableCanvasModule component. PointableCanvasModule is a Unity PointerInputModule subclass, so exactly one instance must exist in the scene and it belongs on the EventSystem GameObject rather than on a Canvas. If it is missing, click Add Component and search for PointableCanvasModule.
  3. If a PointableCanvasModule is also present on a Canvas, remove it. Only one instance can exist in the scene, and it belongs on the EventSystem GameObject.
  4. On the EventSystem GameObject, make sure PointableCanvasModule is first in the component list or has Exclusive Mode enabled. Otherwise, you can run into input conflicts.
  5. Select your Canvas in the Hierarchy and confirm it has both a PointableCanvas component and a GraphicRaycaster component. PointableCanvas requires that its Canvas has a GraphicRaycaster.
  6. If you route Canvas events to UnityEvents, confirm the Canvas also has a PointableCanvasUnityEventWrapper component and that it references the Canvas PointableCanvas.
For the full Canvas setup procedure, see Unity Canvas Integration.

Learn more