Oculus Quest Development

All Oculus Quest developers MUST PASS the concept review prior to gaining publishing access to the Quest Store and additional resources. Submit a concept document for review as early in your Quest application development cycle as possible. For additional information and context, please see Submitting Your App to the Oculus Quest Store.

Destinations and Rich Presence

This article introduces three concepts: Destinations, Deep Linking and Rich Presence, which work together to enable you to build experiences that are more discoverable and social.

Destinations enable you to define deep-linkable locations, levels, or game modes within your app with rich media such as images and translated descriptions, and metadata such as player limits. The Oculus Store can display these destinations on your app store page and on the parties page as recommended activities, and can aggregate users’ presence. Each destination will have an associated URL, which you can use to share new levels or game modes via social media.
The goal of destinations is enable you to create meetup places within an app that you can easily transport users to.

The Rich Presence API enables you to update the Oculus platform with a user’s current destination and status, whether they are joinable, and additional context that can help their friends know whether they can be joined in a social experience.

Whenever a user launches your app to join someone, or navigates to a destination, the Oculus Platform provides a deep-link message with this context, enabling you to take them to the right person or place in your app.

Using Destinations, Rich Presence and Deep Linking, you transport users to a specific destination, where they can play solo or join another user, or users can launch your app to the same destination for a shared social experience.

User Experience

When users opt to share their Rich Presence, their friends can see whether they are in an app and looking for a match, playing a specific map, or participating in an event. Users control their online presence with an Activity privacy setting. A user can see a friend’s status, opt to join them, and be transported to the same destination as their friend.

For example, imagine a scenario where you add a new map to your game. With rich presence, destinations and deep linking:

  • A user can see their friend is playing the new map and launch your app to the new map to join their friend.
  • A user can see marketing for the new map and direct launch the app directly to the new map destination.
  • Two friends can group launch into your app at the same time to the new map destination and play together.

Implementation Overview

To implement Rich Presence, you define one or more Destinations for your app or app grouping that you can then deep link to. A destination is a social gathering place within your app, which might be represented by a matchmaking pool, room multiplayer server or specific configuration of an activity.

Your app code sets destinations for users, which they can opt to share as their online presence with friends or with anyone.

When users opt to either join another user via their rich presence, or launch directly to a specific destination, deep linking is used to launch the app. You provide app code to check the launch status and transport the user to the correct destination.

Destinations can be configured to provide the most relevant context based on the user’s activity and whether they are joinable. For example, a destination can help users looking for a match in 1v1 game or provide a hub to direct users to an app lobby.

In summary, the steps to implement Rich Presence are:

  1. Create one or more destinations on the developer dashboard
  2. Implement code to enable users to share a destination as their status
  3. Parse the app deep-linking URI to direct users to a specific destination

Step 1 - Create a Destination in the Developer Dashboard

The first step to implement rich presence is to create a destination on the developer dashboard.

  1. Find your app or app grouping and then navigate to Platform Services > Destinations.
  2. On the Destinations page, choose Create Destination.
  3. In the Edit Destination page, enter:

    • Api Name - The name you will use in your code when referencing the destination. Can contain alphanumeric and underscore ( _ ) characters. Cannot contain spaces or other special characters.
    • Deeplink Message - A message that you will parse in order to navigate a user to the right place in your app. It can be formatted how you want, but must not contain any spaces. A Deeplink Message is used along with the Api Name to construct a deep link URI.

      Note: A specific deep link URL should always take users to the same destination.

    • Supports Direct Deep Linking - (Enabled by default) Leave enabled if this destination can be launched without a specific user being present at the destination, and your app correctly routes users to this destination. For example, deep linking a lobby destination should take a user to the lobby of the app. In addition, if enabled, the destination can be featured in the Oculus app based on its relevance or popularity. Do not enable if the app cannot resolve a deep link to this destination, or if you do not want the destination to be featured. For example, a private room destination that allows friends to join one another, and shouldn’t be promoted, should not have Direct Deep Linking enabled.
    • Minimum Supported Group Launch (Optional): For a group launch, the minimum number of users required to launch together.
    • Maximum Supported Group Launch (Optional): Required for a group launch. Specifies the maximum number of users that can launch together. If you set this value, the app will shown as a recommendation for user events and coordinated app launches for Oculus Parties.
  4. In the Localizations section click the Modify Languages button to add languages and localized names for each language. The default is the default language you choose for the app on the Translations section of the Submit Your App page.
    • Choose a Language category, and enter:
      • A localized Display Name for that language. This name is used for display purposes, such as in a user’s status.
      • A localized Description for that language. This field is also used for display purposes.

    Repeat for each language you have entered.

  5. Finally, optionally enter the following:

    • Image - An image that represents your destination. The image must be a 2560 x 1440 PNG in 16x9 aspect ratio and 24 or 32 bit-depth. The image may be cropped, so you should leave whitespace around the edges.
  6. When finished, click Submit.

