# User channels (/en/realtime-media/rtm/build/work-with-channels/user-channel)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

<_PlatformTabsGroup groupMode="structured" canonicalPlatform="web" platforms="[&#x22;web&#x22;,&#x22;android&#x22;,&#x22;ios&#x22;,&#x22;macos&#x22;,&#x22;flutter&#x22;,&#x22;windows&#x22;,&#x22;linux-cpp&#x22;]" showTabs="true">
  <_PlatformPanel platform="web">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="web" />

    Signaling enables you to send direct, point-to-point messages to individual users through user channels. This feature is useful in one-on-one communication use-cases such as private chats and customer support interactions.

    ## Understand the tech [#understand-the-tech]

    To implement point-to-point communication between individual users in your app:

    1. **Set up the Signaling SDK**: [Integrate the Signaling SDK](/en/realtime-media/rtm/quickstart) in your app and [initialize an instance](/en/realtime-media/rtm/quickstart) of the Signaling client.
    2. **Authenticate the user**: [Log in to Signaling](/en/realtime-media/rtm/quickstart) using a unique user ID.
    3. **Send direct messages**: Call the `publish` method with the User channel type and specify the recipient's user ID as the channel name to send direct messages.
    4. **Handle incoming messages**: [Listen for message events](/en/realtime-media/rtm/quickstart) to receive messages sent directly to the local user.

    ## Prerequisites [#prerequisites]

    Ensure that you have:

    * Integrated the Signaling SDK in your project, and implemented the framework functionality from the [SDK quickstart](/en/realtime-media/rtm/quickstart).

    ## Implement user messages [#implement-user-messages]

    This section shows you how to use the Signaling SDK to send messages directly to a specified user.

    To send message to a user channel, call the `publish` method with the `channelType` parameter set to `USER` and the `channelName` parameter set to the target user's `userId`. This method enables you to send a message to one user at a time. To send messages to multiple users, call this method for each user. While Signaling does not limit the number of users you can send messages to or receive messages from, it does [limit](/en/realtime-media/rtm/reference/limitations) the frequency at which you can send messages to users.

    Refer to the following sample code for sending messages:

    **String message**

    ```js
    const payload = "Hello Agora!";
    const channelName = "Tony";
    const options = {
        customType: "PlainTxt",
        channelType: "USER",
    };
    try {
        const result = await rtm.publish(channelName, payload, options);
    } catch (status) {
        const { operation, reason, errorCode } = status;
        console.log(`${operation} failed, ErrorCode: ${errorCode}, due to: ${reason}.`);
    }
    ```

    **Binary message**

    ```js
    const message = "Hello Agora!";
    const payload = new TextEncoder().encode(message);
    const channelName = "Tony";
    const options = { customType:"ByteArray", channelType: "USER" }
    try {
        const result = await rtm.publish(channelName, payload, options);
    } catch (status) {
        const { operation, reason, errorCode } = status;
        console.log(`${operation} failed, ErrorCode: ${errorCode}, due to: ${reason}.`);
    }
    ```

    <CalloutContainer type="info">
      <CalloutDescription>
        Signaling currently supports only string and binary message formats. To send other types of data such as JSON objects, or data from third-party data construction tools such as protobuf, serialize the data before sending the message. For information on how to effectively construct the payload data structure and recommended serialization methods, refer to [Message payload structuring](/en/realtime-media/rtm/build/send-and-receive-messages/message-payload-structuring).
      </CalloutDescription>
    </CalloutContainer>

    ## Reference [#reference]

    This section contains content that completes the information on this page, or points you to documentation that explains other aspects to this product.

    ### API reference [#api-reference]

    * [`publish`](/en/api-reference/api-ref/signaling#messagepublishpropsag_platform)

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="android">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="android" />

    Signaling enables you to send direct, point-to-point messages to individual users through user channels. This feature is useful in one-on-one communication use-cases such as private chats and customer support interactions.

    ## Understand the tech [#understand-the-tech-1]

    To implement point-to-point communication between individual users in your app:

    1. **Set up the Signaling SDK**: [Integrate the Signaling SDK](/en/realtime-media/rtm/quickstart) in your app and [initialize an instance](/en/realtime-media/rtm/quickstart) of the Signaling client.
    2. **Authenticate the user**: [Log in to Signaling](/en/realtime-media/rtm/quickstart) using a unique user ID.
    3. **Send direct messages**: Call the `publish` method with the User channel type and specify the recipient's user ID as the channel name to send direct messages.
    4. **Handle incoming messages**: [Listen for message events](/en/realtime-media/rtm/quickstart) to receive messages sent directly to the local user.

    ## Prerequisites [#prerequisites-1]

    Ensure that you have:

    * Integrated the Signaling SDK in your project, and implemented the framework functionality from the [SDK quickstart](/en/realtime-media/rtm/quickstart).

    ## Implement user messages [#implement-user-messages-1]

    This section shows you how to use the Signaling SDK to send messages directly to a specified user.

    To send message to a user channel, call the `publish` method with the `channelType` parameter set to `RtmChannelType.USER` and the `channelName` parameter set to the target user's `userId`. This method enables you to send a message to one user at a time. To send messages to multiple users, call this method for each user. While Signaling does not limit the number of users you can send messages to or receive messages from, it does [limit](/en/realtime-media/rtm/reference/limitations) the frequency at which you can send messages to users.

    Refer to the following sample code for sending messages:

    **String message**

    <CodeBlockTabs defaultValue="Java">
      <CodeBlockTabsList>
        <CodeBlockTabsTrigger value="Java">
          Java
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="Kotlin">
          Kotlin
        </CodeBlockTabsTrigger>
      </CodeBlockTabsList>

      <CodeBlockTab value="Java">
        ```java  tabGroup="language"
        // Send string message
            PublishOptions options = new PublishOptions();
            options.setChannelType(RtmChannelType.USER);
            options.setCustomType("PlainText");
            rtmClient.publish("Tony", "Hello world", options, new ResultCallback<Void>() {
                @Override
                public void onSuccess(Void responseInfo) {
                    log(CALLBACK, "Send message success");
                }

                @Override
                public void onFailure(ErrorInfo errorInfo) {
                    log(ERROR, errorInfo.toString());
                }
            });
        ```
      </CodeBlockTab>

      <CodeBlockTab value="Kotlin">
        ```kotlin  tabGroup="language"
        // Send string message
            val options = PublishOptions()
            options.channelType = RtmChannelType.USER
            options.customType = "PlainText"
            rtmClient.publish("Tony", "Hello world", options, object : ResultCallback<Void> {
                override fun onSuccess(responseInfo: Void?) {
                    log(CALLBACK, "Send message success")
                }

                override fun onFailure(errorInfo: ErrorInfo) {
                    log(ERROR, errorInfo.toString())
                }
            })
        ```
      </CodeBlockTab>
    </CodeBlockTabs>

    **Binary message**

    <CodeBlockTabs defaultValue="Java">
      <CodeBlockTabsList>
        <CodeBlockTabsTrigger value="Java">
          Java
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="Kotlin">
          Kotlin
        </CodeBlockTabsTrigger>
      </CodeBlockTabsList>

      <CodeBlockTab value="Java">
        ```java  tabGroup="language"
        // Send binary message
            byte[] message = new byte[] {1, 2, 3, 4};
            PublishOptions options = new PublishOptions();
            options.setChannelType(RtmChannelType.USER);
            options.setCustomType("ByteArray");
            rtmClient.publish("Tony", message, options, new ResultCallback<Void>() {
                @Override
                public void onSuccess(Void responseInfo) {
                    log(CALLBACK, "Send message success");
                }

                @Override
                public void onFailure(ErrorInfo errorInfo) {
                    log(ERROR, errorInfo.toString());
                }
            });
        ```
      </CodeBlockTab>

      <CodeBlockTab value="Kotlin">
        ```kotlin  tabGroup="language"
        // Send binary message
            val message = byteArrayOf(1, 2, 3, 4)
            val options = PublishOptions()
            options.channelType = RtmChannelType.USER
            options.customType = "ByteArray"
            rtmClient.publish("Tony", message, options, object : ResultCallback<Void> {
                override fun onSuccess(responseInfo: Void?) {
                    log(CALLBACK, "Send message success")
                }

                override fun onFailure(errorInfo: ErrorInfo) {
                    log(ERROR, errorInfo.toString())
                }
            })
        ```
      </CodeBlockTab>
    </CodeBlockTabs>

    <CalloutContainer type="info">
      <CalloutDescription>
        Signaling currently supports only string and binary message formats. To send other types of data such as JSON objects, or data from third-party data construction tools such as protobuf, serialize the data before sending the message. For information on how to effectively construct the payload data structure and recommended serialization methods, refer to [Message payload structuring](/en/realtime-media/rtm/build/send-and-receive-messages/message-payload-structuring).
      </CalloutDescription>
    </CalloutContainer>

    ## Reference [#reference-1]

    This section contains content that completes the information on this page, or points you to documentation that explains other aspects to this product.

    ### Message packet size [#message-packet-size]

    Signaling SDK imposes 32 KB size limits on message payload packets sent in user channels. The message payload packet size includes the message payload itself plus the size of the `customType` field. If the message payload package size exceeds the limit, you receive the following error message.

    ```js
    ErrorInfo {
        errorCode = -11010;
        reason = "Publish too long message.";
        operation = "publishTopicMessage"; // or "publish"
    }
    ```

    To avoid sending failure due to excess message payload packet size, check the packet size before sending.

    ### API reference [#api-reference-1]

    * [`publish`](/en/api-reference/api-ref/signaling#messagepublishpropsag_platform)
    * [`receive`](/en/api-reference/api-ref/signaling#receive)

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="ios">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="ios" />

    Signaling enables you to send direct, point-to-point messages to individual users through user channels. This feature is useful in one-on-one communication use-cases such as private chats and customer support interactions.

    ## Understand the tech [#understand-the-tech-2]

    To implement point-to-point communication between individual users in your app:

    1. **Set up the Signaling SDK**: [Integrate the Signaling SDK](/en/realtime-media/rtm/quickstart) in your app and [initialize an instance](/en/realtime-media/rtm/quickstart) of the Signaling client.
    2. **Authenticate the user**: [Log in to Signaling](/en/realtime-media/rtm/quickstart) using a unique user ID.
    3. **Send direct messages**: Call the `publish` method with the User channel type and specify the recipient's user ID as the channel name to send direct messages.
    4. **Handle incoming messages**: [Listen for message events](/en/realtime-media/rtm/quickstart) to receive messages sent directly to the local user.

    ## Prerequisites [#prerequisites-2]

    Ensure that you have:

    * Integrated the Signaling SDK in your project, and implemented the framework functionality from the [SDK quickstart](/en/realtime-media/rtm/quickstart).

    ## Implement user messages [#implement-user-messages-2]

    This section shows you how to use the Signaling SDK to send messages directly to a specified user.

    In a user channel, you send a point-to-point message to a specified user by calling the `publish` method. Set the `channelType` parameter to `user` and the `channelName` parameter to the user ID of the specified user. This method enables you to send messages to one user at a time. While Signaling does not limit the number of users you can send messages to or receive messages from, it does [limit](/en/realtime-media/rtm/reference/limitations) the frequency at which you can send messages to users.

    Refer to the following sample code for sending messages:

    **String message**

    <CodeBlockTabs defaultValue="Swift">
      <CodeBlockTabsList>
        <CodeBlockTabsTrigger value="Swift">
          Swift
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="Objective-C">
          Objective-C
        </CodeBlockTabsTrigger>
      </CodeBlockTabsList>

      <CodeBlockTab value="Swift">
        ```swift  tabGroup="language"
        let message = "Hello Agora!"
            let user = "Tony"

            let publishOption = AgoraRtmPublishOptions()
            publishOption.channelType = .user

            rtm.publish(channelName: user, message: message, option: publishOption, completion: { res, error in
                if error != nil {
                    print("\(error?.operation) failed! error reason is \(error?.reason)")
                } else {
                    print("success")
                }
            })
        ```
      </CodeBlockTab>

      <CodeBlockTab value="Objective-C">
        ```objc  tabGroup="language"
        // Send string message
            NSString* message = @"Hello Agora!";
            NSString* user = @"Tony";

            AgoraRtmPublishOptions* publish_option = [[AgoraRtmPublishOptions alloc] init];
            publish_option.channelType = AgoraRtmChannelTypeUser;

            [rtm publish:user message:message option:publish_option completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
                if (errorInfo == nil) {
                    NSLog(@"publish success!!");
                } else {
                    NSLog(@"publish failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
                }
            }];
        ```
      </CodeBlockTab>
    </CodeBlockTabs>

    **Binary message**

    <CodeBlockTabs defaultValue="Swift">
      <CodeBlockTabsList>
        <CodeBlockTabsTrigger value="Swift">
          Swift
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="Objective-C">
          Objective-C
        </CodeBlockTabsTrigger>
      </CodeBlockTabsList>

      <CodeBlockTab value="Swift">
        ```swift  tabGroup="language"
        let bytes: [UInt8] = [ /* your raw values */ ]
            let rawMessage = Data(bytes: bytes, count: bytes.count)

            streamChannel.publish(channelName: user, data: rawMessage, option: nil) { response, errorInfo in
                if errorInfo == nil {
                    print("publish success!!")
                } else {
                    print("publish failed, errorCode \(errorInfo!.errorCode), reason \(errorInfo!.reason)")
                }
            }
        ```
      </CodeBlockTab>

      <CodeBlockTab value="Objective-C">
        ```objc  tabGroup="language"
        // Send string message
            NSString* message = @"Hello Agora!";
            NSString* user = @"Tony";

            AgoraRtmPublishOptions* publish_option = [[AgoraRtmPublishOptions alloc] init];
            publish_option.channelType = AgoraRtmChannelTypeUser;

            [rtm publish:user message:message option:publish_option completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
                if (errorInfo == nil) {
                    NSLog(@"publish success!!");
                } else {
                    NSLog(@"publish failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
                }
            }];
        ```
      </CodeBlockTab>
    </CodeBlockTabs>

    <CalloutContainer type="info">
      <CalloutDescription>
        Signaling currently supports only string and binary message formats. To send other types of data such as JSON objects, or data from third-party data construction tools such as protobuf, serialize the data before sending the message. For information on how to effectively construct the payload data structure and recommended serialization methods, refer to [Message payload structuring](/en/realtime-media/rtm/build/send-and-receive-messages/message-payload-structuring).
      </CalloutDescription>
    </CalloutContainer>

    ## Reference [#reference-2]

    This section contains content that completes the information on this page, or points you to documentation that explains other aspects to this product.

    ### Message packet size [#message-packet-size-1]

    Signaling SDK imposes 32 KB size limits on message payload packets sent in user channels. The message payload packet size includes the message payload itself plus the size of the `customType` field. If the message payload package size exceeds the limit, you receive the following error message.

    <CodeBlockTabs defaultValue="Swift">
      <CodeBlockTabsList>
        <CodeBlockTabsTrigger value="Swift">
          Swift
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="Objective-C">
          Objective-C
        </CodeBlockTabsTrigger>
      </CodeBlockTabsList>

      <CodeBlockTab value="Swift">
        ```objc  tabGroup="language"
        // errorInfo
        {
            errorInfo.errorCode = rrorCode = .channelMessageLengthExceedLimitation
            errorInfo.reason = "Publish too long message."
            errorInfo.operation = "publish"; // or "publishTopicMessage
        }
        ```
      </CodeBlockTab>

      <CodeBlockTab value="Objective-C">
        ```objc  tabGroup="language"
        // errorInfo
        {
            errorInfo.errorCode = AgoraRtmErrorChannelMessageLengthExceedLimitation;
            errorInfo.reason = @"Publish too long message.";
            errorInfo.Operation = @"publish"; // or "publishTopicMessage"
        }
        ```
      </CodeBlockTab>
    </CodeBlockTabs>

    To avoid sending failure due to excess message payload packet size, check the packet size before sending.

    ### API reference [#api-reference-2]

    **Swift**

    * [`publish`](/en/api-reference/api-ref/signaling?platform=objc\&tab=swift#messagepublishpropsag_platform)
    * [Receive](/en/api-reference/api-ref/signaling?platform=objc\&tab=swift#receive)

    **Objective-C**

    * [`publish`](/en/api-reference/api-ref/signaling?platform=ios\&tab=objc#messagepublishpropsag_platform)
    * [Receive](/en/api-reference/api-ref/signaling?platform=ios\&tab=objc#receive)

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="macos">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="macos" />

    Signaling enables you to send direct, point-to-point messages to individual users through user channels. This feature is useful in one-on-one communication use-cases such as private chats and customer support interactions.

    ## Understand the tech [#understand-the-tech-3]

    To implement point-to-point communication between individual users in your app:

    1. **Set up the Signaling SDK**: [Integrate the Signaling SDK](/en/realtime-media/rtm/quickstart) in your app and [initialize an instance](/en/realtime-media/rtm/quickstart) of the Signaling client.
    2. **Authenticate the user**: [Log in to Signaling](/en/realtime-media/rtm/quickstart) using a unique user ID.
    3. **Send direct messages**: Call the `publish` method with the User channel type and specify the recipient's user ID as the channel name to send direct messages.
    4. **Handle incoming messages**: [Listen for message events](/en/realtime-media/rtm/quickstart) to receive messages sent directly to the local user.

    ## Prerequisites [#prerequisites-3]

    Ensure that you have:

    * Integrated the Signaling SDK in your project, and implemented the framework functionality from the [SDK quickstart](/en/realtime-media/rtm/quickstart).

    ## Implement user messages [#implement-user-messages-3]

    This section shows you how to use the Signaling SDK to send messages directly to a specified user.

    In a user channel, you send a point-to-point message to a specified user by calling the `publish` method. Set the `channelType` parameter to `user` and the `channelName` parameter to the user ID of the specified user. This method enables you to send messages to one user at a time. While Signaling does not limit the number of users you can send messages to or receive messages from, it does [limit](/en/realtime-media/rtm/reference/limitations) the frequency at which you can send messages to users.

    Refer to the following sample code for sending messages:

    **String message**

    <CodeBlockTabs defaultValue="Swift">
      <CodeBlockTabsList>
        <CodeBlockTabsTrigger value="Swift">
          Swift
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="Objective-C">
          Objective-C
        </CodeBlockTabsTrigger>
      </CodeBlockTabsList>

      <CodeBlockTab value="Swift">
        ```swift  tabGroup="language"
        let message = "Hello Agora!"
            let user = "Tony"

            let publishOption = AgoraRtmPublishOptions()
            publishOption.channelType = .user

            rtm.publish(channelName: user, message: message, option: publishOption, completion: { res, error in
                if error != nil {
                    print("\(error?.operation) failed! error reason is \(error?.reason)")
                } else {
                    print("success")
                }
            })
        ```
      </CodeBlockTab>

      <CodeBlockTab value="Objective-C">
        ```objc  tabGroup="language"
        // Send string message
            NSString* message = @"Hello Agora!";
            NSString* user = @"Tony";

            AgoraRtmPublishOptions* publish_option = [[AgoraRtmPublishOptions alloc] init];
            publish_option.channelType = AgoraRtmChannelTypeUser;

            [rtm publish:user message:message option:publish_option completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
                if (errorInfo == nil) {
                    NSLog(@"publish success!!");
                } else {
                    NSLog(@"publish failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
                }
            }];
        ```
      </CodeBlockTab>
    </CodeBlockTabs>

    **Binary message**

    <CodeBlockTabs defaultValue="Swift">
      <CodeBlockTabsList>
        <CodeBlockTabsTrigger value="Swift">
          Swift
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="Objective-C">
          Objective-C
        </CodeBlockTabsTrigger>
      </CodeBlockTabsList>

      <CodeBlockTab value="Swift">
        ```swift  tabGroup="language"
        let bytes: [UInt8] = [ /* your raw values */ ]
            let rawMessage = Data(bytes: bytes, count: bytes.count)

            streamChannel.publish(channelName: user, data: rawMessage, option: nil) { response, errorInfo in
                if errorInfo == nil {
                    print("publish success!!")
                } else {
                    print("publish failed, errorCode \(errorInfo!.errorCode), reason \(errorInfo!.reason)")
                }
            }
        ```
      </CodeBlockTab>

      <CodeBlockTab value="Objective-C">
        ```objc  tabGroup="language"
        // Send string message
            NSString* message = @"Hello Agora!";
            NSString* user = @"Tony";

            AgoraRtmPublishOptions* publish_option = [[AgoraRtmPublishOptions alloc] init];
            publish_option.channelType = AgoraRtmChannelTypeUser;

            [rtm publish:user message:message option:publish_option completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
                if (errorInfo == nil) {
                    NSLog(@"publish success!!");
                } else {
                    NSLog(@"publish failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
                }
            }];
        ```
      </CodeBlockTab>
    </CodeBlockTabs>

    <CalloutContainer type="info">
      <CalloutDescription>
        Signaling currently supports only string and binary message formats. To send other types of data such as JSON objects, or data from third-party data construction tools such as protobuf, serialize the data before sending the message. For information on how to effectively construct the payload data structure and recommended serialization methods, refer to [Message payload structuring](/en/realtime-media/rtm/build/send-and-receive-messages/message-payload-structuring).
      </CalloutDescription>
    </CalloutContainer>

    ## Reference [#reference-3]

    This section contains content that completes the information on this page, or points you to documentation that explains other aspects to this product.

    ### Message packet size [#message-packet-size-2]

    Signaling SDK imposes 32 KB size limits on message payload packets sent in user channels. The message payload packet size includes the message payload itself plus the size of the `customType` field. If the message payload package size exceeds the limit, you receive the following error message.

    <CodeBlockTabs defaultValue="Swift">
      <CodeBlockTabsList>
        <CodeBlockTabsTrigger value="Swift">
          Swift
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="Objective-C">
          Objective-C
        </CodeBlockTabsTrigger>
      </CodeBlockTabsList>

      <CodeBlockTab value="Swift">
        ```objc  tabGroup="language"
        // errorInfo
        {
            errorInfo.errorCode = rrorCode = .channelMessageLengthExceedLimitation
            errorInfo.reason = "Publish too long message."
            errorInfo.operation = "publish"; // or "publishTopicMessage
        }
        ```
      </CodeBlockTab>

      <CodeBlockTab value="Objective-C">
        ```objc  tabGroup="language"
        // errorInfo
        {
            errorInfo.errorCode = AgoraRtmErrorChannelMessageLengthExceedLimitation;
            errorInfo.reason = @"Publish too long message.";
            errorInfo.Operation = @"publish"; // or "publishTopicMessage"
        }
        ```
      </CodeBlockTab>
    </CodeBlockTabs>

    To avoid sending failure due to excess message payload packet size, check the packet size before sending.

    ### API reference [#api-reference-3]

    **Swift**

    * [`publish`](/en/api-reference/api-ref/signaling?platform=objc\&tab=swift#messagepublishpropsag_platform)
    * [Receive](/en/api-reference/api-ref/signaling?platform=objc\&tab=swift#receive)

    **Objective-C**

    * [`publish`](/en/api-reference/api-ref/signaling?platform=ios\&tab=objc#messagepublishpropsag_platform)
    * [Receive](/en/api-reference/api-ref/signaling?platform=ios\&tab=objc#receive)

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="flutter">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="flutter" />

    Signaling enables you to send direct, point-to-point messages to individual users through user channels. This feature is useful in one-on-one communication use-cases such as private chats and customer support interactions.

    ## Understand the tech [#understand-the-tech-4]

    To implement point-to-point communication between individual users in your app:

    1. **Set up the Signaling SDK**: [Integrate the Signaling SDK](/en/realtime-media/rtm/quickstart) in your app and [initialize an instance](/en/realtime-media/rtm/quickstart) of the Signaling client.
    2. **Authenticate the user**: [Log in to Signaling](/en/realtime-media/rtm/quickstart) using a unique user ID.
    3. **Send direct messages**: Call the `publish` method with the User channel type and specify the recipient's user ID as the channel name to send direct messages.
    4. **Handle incoming messages**: [Listen for message events](/en/realtime-media/rtm/quickstart) to receive messages sent directly to the local user.

    ## Prerequisites [#prerequisites-4]

    Ensure that you have:

    * Integrated the Signaling SDK in your project, and implemented the framework functionality from the [SDK quickstart](/en/realtime-media/rtm/quickstart).

    ## Implement user messages [#implement-user-messages-4]

    This section shows you how to use the Signaling SDK to send messages directly to a specified user.

    To send message to a user channel, call the `publish` method with the `channelType` parameter set to `RtmChannelType.user` and the `channelName` parameter set to the target user's `userId`. This method enables you to send a message to one user at a time. To send messages to multiple users, call this method for each user. While Signaling does not limit the number of users you can send messages to or receive messages from, it does [limit](/en/realtime-media/rtm/reference/limitations) the frequency at which you can send messages to users.

    Refer to the following sample code for sending messages:

    **String message**

    ```dart
    final channelName = '"Tony"';
    var payload = 'Hello world';

    try {
        var (status, response) = await rtmClient.publish(
            channelName,
            payload,
            channelType: RtmChannelType.user,
            customType: 'PlainText');

        if (status.error == true ){
        print('${status.operation} failed, errorCode: ${status.errorCode}, due to ${status.reason}');
        } else {
            print('${status.operation} success!');
        }
    } catch (e) {
        print('something went wrong: $e');
    }
    ```

    **Binary message**

    ```dart
    final channelName = '"Tony"';
    var payload = Uint8List.fromList([155, 26, 88, 0, 0]);

    try {
        var (status, response) = await rtmClient.publishBinaryMessage(
            channelName,
            payload,
            channelType: RtmChannelType.user,
            customType: 'Uint8List');

        if (status.error == true ){
        print('${status.operation} failed, errorCode: ${status.errorCode}, due to ${status.reason}');
        } else {
            print('${status.operation} success!');
        }
    } catch (e) {
        print('something went wrong: $e');
    }
    ```

    <CalloutContainer type="info">
      <CalloutDescription>
        Signaling currently supports only string and binary message formats. To send other types of data such as JSON objects, or data from third-party data construction tools such as protobuf, serialize the data before sending the message. For information on how to effectively construct the payload data structure and recommended serialization methods, refer to [Message payload structuring](/en/realtime-media/rtm/build/send-and-receive-messages/message-payload-structuring).
      </CalloutDescription>
    </CalloutContainer>

    ## Reference [#reference-4]

    This section contains content that completes the information on this page, or points you to documentation that explains other aspects to this product.

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="windows">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="windows" />

    Signaling enables you to send direct, point-to-point messages to individual users through user channels. This feature is useful in one-on-one communication use-cases such as private chats and customer support interactions.

    ## Understand the tech [#understand-the-tech-5]

    To implement point-to-point communication between individual users in your app:

    1. **Set up the Signaling SDK**: [Integrate the Signaling SDK](/en/realtime-media/rtm/quickstart) in your app and [initialize an instance](/en/realtime-media/rtm/quickstart) of the Signaling client.
    2. **Authenticate the user**: [Log in to Signaling](/en/realtime-media/rtm/quickstart) using a unique user ID.
    3. **Send direct messages**: Call the `publish` method with the User channel type and specify the recipient's user ID as the channel name to send direct messages.
    4. **Handle incoming messages**: [Listen for message events](/en/realtime-media/rtm/quickstart) to receive messages sent directly to the local user.

    ## Prerequisites [#prerequisites-5]

    Ensure that you have:

    * Integrated the Signaling SDK in your project, and implemented the framework functionality from the [SDK quickstart](/en/realtime-media/rtm/quickstart).

    ## Implement user messages [#implement-user-messages-5]

    This section shows you how to use the Signaling SDK to send messages directly to a specified user.

    To send message to a user channel, call the `publish` method with the `channelType` parameter set to `RTM_CHANNEL_TYPE_USER` and the `channelName` parameter set to the target user's `userId`. This method enables you to send a message to one user at a time. To send messages to multiple users, call this method for each user. While Signaling does not limit the number of users you can send messages to or receive messages from, it does [limit](/en/realtime-media/rtm/reference/limitations) the frequency at which you can send messages to users.

    Refer to the following sample code for sending messages:

    **String message**

    ```cpp
    // Send string message
    std::string message = "Hello Agora!";
    PublishOptions options;
    options.messageType = RTM_MESSAGE_TYPE_STRING;
    options.customType = "PlainText";
    options.channelType = RTM_CHANNEL_TYPE_USER;

    uint64_t requestId;
    rtmClient->publish("Tony", message.c_str(), message.size(), options, requestId);
    ```

    **Binary message**

    ```cpp
    // Send binary message
    PublishOptions options;
    options.messageType = RTM_MESSAGE_TYPE_BINARY;
    options.customType = "ByteArray";
    options.channelType = RTM_CHANNEL_TYPE_USER;
    char message[5] = {0x00, 0x01, 0x02, 0x03, 0x04};

    uint64_t requestId;
    rtmClient->publish("Tony", message, 5, options, requestId);
    ```

    When you call this method, the SDK triggers the `onPublishResult` callback and returns the API call result.

    ```cpp
    // Asynchronous callback
    class RtmEventHandler : public IRtmEventHandler {
        void onPublishResult(const uint64_t requestId, RTM_ERROR_CODE errorCode) override {
            if (errorCode != RTM_ERROR_OK) {
                // publish message failed
            } else {
                // publish message success
            }
        }
    };
    ```

    <CalloutContainer type="info">
      <CalloutDescription>
        Signaling currently supports only string and binary message formats. To send other types of data such as JSON objects, or data from third-party data construction tools such as protobuf, serialize the data before sending the message. For information on how to effectively construct the payload data structure and recommended serialization methods, refer to [Message payload structuring](/en/realtime-media/rtm/build/send-and-receive-messages/message-payload-structuring).
      </CalloutDescription>
    </CalloutContainer>

    ## Reference [#reference-5]

    This section contains content that completes the information on this page, or points you to documentation that explains other aspects to this product.

    ### API reference [#api-reference-4]

    * [`publish`](/en/api-reference/api-ref/signaling#messagepublishpropsag_platform)

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="linux-cpp">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="linux-cpp" />

    Signaling enables you to send direct, point-to-point messages to individual users through user channels. This feature is useful in one-on-one communication use-cases such as private chats and customer support interactions.

    ## Understand the tech [#understand-the-tech-6]

    To implement point-to-point communication between individual users in your app:

    1. **Set up the Signaling SDK**: [Integrate the Signaling SDK](/en/realtime-media/rtm/quickstart) in your app and [initialize an instance](/en/realtime-media/rtm/quickstart) of the Signaling client.
    2. **Authenticate the user**: [Log in to Signaling](/en/realtime-media/rtm/quickstart) using a unique user ID.
    3. **Send direct messages**: Call the `publish` method with the User channel type and specify the recipient's user ID as the channel name to send direct messages.
    4. **Handle incoming messages**: [Listen for message events](/en/realtime-media/rtm/quickstart) to receive messages sent directly to the local user.

    ## Prerequisites [#prerequisites-6]

    Ensure that you have:

    * Integrated the Signaling SDK in your project, and implemented the framework functionality from the [SDK quickstart](/en/realtime-media/rtm/quickstart).

    ## Implement user messages [#implement-user-messages-6]

    This section shows you how to use the Signaling SDK to send messages directly to a specified user.

    To send message to a user channel, call the `publish` method with the `channelType` parameter set to `RTM_CHANNEL_TYPE_USER` and the `channelName` parameter set to the target user's `userId`. This method enables you to send a message to one user at a time. To send messages to multiple users, call this method for each user. While Signaling does not limit the number of users you can send messages to or receive messages from, it does [limit](/en/realtime-media/rtm/reference/limitations) the frequency at which you can send messages to users.

    Refer to the following sample code for sending messages:

    **String message**

    ```cpp
    // Send string message
    std::string message = "Hello Agora!";
    PublishOptions options;
    options.messageType = RTM_MESSAGE_TYPE_STRING;
    options.customType = "PlainText";
    options.channelType = RTM_CHANNEL_TYPE_USER;

    uint64_t requestId;
    rtmClient->publish("Tony", message.c_str(), message.size(), options, requestId);
    ```

    **Binary message**

    ```cpp
    // Send binary message
    PublishOptions options;
    options.messageType = RTM_MESSAGE_TYPE_BINARY;
    options.customType = "ByteArray";
    options.channelType = RTM_CHANNEL_TYPE_USER;
    char message[5] = {0x00, 0x01, 0x02, 0x03, 0x04};

    uint64_t requestId;
    rtmClient->publish("Tony", message, 5, options, requestId);
    ```

    When you call this method, the SDK triggers the `onPublishResult` callback and returns the API call result.

    ```cpp
    // Asynchronous callback
    class RtmEventHandler : public IRtmEventHandler {
        void onPublishResult(const uint64_t requestId, RTM_ERROR_CODE errorCode) override {
            if (errorCode != RTM_ERROR_OK) {
                // publish message failed
            } else {
                // publish message success
            }
        }
    };
    ```

    <CalloutContainer type="info">
      <CalloutDescription>
        Signaling currently supports only string and binary message formats. To send other types of data such as JSON objects, or data from third-party data construction tools such as protobuf, serialize the data before sending the message. For information on how to effectively construct the payload data structure and recommended serialization methods, refer to [Message payload structuring](/en/realtime-media/rtm/build/send-and-receive-messages/message-payload-structuring).
      </CalloutDescription>
    </CalloutContainer>

    ## Reference [#reference-6]

    This section contains content that completes the information on this page, or points you to documentation that explains other aspects to this product.

    ### API reference [#api-reference-5]

    * [`publish`](/en/api-reference/api-ref/signaling#messagepublishpropsag_platform)

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>
</_PlatformTabsGroup>
