Breakout Rooms·续2

const response = await meeting.connectedMeetings.moveParticipantsWithCustomPreset(
  "SOURCE_MEETING_ID", // sourceMeetingId, meeting id where participants are currently in
  "TARGET_MEETING_ID", // targetMeetingId, meeting id where participants are to be moved
  [{ presetId: "PRESET_ID_1" }, { presetId: "PRESET_ID_2" }], // array of objects with presetId field
);

Move local participant to breakout room

To move the local participant to a different breakout room or back to the parent meeting, use the same API as for moving other participants, but pass the local participant's ID. The local participant must have the appropriate permissions: canSwitchConnectedMeetings to switch between breakout rooms, or canSwitchToParentMeeting to return to the parent meeting, if the request was originated by the non-host local participant.

Handle breakout room events

If a participant has been moved to a breakout room, the changingMeeting event is triggered, followed by the meetingChanged event. These events are also triggered when a participant switches between the main meeting and breakout rooms. Participants will autojoin the breakout room if they are assigned to it. You won't have to join meeting explicitly.

// Listen to changingMeeting event to show a custom UI to indicate that a meeting switch is happening
meeting.connectedMeetings.on("changingMeeting", (meetingId) => {
    console.log("Switching to breakout room or main meeting with id: " + meetingId);
    console.log("Show a Custom UI to indicate that a meeting switch is happening");
});

// Listen to meetingChanged event to update the meeting object reference
meeting.connectedMeetings.on("meetingChanged", (newMeeting) => {
    console.log("Switched to breakout room or main meeting");
    console.log("Every action now should be performed on this meeting");
});
// Listen to changingMeeting event to show a custom UI to indicate that a meeting switch is happening
meeting.connectedMeetings.on("changingMeeting", (meetingId) => {
    console.log("Switching to breakout room or main meeting with id: " + meetingId);
    console.log("Show a Custom UI to indicate that a meeting switch is happening");
});

// Listen to meetingChanged event to update the meeting object reference
meeting.connectedMeetings.on("meetingChanged", (newMeeting) => {
    console.log("Switched to breakout room or main meeting");
    console.log("Every action now should be performed on this meeting");
});
// Listen to changingMeeting event to show a custom UI to indicate that a meeting switch is happening
meeting.connectedMeetings.on("changingMeeting", (meetingId) => {
    console.log("Switching to breakout room or main meeting with id: " + meetingId);
    console.log("Show a Custom UI to indicate that a meeting switch is happening");
});

// Listen to meetingChanged event to update the meeting object reference
meeting.connectedMeetings.on("meetingChanged", (newMeeting) => {
    console.log("Switched to breakout room or main meeting");
    console.log("Every action now should be performed on this meeting");
});
meeting.addConnectedMeetingsEventListener(object : RtkConnectedMeetingsEventListener {
    // Triggered when a meeting switch is initiated — use this to show a loading UI
    override fun onChangingMeeting(meetingId: String) {
        println("Switching to breakout room or main meeting with id: $meetingId")
        println("Show a custom UI to indicate that a meeting switch is happening")
    }

// Triggered when the meeting switch is complete
    override fun onMeetingChanged(error: MeetingError?) {
        if (error != null) {
            println("Failed to switch meeting: $error")
        } else {
            println("Switched to breakout room or main meeting successfully")
        }
    }

override fun onStateUpdate(meetings: List<RtkConnectedMeeting>, parentMeeting: RtkConnectedMeeting?) {}
})
class MyListener: RtkConnectedMeetingsEventListener {
    // Triggered when a meeting switch is initiated — use this to show a loading UI
    func onChangingMeeting(meetingId: String) {
        print("Switching to breakout room or main meeting with id: \(meetingId)")
        print("Show a custom UI to indicate that a meeting switch is happening")
    }

// Triggered when the meeting switch is complete
    func onMeetingChanged(error: MeetingError?) {
        if let error = error {
            print("Failed to switch meeting: \(error)")
        } else {
            print("Switched to breakout room or main meeting successfully")
        }
    }

func onStateUpdate(meetings: [RtkConnectedMeeting], parentMeeting: RtkConnectedMeeting?) {}
}

meeting.addConnectedMeetingsEventListener(MyListener())

The useRealtimeKitClient hook automatically handles the meetingChanged event and swaps the active client reference when the local participant is moved to a breakout room or back to the main meeting. No additional setup is needed.

If you are using the RtkMeeting UI Kit component, the transition UI (the "Joining…" screen) is also handled automatically.

To show a custom loading screen during the switch, listen to the changingMeeting event:

useEffect(() => {
  if (!meeting) return;

const onChangingMeeting = (meetingId: string) => {
    console.log("Switching to meeting:", meetingId);
    // Show a loading indicator
  };

meeting.connectedMeetings.on("changingMeeting", onChangingMeeting);
  return () => meeting.connectedMeetings.removeListener("changingMeeting", onChangingMeeting);
}, [meeting]);

Close breakout rooms

You can close/delete the breakout rooms. This will force participants in those meetings to come to the main room.

await meeting.connectedMeetings.deleteMeetings([
  "MEETING_ID_TO_CLOSE_1",
  "MEETING_ID_TO_CLOSE_2",
]);

This would also trigger stateUpdate event updating the list of breakout rooms & participants.

meeting.connectedMeetings.on("stateUpdate", ({meetings, parentMeeting}) => {
  console.log("stateUpdate", {meetings, parentMeeting});
});