The following image shows an example of the Edit Destination page.

Create Destination dialog

Manage and Share Destinations

  • You can edit or retrieve a sharable URL for your destinations by accessing the by context menu for a destination. To do so:
    1. Find your app, and navigate to Platform Services > Destinations.
    2. Find the destination you want to share or edit and click the ellipses (...) in the far right column.
    3. Choose Go to Destination to visit the destination and retrieve the URL from the address bar of your browser to share the destination in social media and marketing materials. This URL will be in the format: https://oculus.com/vr/?id=[someId].
    4. Choose View/Edit to view and edit the fields for this destination, or choose Delete to delete it.

    The following image shows an example.

    edit destination

  • You can also associate a destination with a leaderboard.

Step 2 - Set the Presence for a User In-App

You define rich presence details for a user in your app by creating a RichPresenceOptions, a struct with several fields that describe a destination. The Oculus platform uses this information to display a status for the user.

The RichPresenceOptions struct has the following functions to set its fields:

  • SetApiName - Sets the api_name you specified for a destination in the developer dashboard.
  • SetCurrentCapacity - Sets the current capacity at that destination.
  • SetMaxCapacity - Sets the maximum capacity of the destination. Can be used with current capacity to see if a user can join. For example, when used with a room, set the max capacity of the destination to the max capacity of the room.
  • SetIsJoinable - Sets a boolean to indicate whether the destination is joinable. You can check the current capacity against the max capacity to determine whether the room is joinable.
  • SetDeeplinkMessageOverride - Sets an optional message to override the deep-link message set in the developer dashboard. This is where you can specify the ID for a room, party, matchmaking pool or group server.
  • SetStartTime - Sets the time the current match starts or started.
  • SetEndTime - Sets the time the current match ends.
  • SetExtraContext - Sets extra information to set the user’s presence correctly.

As the user moves through your app, you can set their presence to destinations as they are applicable.

When To Mark a User as Joinable

Marking a user as joinable depends on the app you are trying to build. Following are a few examples of when to make a user joinable:

  • If a user is in an activity that enables drop-in gameplay, and there are available spaces
  • If a user is in a public lobby or matchmaking queue
  • If the user is in a room or private lobby, where their friends can launch the app to join them
  • When the user is in the main menu of an app that uses simple matchmaking, or a simple invite mechanism. In this case the user should not be in practice or solo mode.

Joinable, Extra Context and User Status

The following table shows how marking a user as joinable and providing extra context can affect the user’s status.

RichPresenceOptions and resultSample Status Displayed
  • is_joinable: true
  • ExtraContext: ovrRichPresenceExtraContext_Looking_For_Match
Status uses the value of is_joinable.
looking for match
  • is_joinable: true
  • ExtraContext: ovrRichPresenceExtraContext_CurrentCapacity
Status displays the results of comparing current_capacity to max_capacity.
capacity
  • is_joinable: true
  • end_time: 3 mins from now
  • ExtraContext: ovrRichPresenceExtraContext_EndingIn
Status displays the time remaining until end_time.
looking for match
  • is_joinable: true
  • start_time: 2 min ago
  • ExtraContext: ovrRichPresenceExtraContext_StartedAgo
Status displays the time elapsed since start_time.
looking for match

Once you’ve added a destination and set a user’s rich presence, the final step is to check for a deep link URI, which is passed in an application lifecycle update message, and navigate the user to the right place in your app.

  • Check for the Platform.ApplicationLifecycle.SetLaunchIntentChangedNotificationCallback, which is sent when a launch intent is received for both cold and warm starts.
  • Use the ApplicationLifecyle_GetLaunchDetails() method and check the LaunchType.
  • If the app LaunchType is Deeplink, parse the LaunchDetails_DeeplinkMessage, Api_Name, UsersOptional, and RoomID fields, as follows:
