Develop

Blocking

Updated: Jun 24, 2026
This is a Platform SDK feature requiring Data Use Checkup
To use this or any other Platform SDK feature, you must complete a Data Use Checkup (DUC). The DUC ensures that you comply with Developer Policies. It requires an administrator from your team to certify that your use of user data aligns with platform guidelines. Until the app review team reviews and approves your DUC, platform features are only available for test users.

Blocking and unblocking users

Blocking is a core safety feature which users expect in multiplayer games and social experiences. Through this platform feature, you, as a developer, can access who users have blocked and allow users to block directly from their app.
The user-block flow can be used to create new blocks with minimal disruption to the app experience. This is useful in a multiplayer or social setting where a user might encounter another player who is abusive. This flow allows you to prompt a user to block a specific other user, which they can choose to confirm or cancel. The user is then brought right back into your app. You can then access this block data to honor all their blocks in your app.
The blocking APIs are part of the horizon.platform.users package. Create an instance of Users to call them:
import horizon.platform.users.Users

val users = Users()
These APIs were added in Meta Horizon OS v85 (VR Platform SDK v0.2.1). Require this version in your AndroidManifest.xml (see Minimum OS versions) or handle error code 1003 (PROVIDER_OPERATION_NOT_SUPPORTED).

Launch the user block flow

suspend fun launchBlockFlow(userId: String): LaunchBlockFlowResult
Input: userId: The ID of the user that the viewer is going to launch the block flow request for.
This method deeplinks the viewer into a modal dialog targeting the specified user to be blocked. From the modal, the viewer can select Block to block the user and return to the app. Selecting Cancel returns the viewer to their app without any block action.
launchBlockFlow is a suspending function. Call it from a coroutine and wrap the call in a try/catch for UsersException.

Checking results

The returned LaunchBlockFlowResult reports the outcome of the viewer’s actions in the modal. See Example code 1 below for how to handle the result.
  • LaunchBlockFlowResult.didBlock is true if the viewer selected Block from the modal.
  • LaunchBlockFlowResult.didCancel is true if the viewer canceled or selected Back from the modal.
See Table 1 below for examples of how these values can be used.

Table 1: Block result feedback cases

SituationDescriptionResult feedback (LaunchBlockFlowResult)
Successful block
The user will view a dialog allowing them to Block or Cancel. The user selects Block and the block is executed successfully.
didBlock: true, didCancel: false
User cancel
The user will view a dialog allowing them to Block or Cancel. The user selects Cancel and returns the viewer to the app.
didBlock: false, didCancel: true
Viewer tries to block someone they blocked previously
The viewer receives a message informing them of the situation and asking whether they would like to unblock the target user. Selecting Back returns the viewer to their app.
didBlock: false, didCancel: true
Viewer tries to block themselves
The viewer receives a message indicating that this is not supported. Selecting Back returns the viewer to their app.
didBlock: false, didCancel: true
The block cannot be sent for some other reason.
The user receives the message “Unable to block. Please check your connection and try again.” Selecting Back returns the viewer to the app.
didBlock: false, didCancel: true

Launch the user unblock flow

suspend fun launchUnblockFlow(userId: String): LaunchUnblockFlowResult
Input: userId: The ID of the user that the viewer is going to launch the unblock flow request for.
This method deeplinks the viewer into a modal dialog targeting the specified user to be unblocked. From the modal, the viewer can select Unblock to unblock the user and return to the app. Selecting Cancel returns the viewer to their app without any unblock action.
launchUnblockFlow is a suspending function. Call it from a coroutine and wrap the call in a try/catch for UsersException.

Checking unblock results

The returned LaunchUnblockFlowResult reports the outcome of the viewer’s actions in the modal. See Example code 1 below for how to handle the result.
  • LaunchUnblockFlowResult.didUnblock is true if the viewer selected Unblock from the modal.
  • LaunchUnblockFlowResult.didCancel is true if the viewer canceled or selected Back from the modal.

Example code 1: Handling the block and unblock flows

import android.util.Log
import horizon.platform.users.Users
import horizon.platform.users.UsersException

suspend fun blockUser(users: Users, userId: String) {
  try {
    val result = users.launchBlockFlow(userId)
    Log.d(TAG, "Got result: didBlock = ${result.didBlock} didCancel = ${result.didCancel}")
  } catch (e: UsersException) {
    Log.e(TAG, "Error when trying to block the user: code ${e.code}", e)
  }
}

suspend fun unblockUser(users: Users, userId: String) {
  try {
    val result = users.launchUnblockFlow(userId)
    Log.d(TAG, "Got result: didUnblock = ${result.didUnblock} didCancel = ${result.didCancel}")
  } catch (e: UsersException) {
    Log.e(TAG, "Error when trying to unblock the user: code ${e.code}", e)
  }
}
Note: In these examples, TAG is your app’s logging tag (any String).

Retrieve a list of the user’s blocked users

To retrieve a list of the logged-in user’s blocked users, call Users.getBlockedUsers(coroutineScope). This returns the blocked user IDs who are also entitled to your app.
fun getBlockedUsers(coroutineScope: CoroutineScope): PagedResults<BlockedUser>
The results are returned as PagedResults<BlockedUser>. Call initialPage() to fetch the first page, then collect the pages flow to read each page; each BlockedUser exposes the blocked user’s id. See Example code 2 below for how to log the blocked user data.

Example code 2: Log blocked user IDs

import android.util.Log
import horizon.core.android.common.pagination.PageFetchException
import horizon.core.android.common.pagination.ext.initialPage
import horizon.core.android.common.pagination.ext.pages
import horizon.platform.users.Users
import horizon.platform.users.UsersException

suspend fun logBlockedUsers(users: Users, coroutineScope: CoroutineScope) {
  try {
    val pagedResults = users.getBlockedUsers(coroutineScope)
    pagedResults.initialPage()
    pagedResults.pages.collect { page ->
      for (blockedUser in page.contents) {
        Log.d(TAG, "Blocked User: ${blockedUser.id}")
      }
    }
  } catch (e: UsersException) {
    Log.e(TAG, "Could not get the list of blocked users: code ${e.code}", e)
  } catch (e: PageFetchException) {
    Log.e(TAG, "Could not fetch a page of blocked users", e)
  }
}