Develop
Develop
Select your platform

Colocation Discovery

Updated: Nov 5, 2025

Learning Objectives

  • Understand how Colocation Discovery uses Bluetooth to enable nearby user discovery and session sharing.
  • Learn the core OVRColocationSession API methods for advertisement and discovery workflows.
  • Configure your Unity project with the required permissions and OVRManager settings.
  • Implement host and client scripts to advertise sessions and discover nearby users with custom metadata.

Colocation Discovery allows users to advertise and discover nearby users via Bluetooth for seamless multi-user experiences. Using the OVRColocationSession API, hosts can broadcast up to 1024 bytes of session data (such as room names or IP addresses), while clients can discover and connect to available sessions in their proximity.
Use the Colocation building block for Colocation Discovery
Starting in v74, you can use the Colocation building block with the "Use Colocation Session" option enabled, which is based on the Colocation Discovery API. It handles all prerequisite setup as well as full end-to-end integration including matchmaking and alignment.

Prerequisites

Before proceeding with this tutorial, complete the setup steps outlined in the following sections:

Compatibility


Project Setup

1. Enable Colocation Discovery Feature

There are two ways to enable Colocation Discovery:
  1. In the Unity Editor Hierarchy, select your OVRCameraRig.
  2. In the Inspector, under OVRManager > Quest Features, enable Colocation Session Support.

Option B: Enable via Android Manifest

  1. Navigate to Meta > Tools and select Create store-compatible AndroidManifest.xml.
  2. Add the following permission to your Android manifest:
<uses-permission android:name="com.oculus.permission.USE_COLOCATION_DISCOVERY_API" android:required="true" />

2. Developer Authorization

For Colocation Discovery to work during development, one of the following must be true:

How Colocation Session Works

Colocation Session operates through two primary workflows:
  • Advertisement: Hosts broadcast their session with up to 1024 bytes of custom data (for example, room name, IP address).
  • Discovery: Clients scan for nearby advertised sessions and receive their unique ID and metadata.

Start Advertisement

A user can start advertising a colocation session with up to 1024 bytes of read-only data. Note that a host can only initiate one advertisement at a time.

Function Signature

public static OVRTask<OVRResult<Guid, Result>> StartAdvertisementAsync(ReadOnlySpan<byte> colocationSessionData)

Parameters

colocationSessionData is a read-only byte array that represents the data used in a colocation session.

Returns

StartAdvertisementAsync returns an awaitable task-like object that you can await on or use a callback by using ContinueWith. See Asynchronous Tasks for more details on task-based programming in the Meta XR Core SDK.
The task’s Result can be used to determine whether the share was successful, and what action should be taken if it fails.
The OVRResult’s Guid represents the advertisement UUID that was generated from calling StartAdvertisementAsync.

Practical Example

byte[] advertisementData = new byte[] {8, 12, 22};
var startAdvertisementResult = await OVRColocationSession.StartAdvertisementAsync(advertisementData);
if (startAdvertisementResult.Success)
{
    Debug.Log("StartAdvertisement was Successful!");
    var advertisementUUID = startAdvertisementResult.Value;
    Debug.Log($"Advertisement UUID is {advertisementUUID}");
}
else
{
    Debug.Log($"StartAdvertisement failed with error code {startAdvertisementResult.Status}");
}

Stop Advertisement

A user can stop their own existing advertisement of a colocation session.

Function Signature

public static OVRTask<OVRResult<Result>> StopAdvertisementAsync()

Returns

StopAdvertisementAsync returns an awaitable task-like object that you can await on or use a callback by using ContinueWith. See Asynchronous Tasks for more details on task-based programming in the Meta XR Core SDK.
The task’s Result can be used to determine whether the share was successful, and what action should be taken if it fails.

Practical Example

var result = await OVRColocationSession.StopAdvertisementAsync();
Debug.Log($"Finished getting result of StopAdvertisementAsync {result.Status}");

Start Discovery

A user can start discovering existing colocation session advertisements.

Function Signature

public static OVRTask<OVRResult<Result>> StartDiscoveryAsync()

Returns

StartDiscoveryAsync returns an awaitable task-like object that you can await on or use a callback by using ContinueWith. See Asynchronous Tasks for more details on task-based programming in the Meta XR Core SDK.
The task’s Result can be used to determine whether the share was successful, and what action should be taken if it fails.
Note: We recommend registering a callback when discovering a colocation session to add custom logic.
public static event Action<Data> ColocationSessionDiscovered;

Practical Example

private void OnColocationSessionDiscovered(OVRColocationSession.Data session)
{
    Debug.Log($"The advertisement UUID is: {session.AdvertisementUuid}");
    Debug.Log($"Data for session is {session.Metadata}");
}

OVRColocationSession.ColocationSessionDiscovered += OnColocationSessionDiscovered;

