Add Custom Header·续
RealtimeKit UI provides the RtkMeetingHeaderView component for a default header.
If you need additional controls, replace RtkMeetingHeaderView with individual UI Kit components and custom elements.
Import the required components:
import com.cloudflare.realtimekit.ui.view.headers.RtkMeetingHeaderView
import com.cloudflare.realtimekit.ui.view.RtkMeetingTitleView
import com.cloudflare.realtimekit.ui.view.RtkParticipantCountView
import com.cloudflare.realtimekit.ui.view.RtkClockView
import com.cloudflare.realtimekit.ui.view.RtkRecordingIndicator
import com.cloudflare.realtimekit.ui.view.RtkLivestreamIndicator
import com.cloudflare.realtimekit.ui.view.RtkGridPaginatorView
Create custom header layout
Create an XML layout file for your custom header:
layout/custom_header.xmlxml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingHorizontal="12dp"
android:background="@android:color/black">
<!-- Left section -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:gravity="start|center_vertical">
<com.cloudflare.realtimekit.ui.view.RtkRecordingIndicator
android:id="@+id/recordingIndicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.cloudflare.realtimekit.ui.view.RtkLivestreamIndicator
android:id="@+id/livestreamIndicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp" />
</LinearLayout>
<!-- Center section -->
<com.cloudflare.realtimekit.ui.view.RtkMeetingTitleView
android:id="@+id/meetingTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/white" />
<!-- Right section -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:gravity="end|center_vertical">
<com.cloudflare.realtimekit.ui.view.RtkGridPaginatorView
android:id="@+id/gridPaginator"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.cloudflare.realtimekit.ui.view.RtkParticipantCountView
android:id="@+id/participantCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp" />
<com.cloudflare.realtimekit.ui.view.RtkClockView
android:id="@+id/clock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp" />
<Button
android:id="@+id/reportBugButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="Report Bug"
android:textColor="@android:color/white"
android:background="@android:color/transparent"
style="?android:attr/borderlessButtonStyle" />
</LinearLayout>
</LinearLayout>
Create custom header view class
CustomHeaderView.ktkotlin
package com.example.meeting
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.widget.Button
import android.widget.LinearLayout
import com.cloudflare.realtimekit.ui.view.RtkClockView
import com.cloudflare.realtimekit.ui.view.RtkMeetingTitleView
import com.cloudflare.realtimekit.ui.view.RtkParticipantCountView
import com.cloudflare.realtimekit.ui.view.RtkRecordingIndicator
class CustomHeaderView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
init {
LayoutInflater.from(context).inflate(R.layout.custom_header, this, true)
setupReportBugButton()
}
private fun setupReportBugButton() {
findViewById<Button>(R.id.reportBugButton).setOnClickListener {
Log.d("CustomHeader", "Report Bug Clicked")
// Add your custom logic here
}
}
}
Use in your meeting activity
In your MeetingActivity, replace the default header with your custom header:
MeetingActivity.ktkotlin
package com.example.meeting
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.cloudflare.realtimekit.RealtimeKitClient
class MeetingActivity : AppCompatActivity() {
private lateinit var meeting: RealtimeKitClient
private lateinit var customHeader: CustomHeaderView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_meeting)
customHeader = findViewById(R.id.customHeader)
initializeMeeting()
}
private fun initializeMeeting() {
RealtimeKitClient.init(
authToken = "<PARTICIPANT_AUTH_TOKEN>",
onSuccess = { client ->
meeting = client
// Configure meeting UI
},
onError = { error ->
Log.e("Meeting", "Failed to initialize: $error")
}
)
}
}
RealtimeKit UI provides the RtkHeader component for a default header.
If you need additional controls, replace RtkHeader with individual UI Kit components and custom elements.
Import the required components:
import {
RtkLogo,
RtkRecordingIndicator,
RtkLiveStreamIndicator,
RtkMeetingTitle,
RtkGridPagination,
RtkParticipantCount,
RtkClock,
} from "@cloudflare/realtimekit-react-native-ui";
import {
useRealtimeKitMeeting,
useRealtimeKitSelector,
} from "@cloudflare/realtimekit-react-native";
Create custom header component
Create a custom header component that uses the RealtimeKit React Native components directly. Each component requires the meeting instance as a prop, which you obtain via the useRealtimeKitMeeting hook. The component waits for roomJoined before rendering to ensure the meeting state is ready:
CustomHeader.tsxtsx
import React from "react";
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";
import {
RtkLogo,
RtkRecordingIndicator,
RtkLiveStreamIndicator,
RtkMeetingTitle,
RtkGridPagination,
RtkParticipantCount,
RtkClock,
} from "@cloudflare/realtimekit-react-native-ui";
import {
useRealtimeKitMeeting,
useRealtimeKitSelector,
} from "@cloudflare/realtimekit-react-native";
interface CustomHeaderProps {
onReportBugPress?: () => void;
}
export function CustomHeader({ onReportBugPress }: CustomHeaderProps) {
const { meeting } = useRealtimeKitMeeting();
const { roomJoined } = useRealtimeKitSelector((state) => state.self);
const handleReportBugPress = () => {
console.log("Report Bug Pressed");
onReportBugPress?.();
};
if (!roomJoined) {
return null;
}
return (
<View style={styles.container}>
{/* Left section */}
<View style={styles.leftSection}>
<RtkLogo />
<RtkRecordingIndicator meeting={meeting} />
<RtkLiveStreamIndicator meeting={meeting} />
</View>
{/* Center section */}
<View style={styles.centerSection}>
<RtkMeetingTitle meeting={meeting} />
</View>
{/* Right section */}
<View style={styles.rightSection}>
<RtkGridPagination meeting={meeting} />
<RtkParticipantCount meeting={meeting} />
<RtkClock meeting={meeting} />
<TouchableOpacity
style={styles.reportBugButton}
onPress={handleReportBugPress}
>
<Text style={styles.reportBugText}>Report Bug</Text>
</TouchableOpacity>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
height: 48,
paddingHorizontal: 12,
backgroundColor: "black",
},
leftSection: {
flexDirection: "row",
alignItems: "center",
gap: 8,
},
centerSection: {
flexDirection: "row",
alignItems: "center",
},
rightSection: {
flexDirection: "row",
alignItems: "center",
gap: 8,
},
reportBugButton: {
borderWidth: 1,
borderColor: "white",
borderRadius: 4,
paddingHorizontal: 8,
paddingVertical: 4,
},
reportBugText: {
color: "white",
fontSize: 12,
},
});
Note
useRealtimeKitMeeting and useRealtimeKitSelector must be called inside a component rendered within a RealtimeKitProvider. The roomJoined guard ensures the header only renders once the participant has successfully joined the meeting. meeting.join() is called from the parent MeetingScreen so that the join lifecycle is managed in one place.
Use in your meeting screen
In your meeting screen, replace the default RtkHeader with your custom header:
MeetingScreen.tsxtsx
import React, { useEffect } from "react";
import { View, StyleSheet } from "react-native";
import {
RealtimeKitProvider,
useRealtimeKitClient,
} from "@cloudflare/realtimekit-react-native";
import {
RtkGrid,
RtkControlbar,
RtkDialogManager,
} from "@cloudflare/realtimekit-react-native-ui";
import { CustomHeader } from "./CustomHeader";
function MeetingContainer() {
const [meeting, initMeeting] = useRealtimeKitClient();
useEffect(() => {
initMeeting({
authToken: "<PARTICIPANT_AUTH_TOKEN>",
});
}, [initMeeting]);
useEffect(() => {
if (!meeting) return;
meeting.join();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [meeting]);
if (!meeting) {
return null;
}
return (
<RealtimeKitProvider value={meeting}>
<View style={styles.container}>
{/* Custom header replaces RtkHeader */}
<CustomHeader
onReportBugPress={() => console.log("Report bug pressed")}
/>
{/* Meeting grid */}
<View style={styles.gridContainer}>
<RtkGrid meeting={meeting} />
</View>
{/* Control bar */}
<RtkControlbar meeting={meeting} />
</View>
{/* Required components */}
<RtkDialogManager meeting={meeting} />
</RealtimeKitProvider>
);
}
export function MeetingScreen() {
return <MeetingContainer />;
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "black",
},
gridContainer: {
flex: 1,
},
});
Note
You must include RtkDialogManager. If you leave it out, features like settings toggles will not work.
Was this helpful?
YesNo
On this page
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/realtime/realtimekit/humans/ui-kit/custom-header/#page","headline":"Add Custom Header","description":"Add a custom header to your RealtimeKit meeting UI with individual components.","url":"https://developers.cloudflare.com/realtime/realtimekit/humans/ui-kit/custom-header/","inLanguage":"en","image":"https://developers.cloudflare.com/realtime/realtimekit/humans/ui-kit/custom-header/og.png?v=e73652b1d8137740","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: Customize text and localize the RealtimeKit UI Kit meeting interface for different languages. title: Meeting Locale image: https://developers.cloudflare.com/realtime/realtimekit/humans/ui-kit/meeting-locale/og.png?v=8f80148548031940
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.
Docs