ScenarioExample FieldsExample Action
Join a User: In headset, a user taps Go To on another user from the Friends List, Party panel, or Home feed."destination_api_name": "level3",
"deeplink_message":"deeplink message from the user's presence",
"users": [{"id":"123456789","alias":"otherUser"}]
Navigate this user to where the otherUser is at level3.
Direct Launch: Level 5 shows up in popular destinations based on a large number of people. A user accesses the destination from a deep link URL and remotely launches the app."destination_api_name":"level5",
"deeplink_message": "your deeplink to the destination",
"users": []
Launch the user into level5.
Group Launch: A party of 2 users choose Boss Level from a list of possible places and both users tap Launch."destination_api_name": "bossLevel",
"deeplink_message": "your deeplink to the destination",
"room_id":"12345",
"users": [{"id":"123456789","alias":"user1Joining"}, {"id":"67891234","alias":"user2Joining"}]
Create a room with the server API, and then launch the users into the same instance of boss_level using the room_id from the server call and the client Join2 method.

Test Deeplink with adb

You can launch your app with a deep-link payload for testing purposes using the Android Adb tool with the shell command. An example command:

$ adb shell am start -n com.company.appname/com.your.activity -e intent_cmd '''{\"ovr_social_launch\":{\"type\":\"DEEPLINK\",\"destination_api_name\": \"api_name\",\"room_id\": \"1337\",\"deeplink_message\":\"yourdeeplink\",\"users\":[{\"id\":\"123456789\",\"alias\":\"janedoe1234\"},{\"id\":\"12355555555\",\"alias\":\"johndoe5678\"}]}}'''

Note that:

  • Quotes in the JSON are escaped with a backslash (\)
  • Spaces in the deeplink message will cause errors
  • Your exact command format could vary depending on your development platform and command shell

You retrieve the destination_api_name and users along with deeplink_message from LaunchDetails to help you launch users to the correct destination.

For more information about using the adb shell to start an activity, see the activity manager section of Android Debug Bridge (adb) in the Android documentation.

Test Destinations, Rich Presence and Deep Linking on Oculus Quest

The following sections list some the implementation scenarios and how you might test these on an Oculus Quest device.

#1. Join a User based on their Rich Presence

  • Users A and B should be in a party
  • Navigate User A to a joinable destination
  • With User B, open the lightweight party panel. User A should be shown with a Go To button
  • Tap this button to trigger an app launch
  • Verify the app is correctly putting User B into the same instance or room ID as User A.

#2. Direct Launch to a specific destination

  • Find your app or app grouping and then navigate to Platform Services > Destinations.
  • Click the ellipses (...) button for a specific destination and select View/Edit Destination
  • From the Edit Destination page enable the Supports Direct Deep Linking toggle and save the destination.
  • From the Destinations list, click the ellipses (...) button and select Go To Destination. A new browser tab will open.
  • Preview your destination in the browser including the image, title and description
  • You will be able to see all of the Quest devices on which you’ve installed the app. Click ‘launch’ and you’ll be prompted to put on your headset.
  • Put on your headset, your app will launch.
  • Verify the app is correctly launching to the destination, with the desired behavior. For example, make sure the user is added to a matchmaking queue, if this is a matchmaking destination.

#3. Group Launch

  • Group Launch is not currently available for Oculus Rift or Oculus Quest.
  • You can test Group Launch using the ADB method.
  • Ensure that your app is capable of handling race conditions if two users both launch the app at the same time, expecting to be paired with one another at a destination.

Best Practices for Destinations, Rich Presence and Deep Linking

Following are some best practices and things to consider when you incorporate destinations and rich presence in your apps.

  • Create meaningful destinations that users will be interested in. You want to create destinations that other users want to join.
  • If you get a destination, in-app, and you don’t know how to handle it:
    • Show a message that recommends the user update the app. It is possible they do not have that destination in their version.
    • Notify the user that you cannot connect the user to the destination and offer an alternative.
    • Land the user in in a joinable state if you can’t join them with another user. In other words, if a new user is trying to join an existing user at a destination, but the existing user is no longer joinable, make the new user joinable at the same destination by putting them in joinable single-player mode or in a waiting room for the game mode they were trying to join.
  • Provide UI to join users in-app. The Rich Presence API enables you to query the presence status of party members, friends and recently met users who are in your app. This makes it easy to show someone a UI to easily reconnect with their group, when they next become available.
  • Even if your app is social (joinable) in only one destination, you can create multiple destinations for your app, and mark these additional destinations as non-joinable. For these destinations, use one of the ExtraContext fields such as EndingIn to report additional details. This can help lead to social experiences. For example, a user could see that their friend has just a few minutes left in their solo game, and decide to launch the same game.
  • Finally, try to create opportunities when things don’t go as planned. For example, if a group of people wants to join a game mode destination that requires 6 to play, and for some reason only 5 people join, you still to enable the group to play together. You could move the group to a different game mode or put them into a matchmaking queue for an additional person.