Develop

QR Code Detection sample overview

Updated: May 7, 2026

Overview

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.

What you will learn

  • 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)

Requirements

  • 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

Get started

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.

Explore the sample

The sample includes five C# scripts in the Meta.XR.MRUtilityKitSamples.QRCodeDetection namespace, two prefabs, and one Unity scene.
File / SceneWhat it demonstratesKey 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

Runtime behavior

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.

Key concepts

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.

Payload extraction with type safety

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.

Billboard canvas with camera-facing transform

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

Permission request flow

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.

Extend the sample

  • 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.