Minecraft 26.2 snapshot 7
Original ChangelogMinecraft now has a friends list and peer-to-peer!
Privacy Considerations
Adding a friend in Minecraft also adds them as a friend on Xbox, allowing them to see your Xbox profile. Make sure your Xbox profile does not contain any personal information before adding players you don’t trust as friends.
Since peer-to-peer connections attempt to use the most direct network path possible, Joining a friend’s world or letting a friend join your world may expose your IP address to them, even if normal traffic is routed through a VPN or proxy.
Potent Sulfur
Eruption and cooldown times of Geysers are now random based on the world seed and the position of the block.
To launch entities, geysers no longer require an entity’s eye position to have visual line of sight with the center of the geyser’s topmost water block.
To apply Nausea to a player in range, the player’s eyes must be in an air block directly above a water block, and the center of that water block must have collision line of sight (used to be visual line of sight) with the point one block below the player’s eyes.
Block Data
potent_sulfur_state can now be continuous.
Block Entity Data
Removed dormant_time and eruption_time.
Music Disc
“Bounce” plays for 3:54.
Bounce appears in chest minecarts that are opened in a Sulfur Cave biome, not just minecarts that generate in a Sulfur Cave biome. It is possible to move a minecart into a Sulfur Cave, then open it for a chance to get the music disc.
Chest minecarts opened in a Sulfur Cave biome contain their usual loot, with the Bounce music disc added to the pool containing rails and torches (3 rolls):
| Item | Weight | Chance |
|---|---|---|
| Rails | 20/60 | 70.370% |
| Torch | 15/60 | 57.812% |
| Music Disc (Bounce) | 10/60 | 42.130% |
| Activator Rail | 5/60 | 22.975% |
| Detector Rail | 5/60 | 22.975% |
| Powered Rail | 5/60 | 22.975% |
Friends List
If the Xbox account associated with your Microsoft account has friends, those friends will appear in the friends list. Adding a friend in Minecraft also adds them as a friend on Xbox.
Players that have their chat settings set to “Friends Only” in either Minecraft or Xbox settings must opt-in to the friends list before they can talk to existing friends, otherwise they will not be able to see anyone’s messages.
Invites to join your world expire after one minute.
Outgoing invites and presence (“Online”, “In a world”, etc…) are sent every 60 seconds, or every 10 seconds if the friends menu is open. Your presence is sent 10 seconds after the last update when:
- You open/close a world
- You publish/unpublish a server
- You disconnect from a server
- You send an invite to join your world
- You accept or decline an incoming invite
- An outgoing invite expires
Peer-to-Peer
Peer-to-peer uses the WebRTC protocol to connect two players through as direct a network path as possible. If two players cannot connect directly, all traffic is routed through Mojang’s relay servers.
Peer-to-peer traffic is encrypted. Even if traffic is routed through Mojang’s relay servers, Mojang cannot read its content.
Like a LAN server, worlds shared to friends are in online-mode. Unlike LAN servers, worlds shared to friends will not let players in if their username cannot be verified or if authentication servers cannot be reached.
Up to 8 players can play on the same published singleplayer world, whether they join through LAN or peer-to-peer. Mods can increase this limit.
Friends who attempt to join you world when the world has not been published online will be rejected. Non-friends will be ignored instead.
Splash Text
Added a new splash text: “Music by fingerspit!”
Data
The last_explosion_impact_pos entity NBT field was moved from all living entities to just players.
Debug Properties
Added two debug properties:
-DMC_DEBUG_DEBUG_CHAT_FRIENDS_ONLY[sic] - Acts as if chat is restricted to friends only.-DMC_DEBUG_NATIVE_WEBRTC_LOGS- Prints logs at theINFOlevel or above from the webrtc-java library.
Session API
All endpoints are located at `https://sessionserver.mojang.com.
GET /session/minecraft/profile/<uuid>
Response
action in profileActions was renamed to updateType.
Example:
{
...,
"profileActions": [
{
"updateType": "USING_BANNED_SKIN"
}
]
}
Minecraft Services API
All endpoints are located at https://api.minecraftservices.com and require an Authorization bearer token.
All endpoints may respond with the following HTTP codes when an error occurs:
- 400: Name or UUID does not exist
- 403: Access token is invalid
- 429: Too many requests
- 500: Service not available Other errors are treated as generic errors.
GET /player/attributes
Response
Added new fields:
friendsPreferences: Optionalfriends: Whether the friends list is enabled, eitherENABLEDorDISABLEDacceptInvites: Whether friend requests are allowed, eitherENABLEDorDISABLED
chatPreferences: OptionaltextCommunication: Whether chat is enabled, eitherENABLED,FRIENDS_ONLY, orDISABLED
Example:
{
...,
"friendsPreferences": {
"friends": "ENABLED",
"acceptInvites": "ENABLED"
},
"chatPreferences": {
"textCommunication": "ENABLED"
},
...
}
POST /player/attributes
Payload
Added new fields:
friendsPreferences: Optionalfriends: Whether the friends list is enabled, eitherENABLEDorDISABLEDacceptInvites: Whether friend requests are allowed, eitherENABLEDorDISABLED
Example:
{
...,
"friendsPreferences": {
"friends": "ENABLED",
"acceptInvites": "ENABLED"
}
}
Response
The POST /player/attributes response is the same as GET /player/attributes.
GET /friends
New endpoint added.
Response
friends: Current friend list- A friend request
profileId: The player’s in-game UUIDname: The player’s in-game username
- A friend request
incomingRequests: Incoming friend requests- A friend request
profileId: The player’s in-game UUIDname: The player’s in-game username
- A friend request
outgoingRequests: Outgoing friend requests- A friend request
profileId: The player’s in-game UUIDname: The player’s in-game username
- A friend request
empty: Optional, whether the friends list is empty
The response has an ETag header which can be used for caching.
Example:
{
"friends": [
{
"profileId": "f6489b79-7a9f-49e2-980e-265a05dbc3af",
"name": "Tis_awesomeness"
}
],
"incomingRequests": [],
"outgoingRequests": [],
"empty": false
}
PUT /friends
New endpoint added.
Payload
name: Optional, the player’s in-game usernameprofileId: Optional, the player’s in-game UUIDupdateType: EitherADDto send an outgoing friend request or accept an incoming friend request, orREMOVEto remove a friend, decline an incoming friend request, or revoke an outgoing friend request
Either name or profileId must be provided. If both are provided, profileId is used and name is ignored.
The response has an ETag header which can be used for caching.
Example:
{
"name": "jeb_",
"updateType": "ADD"
}
Response
The PUT /friends response is the same as GET /friends.
PUT /presence
New endpoint added.
Payload
status: One ofONLINE,PLAYING_OFFLINE,PLAYING_REALMS,PLAYING_SERVER,PLAYING_HOSTED_SERVER, orOFFLINEjoinInfo: Optionalvalue: String with unknown purpose, client always sendsnullinvites: Optional, list of invited players- In-game UUID of an invited player
Example:
{
"status": "PLAYING_SERVER",
"joinInfo": {
"value": null,
"invites": [
"f6489b79-7a9f-49e2-980e-265a05dbc3af"
]
}
}
Response
presence: List of presence statuses for each player in the friends list- A presence status
profileId: The player’s in-game UUIDpmid: The player’s PMID, a UUID with dashes used for peer-to-peer multiplayerstatus: One ofONLINE,PLAYING_OFFLINE,PLAYING_REALMS,PLAYING_SERVER,PLAYING_HOSTED_SERVER, orOFFLINEjoinInfo: Optionalvalue: Unused string with unknown purposeinvited: Whether the player has invited you to their world
lastUpdated: When presence was last updated
- A presence status
{
"presence": [
{
"profileId": "f6489b79-7a9f-49e2-980e-265a05dbc3af",
"pmid": "13280211-851c-4543-9448-89777f191702",
"status": "PLAYING_SERVER",
"joinInfo": {
"value": "13280211-851c-4543-9448-89777f191702",
"invited": true
},
"lastUpdated": "2026-05-20T04:42:00.139151764Z"
}
]
}
Signaling API
All endpoints are located at https://signaling-afd.franchise.minecraft-services.net.
GET /
Request
x-mojangauth: The Minecraft access tokenSession-Id: A random UUID generated once on startupRequest-Id: A random UUID generated for each request
Example:
x-mojangauth: <token>
Session-Id: 87c025a5-8ab5-4c07-8188-2057dabf7ed1
Request-Id: e4a43120-687a-4b13-97e7-d175b0f4aae2
Response
resultsignalingUri: A base URI to a Minecraft signaling serverpingFrequency: A time inhh:mm:ssformat, currently unused
Example:
{
"result": {
"signalingUri": "wss://signal-eastus2.franchise.minecraft-services.net"
}
}
Peer-to-Peer Protocol
Peer-to-peer uses WebRTC to connect two players to each other.
First, the client requests the signalingUri from the Signaling API. Then, it sends a GET request with the same headers to <signalingUri>/ws/v1.0/messaging/connect/java to open a websocket connection.
Signaling messages such as join requests are sent through the websocket using the JSON-RPC 2.0 protocol. Both clients use the signaling server to negotiate how best to connect to each other.
Ping
The client sends the websocket a ping every 50 seconds:
jsonrpc:2.0id: The numeric transaction ID as a string, incremented with each requestmethod:System_Ping_v1_0params: Empty list
Example:
{
"jsonrpc": "2.0",
"id": "1",
"method": "System_Ping_v1_0",
"params": []
}
The server will send back a pong, which the client ignores:
jsonrpc:2.0id: The numeric transaction ID as a string, incremented with each requestmethod:System_Pong_v1_0params: Empty list
Example:
{
"jsonrpc": "2.0",
"id": "1",
"method": "System_Pong_v1_0",
"params": []
}
Signaling Messages
Sending
Clients can send signaling messages to other players over the signaling websocket:
jsonrpc:2.0id: The numeric transaction ID as a string, incremented with each requestmethod:Signaling_SendClientMessage_v1_0params: A list with three parametersnull- The PMID of the player to send the message to
- The signal message JSON encoded as a string
Example:
{
"jsonrpc": "2.0",
"id": "1",
"method": "Signaling_SendClientMessage_v1_0",
"params": [
null,
"13280211-851c-4543-9448-89777f191702",
"{\"type\":\"JOIN_REQUEST\",\"sessionId\":\"87c025a5-8ab5-4c07-8188-2057dabf7ed1\"}"
]
}
If an error occurs, the websocket will return the following:
jsonrpc:2.0id: The same transaction IDerrorcode: The JSON-RPC error codemessage: The error message
Example:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32600,
"message": "Invalid Request"
}
}
Receiving
Clients also receive messages on the same websocket:
jsonrpc:2.0id: The numeric transaction ID as a string, incremented with each requestmethod:Signaling_ReceiveMessage_v1_0params: A list with one parameter- A message
From: The PMID of the player the message was sent fromMessage: The signal message JSON encoded as a stringId: Optional, UUID with unknown purpose, currently unused
- A message
Example:
{
"jsonrpc": "2.0",
"id": "1",
"method": "Signaling_ReceiveMessage_v1_0",
"params": [
{
"From": "13280211-851c-4543-9448-89777f191702",
"Message": "{\"type\":\"JOIN_REQUEST\",\"sessionId\":\"87c025a5-8ab5-4c07-8188-2057dabf7ed1\"}",
"Id": "e4a43120-687a-4b13-97e7-d175b0f4aae2"
}
]
}
Join Requests
Join requests and responses (and declined invites) are sent as signaling messages:
type: One ofJOIN_REQUEST,JOIN_ACCEPTED,JOIN_REJECTED, orINVITE_DECLINEDsessionId: The sameSession-Idsent to the Signaling API
Example:
{
"type": "JOIN_REQUEST",
"sessionId": "87c025a5-8ab5-4c07-8188-2057dabf7ed1"
}
When a host publishes a world online, either:
- The host sends an invite to a guest, who can send either a
JOIN_REQUESTto accept or anINVITE_DECLINEDto decline. - A guest sends a
JOIN_REQUESTto the host without receiving an invite.
When the host receives a JOIN_REQUEST:
- If the join request came from a friend and the host is hosting an online world, the host responds with
JOIN_ACCEPTED - If the join request came from a friend, but the host is not hosting an online world, the host responds with
JOIN_REJECTED - If the join request did not come from a friend, it is silently ignored
Request TURN Server
Once the host sends JOIN_ACCEPTED and the guest receives JOIN_ACCEPTED, both request TURN/STUN servers from Mojang over the signaling websocket. The TURN/STUN servers are later used for Interactive Connectivity Establishment.
jsonrpc:2.0id: The numeric transaction ID as a string, incremented with each requestmethod:Signaling_TurnAuth_v1_0params: Empty list
Example:
{
"jsonrpc": "2.0",
"id": "1",
"method": "Signaling_TurnAuth_v1_0",
"params": []
}
The websocket returns the following result:
jsonrpc:2.0id: The same transaction IDresultExpirationInSeconds: Time until the username/passwords expiresTurnAuthServers: A list of TURN auth servers- A TURN auth server
Username: Username used to authenticate to the TURN serverPassword: Password used to authenticate to the TURN serverUrls: List of TURN/STUN URLs- A TURN/STUN URL
- A TURN auth server
Example:
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"ExpirationInSeconds": 604799,
"TurnAuthServers": [
{
"Username": "...",
"Password": "...",
"Urls": [
"stun:relay.communication.microsoft.com:3478",
"turn:relay.communication.microsoft.com:3478"
]
}
]
}
}
Handshake
Once each client obtains the TURN servers, the WebRTC handshake begins. Both SDP offer/answer and ICE candidate messages are exchanged in parallel.
SDP Offer/Answer
The guest and host negotiates and agrees upon network parameters (such as for SCTP and DTLS) that allow a connection to be established and allow the guest and host to understand each other.
First, the guest sends the host an OFFER signaling message, containing network parameters in SDP format. Then, the host sends the guest an ANSWER in SDP format, which contains the network parameters that will be used for the connection.
type: One ofOFFERorANSWERsessionId: The sameSession-Idsent to the Signaling APIsdp: The SDP offer or answer
Example:
{
"type": "OFFER",
"sessionId": "87c025a5-8ab5-4c07-8188-2057dabf7ed1",
"sdp": "v=0\r\no=- ...\r\n"
}
ICE
Interactive Connectivity Establishment (ICE) is used to find ways the guest and host can communicate with each other as directly as possible. ICE is negotiated over exclusively UDP, over IPv4 or IPv6.
Both clients continually generate a set of ICE candidates: possible IP addresses and ports the clients can use to connect to each other:
- If both clients are on the same network, connecting directly is preferred.
- Each client reaches out to a STUN server received earlier, which replies with the client’s public address and whether or not the client is accessible behind its router’s NAT, if one exists.
- As a last resort, the TURN relay server allocates an IP and port the client can use to communicate with the other client. All traffic will be routed through the relay server.
Both clients send ICE candidate signaling messages to each other as they are discovered:
type:ICE_CANDIDATEsessionId: The sameSession-Idsent to the Signaling APIiceCandidatecandidate: The ICE candidate in SDP formatsdpMid: Optional, the SDP stream media ID, defaults to “0”sdpMLineIndex: The index (starting at 0) of the SDP media description the candidate is associated with
Example:
{
"type": "ICE_CANDIDATE",
"sessionId": "87c025a5-8ab5-4c07-8188-2057dabf7ed1",
"iceCandidate": {
"candidate": "candidate:842163049 1 udp 2122260223 192.0.2.1 49152 typ host",
"sdpMid": "0",
"sdpMLineIndex": 0
}
}
Each client pairs up sent and received ICE candidates, performing connectivity checks to ensure the other client can be reached. Finally, the guest nominates an ICE candidate pair, and both the guest and host begin the Minecraft protocol using those IP addresses and ports.
Handoff to Minecraft Protocol
Both the guest and the host perform the usual client-server handshake for an online mode server. However, since the connection is already encrypted with DTLS (as required by the WebRTC protocol), the symmetric key negotiated during the client-server handshake is not used to double-encrypt the connection.