var startDiscoveryResult = await OVRColocationSession.StartDiscoveryAsync();
Debug.Log($"We finished awaiting StartDiscoveryAsync to finish status: {result.Status}");

Stop Discovery

A user can stop discovering existing colocation session advertisements.

Function Signature

public static OVRTask<OVRResult<Result>> StopDiscoveryAsync()

Returns

StopDiscoveryAsync returns an awaitable task-like object that you can await on or use a callback by using ContinueWith. See Asynchronous Tasks for more details on task-based programming in the Meta XR Core SDK.
The task’s Result can be used to determine whether the share was successful, and what action should be taken if it fails.

Practical Example

var stopDiscoveryResult = await OVRColocationSession.StopDiscoveryAsync();
Debug.Log($"Stopped Discovery Async result is {stopDiscoveryResult.Status}");

End to End Example using Colocation Sessions

This section demonstrates how a host can advertise their server via an IP Address and how a nearby client can connect to the host’s server.

Arbitrary User-Defined: ColocationSessionData and SerializationUtils

In this end to end example, arbitrary user-defined code is required to fully demonstrate how colocation sessions work.
  • ColocationSessionData is a struct used to define the data that will be passed from the host and client.
  • SerializationUtils is a class used to serialize to and from a generic to a byte array.
[System.Serializable]
public struct ColocationSessionData
{
    public string roomName;
    public string ipAddress;
}

public static class SerializationUtils
{
    public static byte[] SerializeToByteArray<T>(T obj)
        where T : new()
    {
        // NOTE: Using JSON as an intermediate protocol is fairly inefficient at runtime compared to a more direct
        // protocol, but it is safe, and the code is brief for the sake of this example.
        var json = JsonUtility.ToJson(obj, prettyPrint: false) ?? "{}";
        return s_Encoding.GetBytes(json);
    }

    public static T DeserializeFromByteArray<T>(byte[] data)
        where T : new()
    {
        var json = s_Encoding.GetString(data);
        return JsonUtility.FromJson<T>(json);
    }

    // UTF8 is best for serialization, and we want to omit the default BOM:
    static readonly Encoding s_Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
}

Example: How a Host uses Colocation Session

The host can advertise any data up to 1024 bytes.
public async void Example_Host_Flow()
{
    // Creates the data that will be advertised (Note: ColocationSessionData is a user-defined struct)
    var colocationSessionData = new ColocationSessionData()
    {
        roomName = "Lambo The Rabbit Room",
        ipAddress = "127.0.0.1"
    };

    // Note: SerializationUtils is a user-defined class
    var byteArrayData = SerializationUtils.SerializeToByteArray(colocationSessionData);

    // advertises a newly created session with the room name data
    var startAdvertisementResult = await OVRColocationSession.StartAdvertisementAsync(byteArrayData);
    if (startAdvertisementResult.Success)
    {
        Debug.Log($"Starting the Advertisement was successful with code: {startAdvertisementResult.Status.ToString()}");
    }
    else
    {
        Debug.LogError($"Starting the Advertisement failed with error code: {startAdvertisementResult.Status.ToString()}");
    }
}

Example: How a Client uses Colocation Session

The client can discover other colocation sessions nearby.
public async void Example_Discover_Flow()
{
    // registers a callback function for when we discover a colocation session
    OVRColocationSession.ColocationSessionDiscovered += OnColocationSessionDiscovered;

    // starts discovering session
    var startDiscoveryResult = await OVRColocationSession.StartDiscoveryAsync();
    if (startDiscoveryResult.Success)
    {
        Debug.Log($"Starting discovery was successful with code: {startDiscoveryResult.Status.ToString()}");
    }
    else
    {
        Debug.LogError($"Starting discovery failed with error code: {startDiscoveryResult.Status.ToString()}");
    }
}

// when a colocation session is discovered, OnColocationSessionDiscover will be invoked
private void OnColocationSessionDiscovered(OVRColocationSession.Data data)
{
    // deserializes the byte array into ColocationSessionData
    var colocationSessionData = SerializationUtils.DeserializeFromByteArray<ColocationSessionData>(data.Metadata);
    Debug.Log($"The room name is {colocationSessionData.roomName}");
    Debug.Log($"The IP Address is {colocationSessionData.ipAddress}");

    // at this point, having the ipAddress is enough data for the client to connect to the host's server
    // YourNetcodeUsed.Join(colocationSessionData.ipAddress);
}

Colocation Discovery Scene
A shared whiteboard scene demonstrating Colocation Discovery and anchor sharing between users. Features micro-gestures for moving and scaling the whiteboard using hands and controllers.
View on GitHub
Demonstrates the Space Sharing API to share room layouts between users. Includes a bouncing ball spawner where users can spawn balls that bounce off shared room meshes in the same physical space.
View on GitHub
Space Sharing Scene

Explore more Unity documentation topics for multiplayer, spatial anchors, and shared experiences.

Previous:Colocation Overview
Did you find this page helpful?