QR Code Detection sample overview
Updated: May 7, 2026
This sample demonstrates real-time QR code detection in mixed reality using the Mixed Reality Utility Kit (MRUK) trackables API. It subscribes to spatial tracking events, filters for QR code trackables, visualizes their 2D bounding boxes, and displays payload data as billboard UI elements.
- Subscribe to
MRUK trackable events to detect QR codes in the physical environment - Filter trackable objects by type and extract payload data (UTF-8 strings or binary)
- Visualize 2D bounding rectangles aligned to physical marker locations
- Implement billboard behavior to make world-space canvas elements face the camera
- Manage runtime permission requests for spatial data (Scene permission)
- Meta Quest 3, or Quest 3S (devices with passthrough and spatial tracking support)
- Unity 2022.3 LTS or newer with the Mixed Reality Utility Kit package installed
- For detailed setup instructions, see the
MRUK setup guide
Clone or download the Unity MRUtilityKitSample repository from GitHub. Open the project in Unity and navigate to Assets/MRUKSamples/QRCodeDetection/. Open the QRCodeDetection.unity scene, then build to your Meta Quest device. For detailed build instructions, see the repository’s README.
The sample includes five C# scripts in the Meta.XR.MRUtilityKitSamples.QRCodeDetection namespace, two prefabs, and one Unity scene.
| File / Scene | What it demonstrates | Key concepts |
|---|
QRCodeDetection.unity | Main scene setup with MRUK configuration, camera rig, and UI panel | Scene configuration, spatial tracking initialization |
QRCodeManager.cs | Central controller that subscribes to MRUK trackable events and spawns QR code overlays | Event-driven trackable lifecycle, singleton pattern, permission handling |
QRCode.cs | Per-QR-code instance that displays payload text and tracking state | Payload extraction (string vs binary), dynamic UI updates |
QRCodeFaceCamera.cs | Billboard behavior that makes the canvas always face the user | Camera-facing transform manipulation |
Bounded2DVisualizer.cs | Renders a 4-corner rectangle outline matching the QR code’s 2D bounding box | LineRenderer-based boundary visualization |
QRCodeSampleUI.cs | Status panel showing device support, permissions, tracking toggle, and activity log | Runtime state monitoring, permission UI flow |
QRCodePrefab.prefab | Visual overlay instantiated per detected QR code | Prefab composition, child-transform parenting |
QRCodeSampleUI.prefab | Controller-attached UI for status and controls | Wrist-mounted UI pattern |
When you run this scene, a status panel attached to your controller shows QR code tracking support, permission status, active tracker count, a tracking toggle, and a color-coded log. Press the Request Permissions button to grant the spatial data (Scene) permission.
Point your headset at a physical QR code. An orange rectangle outline overlays the bounding box, a small RGB axes gizmo shows pose orientation, and a billboard canvas floats below displaying the payload text (for example, “https://example.com”) and tracking state (“Tracked” or “Untracked”). The canvas always faces the camera. Toggle tracking on or off via the UI panel. When a QR code leaves view, the overlay is removed and the active count decrements.
Event-driven trackable lifecycle
The sample subscribes to MRUK’s TrackableAdded and TrackableRemoved events to detect when QR codes enter or leave the tracking system. This pattern allows the sample to spawn overlays immediately when QR codes enter view, without polling for updates. When a trackable is added, the manager filters for OVRAnchor.TrackableType.QRCode and instantiates the overlay prefab as a child of the trackable’s transform, automatically positioning it at the physical QR code’s location.
Source: QRCodeManager.cs
_mrukInstance.SceneSettings.TrackableAdded.AddListener(OnTrackableAdded);
_mrukInstance.SceneSettings.TrackableRemoved.AddListener(OnTrackableRemoved);
For the full API specification, see the Trackables overview.
QR codes can encode UTF-8 strings or arbitrary binary data. The sample checks MarkerPayloadString first, falling back to MarkerPayloadBytes if the payload is not a valid string. Binary payloads display the first 16 bytes as hex-formatted data along with total length metadata. This pattern handles both URL-encoded markers and custom binary protocols.
Source: QRCode.cs
if (trackable.MarkerPayloadString is { } str)
_text.text = $"\"{str}\"";
else if (trackable.MarkerPayloadBytes is { } bytes)
_text.text = $"Binary(data=[...], length={bytes.Length})";
For payload format details, see the QR Code Detection guide.
The sample implements billboard behavior by updating the canvas transform each frame to face the main camera. The QRCodeFaceCamera component uses Quaternion.LookRotation to orient the canvas toward the camera position, ensuring the text remains readable regardless of the user’s viewpoint. This technique is essential for world-space UI elements in mixed reality.
Source: QRCodeFaceCamera.cs
The sample uses OVRPermissionsRequester.ScenePermission to request spatial data access, which is required for QR code tracking. The sample requests permission on button press rather than at startup, giving users explicit control over when the permission dialog appears.
Source: QRCodeManager.cs
For permission best practices, see the Spatial Data Permission guide.
- Interact with detected QR codes: Add raycasting to detect when the user taps a QR code overlay, then trigger an action like opening a URL or spawning a 3D object.
- Filter by payload content: Modify OnTrackableAdded to only visualize QR codes whose payload matches a specific pattern (for example, URLs starting with “https://yourdomain.com”).
- Track other marker types: Explore the Keyboard Tracking sample (Assets/MRUKSamples/KeyboardTracker/) to see how the same trackable pattern applies to detecting physical keyboards with 3D bounding boxes instead of 2D rectangles.