// Alternatively, you can access the meetings and parentMeeting from the connectedMeetings object
console.log("Meetings List", meeting.connectedMeetings.meetings);
console.log("Parent Meeting", meeting.connectedMeetings.parentMeeting);
await meeting.connectedMeetings.deleteMeetings([
  "MEETING_ID_TO_CLOSE_1",
  "MEETING_ID_TO_CLOSE_2",
]);

This would also trigger stateUpdate event updating the list of breakout rooms & participants.

meeting.connectedMeetings.on("stateUpdate", ({meetings, parentMeeting}) => {
  console.log("stateUpdate", {meetings, parentMeeting});
});

// Alternatively, you can access the meetings and parentMeeting from the connectedMeetings object
console.log("Meetings List", meeting.connectedMeetings.meetings);
console.log("Parent Meeting", meeting.connectedMeetings.parentMeeting);
await meeting.connectedMeetings.deleteMeetings([
  "MEETING_ID_TO_CLOSE_1",
  "MEETING_ID_TO_CLOSE_2",
]);

This would also trigger stateUpdate event updating the list of breakout rooms & participants.

meeting.connectedMeetings.on("stateUpdate", ({meetings, parentMeeting}) => {
  console.log("stateUpdate", {meetings, parentMeeting});
});

// Alternatively, you can access the meetings and parentMeeting from the connectedMeetings object
console.log("Meetings List", meeting.connectedMeetings.meetings);
console.log("Parent Meeting", meeting.connectedMeetings.parentMeeting);
meeting.connectedMeetings.deleteMeetings(
    meetingIds = listOf("MEETING_ID_TO_CLOSE_1", "MEETING_ID_TO_CLOSE_2")
) { error ->
    if (error != null) {
        println("Failed to close breakout rooms: $error")
    } else {
        println("Breakout rooms closed successfully")
    }
}

This will also trigger the onStateUpdate event, updating the list of breakout rooms and participants.

meeting.addConnectedMeetingsEventListener(object : RtkConnectedMeetingsEventListener {
    override fun onStateUpdate(meetings: List<RtkConnectedMeeting>, parentMeeting: RtkConnectedMeeting?) {
        println("State updated. Meetings: $meetings, Parent: $parentMeeting")

// Alternatively, access state directly from the connectedMeetings object
        println("Meetings List: ${meeting.connectedMeetings.meetings}")
        println("Parent Meeting: ${meeting.connectedMeetings.parentMeeting}")
    }

override fun onChangingMeeting(meetingId: String) {}
    override fun onMeetingChanged(error: MeetingError?) {}
})
meeting.connectedMeetings.deleteMeetings(meetingIds: ["MEETING_ID_TO_CLOSE_1", "MEETING_ID_TO_CLOSE_2"]) { error in
    if let error = error {
        print("Failed to close breakout rooms: \(error)")
    } else {
        print("Breakout rooms closed successfully")
    }
}

This will also trigger the onStateUpdate event, updating the list of breakout rooms and participants.

class MyListener: RtkConnectedMeetingsEventListener {
    func onStateUpdate(meetings: [RtkConnectedMeeting], parentMeeting: RtkConnectedMeeting?) {
        print("State updated. Meetings: \(meetings), Parent: \(String(describing: parentMeeting))")

// Alternatively, access state directly from the connectedMeetings object
        print("Meetings List: \(meeting.connectedMeetings.meetings)")
        print("Parent Meeting: \(String(describing: meeting.connectedMeetings.parentMeeting))")
    }

func onChangingMeeting(meetingId: String) {}
    func onMeetingChanged(error: MeetingError?) {}
}

meeting.addConnectedMeetingsEventListener(MyListener())
await meeting.connectedMeetings.deleteMeetings([
  "MEETING_ID_TO_CLOSE_1",
  "MEETING_ID_TO_CLOSE_2",
]);

This would also trigger stateUpdate event updating the list of breakout rooms & participants.

meeting.connectedMeetings.on("stateUpdate", ({meetings, parentMeeting}) => {
  console.log("stateUpdate", {meetings, parentMeeting});
});

// Alternatively, you can access the meetings and parentMeeting from the connectedMeetings object
console.log("Meetings List", meeting.connectedMeetings.meetings);
console.log("Parent Meeting", meeting.connectedMeetings.parentMeeting);

Next steps

You have successfully integrated breakout rooms into your RealtimeKit application. Participants can now:

  • Join the main meeting
  • Be assigned to breakout rooms by the host
  • Switch between the main meeting and breakout rooms
  • Collaborate in smaller focused groups

For more advanced customization, explore the following:

Was this helpful?

YesNo

On this page

Breakout Rooms·续2 - 图1Docs

{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/realtime/realtimekit/humans/core/breakout-rooms/#page","headline":"Breakout Rooms","description":"Create and manage breakout rooms to split participants into smaller groups in RealtimeKit.","url":"https://developers.cloudflare.com/realtime/realtimekit/humans/core/breakout-rooms/","inLanguage":"en","image":"https://developers.cloudflare.com/realtime/realtimekit/humans/core/breakout-rooms/og.png?v=2c58dd3ea3e8b2cb","dateModified":"2026-10-19","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}


description: Send and receive chat messages in RealtimeKit meetings using the Core SDK. title: Chat image: https://developers.cloudflare.com/realtime/realtimekit/humans/core/chat/og.png?v=a81cc23312bdf906


Skip to content

Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/realtime/llms.txt
Use this file to discover all available pages before exploring further.