ConnectyCube Chat (messaging) API is built on top of Real-time(XMPP) protocol. In order to use it you need to setup real-time connection with ConnectyCube Chat server and use it to exchange data.
By default Real-time Chat works over secure TLS connection.
Get started with SDK
Follow the Getting Started guide on how to connect ConnectyCube SDK and start building your first app.
Code samples
There are ready-to-go FREE code samples to help you better understand how to integrate messaging capabilities in your apps:
TextChat code sample, Swift request
Connect to chat
let user = ConnectycubeUser ()
user. password = " password "
ConnectyCube (). chat . login ( user : user, successCallback :{
}, errorCallback : { error in
}, resource : ConnectycubeSettings () . chatDefaultResource )
[CYBChat.instance connectWithUserID:2746 password:@"password" completion:^(NSError * _Nullable error) {
Chat. instance . connect ( withUserID : 2746 , password : " password " ) { (error) in
Use CYBChatDelegate
v1 or ConnectycubeConnectionListener
v2 to handle different connection states:
class YourClass : NSObject {
ConnectyCube (). chat . addConnectionListener ( listener : self )
extension YourClass : ConnectycubeConnectionListener {
@interface YourClass () <CYBChatDelegate>
@implementation YourClass
[CYBChat.instance addDelegate:self];
- (void)chatDidReconnect {
- (void)chatDidDisconnectWithError:(NSError *)error {
- (void)chatDidNotConnectWithError:(NSError *)error {
- (void)chatDidFailWithStreamError:(NSError *)error {
class YourClass : NSObject {
Chat. instance . addDelegate ( self )
extension YourClass : ChatDelegate {
func chatDidReconnect () {
func chatDidDisconnectWithError ( _ error : Error ) {
func chatDidNotConnectWithError ( _ error : Error ) {
Connect to chat using custom authentication providers
In some cases we don’t have a user’s password, for example when login via:
Facebook
Twitter
Firebase phone authorization
Custom identity authentication
etc.
In such cases ConnectyCube API provides possibility to use ConnectyCube session token as a password for chat connection:
let user = ConnectycubeUser ()
user. password = ConnectycubeSessionManager (). getToken ()
ConnectyCube (). chat . login ( user : user, successCallback :{
}, errorCallback : { error in
}, resource : ConnectycubeSettings () . chatDefaultResource )
NSString *token = CYBSession.currentSession.sessionDetails.token;
[CYBChat.instance connectWithUserID:2746 password:token completion:^(NSError * _Nullable error) {
String token = Session. currentSession . sessionDetails . token
Chat. instance . connect ( withUserID : 2746 , password : token ) { (error) in
Disconnect
ConnectyCube (). chat . logout ( successCallback : {
[CYBChat.instance disconnectWithCompletionBlock:^(NSError * _Nullable error) {
Chat. instance . disconnect { (error) in
Reconnection
SDK reconnects automatically when connection to Chat server is lost.
There is a way to disable it and then manage it manually:
CYBSettings.autoReconnectEnabled = NO;
Settings. autoReconnectEnabled = false
Chat in background
As iOS doesn’t provide ‘true’ background mode, we can’t have a persistent Chat connection while iOS application is in the background.
The better way to handle chat offline messages correctly is to do:
Chat disconnect
when an app goes to background and do Chat connect
when an app goes to the foreground.
class AppDelegate: UIResponder , UIApplicationDelegate {
func applicationWillTerminate ( _ application : UIApplication ) {
ConnectyCube (). chat . logout ( successCallback : {
func applicationDidEnterBackground ( \ _ application : UIApplication ) {
ConnectyCube (). chat . logout ( successCallback : {
func applicationWillEnterForeground ( \ _ application : UIApplication ) {
ConnectyCube (). chat . login ( user : user, successCallback :{
}, errorCallback : { error in
}, resource : ConnectycubeSettings () . chatDefaultResource )
@implementation AppDelegate
- (void)applicationWillTerminate:(UIApplication *)application {
[CYBChat.instance disconnectWithCompletionBlock:^(NSError * _Nullable error) {
- (void)applicationDidEnterBackground:(UIApplication *)application {
[CYBChat.instance disconnectWithCompletionBlock:^(NSError * _Nullable error) {
- (void)applicationWillEnterForeground:(UIApplication *)application {
[CYBChat.instance connectWithUserID:2746 password:@"password" completion:^(NSError * _Nullable error) {
class AppDelegate: UIResponder , UIApplicationDelegate {
func applicationWillTerminate ( _ application : UIApplication ) {
Chat. instance . disconnect { (error) in
func applicationDidEnterBackground ( _ application : UIApplication ) {
Chat. instance . disconnect { (error) in
func applicationWillEnterForeground ( _ application : UIApplication ) {
Chat. instance . connect ( withUserID : 2746 , password : " password " ) { (error) in
Dialogs
All chats between users are organized in dialogs. The are 4 types of chat dialogs:
1-1 chat - a conversation between 2 users.
group chat - a conversation between specified list of users.
public group chat - an open conversation. Any user from your app can subscribe to it.
broadcast - chat where a message is sent to all users within application at once.
All the users from the application are able to join this group. Broadcast dialogs can be created only via Admin panel.
You need to create a new dialog and then use it to chat with other users. You also can obtain a list of your existing dialogs.
Create new dialog
Create 1-1 chat
let dialog = ConnectycubeDialog ()
dialog. type = ConnectycubeDialogType. companion . PRIVATE
dialog. occupantsIds = [ 34 ] // an ID of opponent
ConnectyCube (). createDialog ( connectycubeDialog : dialog, successCallback : {(dialog) in
CYBChatDialog *dialog = [[CYBChatDialog alloc] initWithDialogID:nil type:CYBChatDialogTypePrivate];
dialog.occupantIDs = @[@34]; // an ID of opponent
[CYBRequest createDialog:dialog successBlock:^(CYBChatDialog * _Nonnull dialog) {
} errorBlock:^(NSError * _Nonnull error) {
let dialog = ChatDialog ( dialogID : nil, type : . private )
dialog. occupantIDs = [ 34 ] // an ID of opponent
Request. createDialog ( dialog, successBlock : { (dialog) in
Create group chat
let dialog = ConnectycubeDialog ()
dialog. type = ConnectycubeDialogType. companion . GROUP
dialog. name = " New group dialog "
dialog. occupantsIds = [ 34 , 45 , 55 ]
//dialog.dialogDescription = "..."
ConnectyCube (). createDialog ( connectycubeDialog : dialog, successCallback : {(dialog) in
CYBChatDialog *dialog = [[CYBChatDialog alloc] initWithDialogID:nil type:CYBChatDialogTypeGroup];
dialog.name = @"Group dialog name";
dialog.occupantIDs = @[@34, @45, @55];
// dialog.photo = @"...";
// dialog.dialogDescription = @"...";
[CYBRequest createDialog:dialog successBlock:^(CYBChatDialog * _Nonnull dialog) {
} errorBlock:^(NSError * _Nonnull error) {
let dialog = ChatDialog ( dialogID : nil, type : . group )
dialog. name = " New group dialog "
dialog. occupantIDs = [ 34 , 45 , 55 ]
// dialog.dialogDescription = "...";
Request. createDialog ( dialog, successBlock : { (dialog) in
Create public chat
It’s possible to create a public chat, so any user from your application can subscribe to it.
let dialog = ConnectycubeDialog ()
dialog. type = ConnectycubeDialogType. companion . PUBLIC
dialog. name = " Public dialog name "
dialog. dialogDescription = " Public dialog description "
ConnectyCube (). createDialog ( connectycubeDialog : dialog, successCallback : {(dialog) in
CYBChatDialog *dialog = [[CYBChatDialog alloc] initWithDialogID:nil type:CYBChatDialogTypePublic];
dialog.name = @"Public dialog name";
dialog.dialogDescription = @"Public dialog description";
// dialog.photo = @"...";
[CYBRequest createDialog:dialog successBlock:^(CYBChatDialog * _Nonnull dialog) {
} errorBlock:^(NSError * _Nonnull error) {
let dialog = ChatDialog ( dialogID : nil, type : . public )
dialog. name = " Public dialog name "
dialog. dialogDescription = " Public dialog description "
Request. createDialog ( dialog, successBlock : { (dialog) in
With public dialog ID any user can subscribe to the public dialog via the following code:
ConnectyCube (). subscribeToDialog ( dialogId : " 5b8d30d1ca8bf43f8b9df3d9 " , successCallback : {(dialog) in
[CYBRequest subscribeToPublicDialogWithID:@"5b8d30d1ca8bf43f8b9df3d9" successBlock:^{
} errorBlock:^(NSError *error) {
Request. subscribeToPublicDialog ( withID : " 5b8d30d1ca8bf43f8b9df3d9 " , successBlock : {
After dialog subscription, this dialog will be listed in retrieve dialogs request and you also will be able to chat in it.
You also can unsubscribe if you do not want to be in this public dialog anymore:
ConnectyCube (). unsubscribeFromDialog ( dialogId : " 5b8d30d1ca8bf43f8b9df3d9 " , successCallback : {
[CYBRequest ubsubscribeFromPublicDialogWithID:@"5b8d30d1ca8bf43f8b9df3d9" successBlock:^{
} errorBlock:^(NSError *error) {
Request. ubsubscribeFromPublicDialog ( withID : " 5b8d30d1ca8bf43f8b9df3d9 " , successBlock : {
Retrieve list of dialogs
It’s common to request all your conversations on every app login:
let params = [ " limit " : 50 , " skip " : 100 ]
ConnectyCube (). getDialogs ( params : params, successCallback : { result in
let dialogs: [ConnectycubeDialog] = result. items as! [ConnectycubeDialog]
}, errorCallback : { error in
[CYBRequest dialogsWithPaginator:[CYBPaginator limit:50 skip:100]
successBlock:^(NSArray<CYBChatDialog *> * _Nonnull dialogs, NSSet<NSNumber *> * _Nonnull dialogsUsersIDs, CYBPaginator * _Nonnull paginator) {
} errorBlock:^(NSError * _Nonnull error) {
Request. dialogs ( with : Paginator. limit ( 50 , skip : 100 ) ,
successBlock : { (dialogs, usersIDs, paginator) in
It will return all your 1-1 dialogs, group dialog and also public dialogs your are subscribed to.
Update dialog’s name, description, photo
User can update group chat name, description, photo:
let paramsToUpdate = UpdateDialogParams ()
paramsToUpdate. newName = " New dialog name "
paramsToUpdate. newDescription = " New dialog description "
paramsToUpdate. newPhoto = " https://new_photo_url " // or it can be an ID to some file in Storage module
let parameters = paramsToUpdate. getUpdateDialogParams () as! [ String : Any ]
ConnectyCube (). updateDialog ( dialogId : " 5356c64ab35c12bd3b108a41 " , params : parameters, successCallback : { dialog in
}, errorCallback : { error in
CYBUpdateChatDialogParameters *parameters = [[CYBUpdateChatDialogParameters alloc] init];
parameters.name = @"New dialog name";
parameters.dialogDescription = @"New dialog description";
parameters.photo = @"https://new_photo_url"; // or it can be an ID to some file in Storage module
[CYBRequest updateDialogWithID:@"5356c64ab35c12bd3b108a41" updateParameters:parameters successBlock:^(CYBChatDialog * _Nonnull dialog) {
} errorBlock:^(NSError * _Nonnull error) {
let parameters = UpdateChatDialogParameters ()
parameters. name = " New dialog name "
parameters. dialogDescription = " New dialog description "
parameters. photo = " https://new_photo_url " // or it can be an ID to some file in Storage module
Request. updateDialog ( withID : " 5356c64ab35c12bd3b108a41 " , update : parameters, successBlock : { (updatedDialog) in
Add/Remove occupants
You can add/remove occupants in group and public dialogs:
let paramsToUpdate = UpdateDialogParams ()
paramsToUpdate. addOccupantIds = [ 10056 , 75432 ]
//paramsToUpdate.deleteOccupantIds = [10023]
let parameters = paramsToUpdate. getUpdateDialogParams () as! [ String : Any ]
ConnectyCube (). updateDialog ( dialogId : " 5356c64ab35c12bd3b108a41 " , params : parameters, successCallback : { dialog in
}, errorCallback : { error in
CYBUpdateChatDialogParameters *parameters = [[CYBUpdateChatDialogParameters alloc] init];
parameters.occupantsIDsToAdd = @[@10056, @75432];
//parameters.occupantsIDsToRemove = @[@10023];
[CYBRequest updateDialogWithID:@"5356c64ab35c12bd3b108a41" updateParameters:parameters successBlock:^(CYBChatDialog *dialog) {
} errorBlock:^(NSError * _Nonnull error) {
let updateParameters = UpdateChatDialogParameters ()
updateParameters. occupantsIDsToAdd = [ 10056 , 75432 ]
//updateParameters.occupantsIDsToRemove = [10023]
Request. updateDialog ( withID : " 5356c64ab35c12bd3b108a41 " , update : updateParameters, successBlock : { (updatedDialog) in
!> Important note: Only group chat owner and admins can remove other users from group chat.
Add/Remove admins
Admins it’s a special role in chats.
They have the same permissions as a dialog’s creator except add/remove other admins and remove dialog.
Owner of the group chat dialog can add admins:
ConnectyCube (). addRemoveAdmins ( dialogId : " 5356c64ab35c12bd3b108a41 " , toAddIds : [ 10056 , 75432 ], toRemoveIds : nil, successCallback : { dialog in
}, errorCallback : { error in
[CYBRequest addAdminsToDialogWithID:@"5356c64ab35c12bd3b108a41" adminsUserIDs:@[@10056, @75432] successBlock:^{
} errorBlock:^(NSError * _Nonnull error) {
Request. addAdminsToDialog ( withID : " 5356c64ab35c12bd3b108a41 " , adminsUserIDs : [ 10056 , 75432 ], successBlock : {
and remove:
ConnectyCube (). addRemoveAdmins ( dialogId : " 5356c64ab35c12bd3b108a41 " , toAddIds : nil, toRemoveIds : [ 75435 ], successCallback : { dialog in
}, errorCallback : { error in
[CYBRequest removeAdminsFromDialogWithID:@"5356c64ab35c12bd3b108a41" adminsUserIDs:@[@75435] successBlock:^{
} errorBlock:^(NSError * _Nonnull error) {
Request. removeAdminsFromDialog ( withID : " 5356c64ab35c12bd3b108a41 " , adminsUserIDs : [ 75435 ], successBlock : {
Pin messages
Pinning a message allows group owner or chat admins to easily store messages which are important, so that all users in chat have a quick access to them. The following code pins some messages to a particular group dialog:
let paramsToUpdate = UpdateDialogParams ()
paramsToUpdate. addPinnedMsgIds = [ " 5356c64ab35c12bd3b10ba32 " , " 5356c64ab35c12bd3b10wa65 " ]
//paramsToUpdate.deletePinnedMsgIds = ["5356c64ab35c12bd3b10ba31", "5356c64ab35c12bd3b10wa64"]
let parameters = paramsToUpdate. getUpdateDialogParams () as! [ String : Any ]
ConnectyCube (). updateDialog ( dialogId : " 5356c64ab35c12bd3b108a41 " , params : parameters, successCallback : { dialog in
}, errorCallback : { error in
CYBUpdateChatDialogParameters *parameters = [[CYBUpdateChatDialogParameters alloc] init];
parameters.pinnedMessagesIDsToAdd = @[@"5356c64ab35c12bd3b10ba32", @"5356c64ab35c12bd3b10wa65"];
//parameters.pinnedMessagesIDsToRemove = @[@"5356c64ab35c12bd3b10ba31", @"5356c64ab35c12bd3b10wa64"];
[CYBRequest updateDialogWithID:@"5356c64ab35c12bd3b108a41" updateParameters:parameters successBlock:^(CYBChatDialog * _Nonnull dialog) {
} errorBlock:^(NSError * _Nonnull error) {
let updateParameters = UpdateChatDialogParameters ()
updateParameters. pinnedMessagesIDsToAdd = [ " 5356c64ab35c12bd3b10ba32 " , " 5356c64ab35c12bd3b10wa65 " ]
//updateParameters.pinnedMessagesIDsToRemove = ["5356c64ab35c12bd3b10ba31", "5356c64ab35c12bd3b10wa64"]
Request. updateDialog ( withID : " 5356c64ab35c12bd3b108a41 " , update : updateParameters, successBlock : { (updatedDialog) in
Remove dialog
ConnectyCube (). deleteDialogs ( dialogsIds : [ " 5356c64ab35c12bd3b108a41 " , " d256c64ab35c12bd3b108bc5 " ], force : false , successCallback : {(result) in
ConnectyCube (). deleteDialog ( dialogId : " 5356c64ab35c12bd3b108a41 " , force : false , successCallback : {
[CYBRequest deleteDialogsWithIDs:[NSSet setWithArray:@[@"5356c64ab35c12bd3b108a41", @"d256c64ab35c12bd3b108bc5"]]
successBlock:^(NSArray<NSString *> * _Nonnull deletedObjectsIDs,
NSArray<NSString *> * _Nonnull notFoundObjectsIDs,
NSArray<NSString *> * _Nonnull wrongPermissionsObjectsIDs) {
} errorBlock:^(NSError * _Nonnull error) {
Request. deleteDialogs ( withIDs : Set < String > ( [ " 5356c64ab35c12bd3b108a41 " , " d256c64ab35c12bd3b108bc5 " ] ) ,
successBlock : { (deletedObjectsIDs, notFoundObjectsIDs, wrongPermissionsObjectsIDs) in
This request will remove this conversation for current user, but other users still will be able to chat there. The forAllUsers
or force
parameter is used to completely remove the dialog. Only group chat owner can remove the group conversation for all users.
You can also delete multiple conversations in a single request.
Chat history
Every chat conversation stores its chat history which you can retrieve:
let params: GetMessagesParameters = GetMessagesParameters ()
params. sorter = RequestSorter ( fieldType : " 1455098137 " , fieldName : " date_sent " , sortType : " gt " )
let parameters = params. getRequestParameters () as! [ String : Any ]
ConnectyCube (). getMessages ( dialogId : " 5356c64ab35c12bd3b108a41 " , params : parameters, successCallback : { result in
let messages = result. items as! [ConnectycubeMessage]
}, errorCallback : { error in
[CYBRequest messagesWithDialogID:@"5356c64ab35c12bd3b108a41"
extendedRequest:@{@"date_sent[gt]" : @"1455098137"}
paginator:[CYBPaginator limit:20 skip:0]
successBlock:^(NSArray<CYBChatMessage *> * _Nonnull messages, CYBPaginator * _Nonnull paginator) {
} errorBlock:^(NSError * _Nonnull error) {
Request . messages ( withDialogID : " 5356c64ab35c12bd3b108a41 " ,
extendedRequest : [ " date_sent[gt] " : " 1455098137 " ],
paginator : Paginator. limit ( 20 , skip : 0 ) ,
successBlock : { (messages, paginator) in
!> Important note: All retrieved chat messages will be marked as read after the request. If you decide not to mark chat messages as read, then add the following parameter to your extendedRequest - @{@"mark_as_read" : @"0"};
or markAsRead = false
Send/Receive chat messages
1-1 Chat
let message = ConnectycubeMessage ()
message. body = " How are you today? "
message. dialogId = " 5356c64ab35c12bd3b108a41 "
message. recipientId = 10056
ConnectyCube (). chat . sendMessage ( msg : message, successCallback : {
//MARK: ConnectycubeMessageListener
ConnectyCube (). chat . addMessageListener ( listener : self )
extension YourClass: ConnectycubeMessageListener {
func onMessage ( message : ConnectycubeMessage ) {
func onError ( message : ConnectycubeMessage, ex : KotlinThrowable ) {
CYBChatMessage *message = [[CYBChatMessage alloc] init];
message.text = @"How are you today?";
CYBChatDialog *privateDialog = ...;
[privateDialog sendMessage:message completionBlock:^(NSError * _Nullable error) {
- (void)chatDidReceiveMessage:(CYBChatMessage *)message {
let message = ChatMessage ()
message.text = " How are you today? "
privateDialog. send ( message ) { (error) in
func chatDidReceive ( _ message : ChatMessage ) {
Group/Public chat
Before you start chatting in a group/public conversation, you need to join it. When joined - you can send/receive messages in a real time.
//not supported, no need to join
CYBChatDialog *groupDialog = ...;
[groupDialog joinWithCompletionBlock:^(NSError * _Nullable error) {
groupDialog. join { (error) in
Then you are able to send/receive messages:
let message = ConnectycubeMessage ()
message. body = " How are you today? "
message. dialogId = " 5356c64ab35c12bd3b108a41 "
message. type = ConnectycubeMessageType. groupchat
ConnectyCube (). chat . sendMessage ( msg : message, successCallback : {
//MARK: ConnectycubeMessageListener
ConnectyCube (). chat . addMessageListener ( listener : self )
extension YourClass: ConnectycubeMessageListener {
func onMessage ( message : ConnectycubeMessage ) {
func onError ( message : ConnectycubeMessage, ex : KotlinThrowable ) {
CYBChatMessage *message = [[CYBChatMessage alloc] init];
message.text = @"How are you today?";
CYBChatDialog *groupDialog = ...;
[groupDialog sendMessage:message completionBlock:^(NSError * _Nullable error) {
- (void)chatRoomDidReceiveMessage:(CYBChatMessage *)message fromDialogID:(NSString *)dialogID {
let message = ChatMessage ()
message.text = " How are you today? "
groupDialog. send ( message ) { (error) in
func chatRoomDidReceive ( _ message : ChatMessage, fromDialogID dialogID : String ) {
When it’s done, you can leave the group conversation:
//not supported, no need to leave
CYBChatDialog *groupDialog = ...;
[groupDialog leaveWithCompletionBlock:^(NSError * _Nullable error) {
groupDialog. leave { (error) in
‘Sent’ status
There is a ‘sent’ status to ensure that message is delivered to the server.
The completionBlock
is used to track the status:
//MARK: ConnectycubeMessageSentListener
ConnectyCube (). chat . addMessageSentListener ( listener : self )
extension YourClass: ConnectycubeMessageSentListener {
func onMessageSent ( message : ConnectycubeMessage ) {
func onMessageSentFailed ( message : ConnectycubeMessage ) {
CYBChatDialog *chatDialog = ...;
[chatDialog sendMessage:message completionBlock:^(NSError * _Nullable error) {
chatDialog. send ( message ) { (error) in
‘Delivered’ status
By default, SDK sends ‘delivered’ status automatically when the message is received by the recipient. This is controlled by message.markable
parameter when you send a message.
let message = ConnectycubeMessage ()
message. recipientId = 10056
message. body = " How are you today? "
ConnectyCube (). chat . sendMessage ( msg : message, successCallback : {
CYBChatMessage *message = [CYBChatMessage new];
message.text = @"How are you today?";
[chatDialog sendMessage:message completionBlock:^(NSError * _Nullable error) {
let message = ChatMessage ()
message.text = " How are you today? "
chatDialog. send ( message ) { (error) in
If markable is false or omitted, you can send ‘delivered’ status manually via Chat
:
ConnectyCube (). chat . sendDeliveredStatus ( msg : message, successCallback : {
[CYBChat.instance markAsDelivered:message completion:^(NSError * _Nullable error) {
Chat. instance . mark ( asDelivered : message ) { (error) in
and via REST
let updatedParams = UpdateMessageParameters ()
updatedParams. delivered = true
ConnectyCube (). updateMessage ( messageId : " 5b23aa4f5d0b0be0900041aa " , dialogId : " 5b23a9f38b518248d4fd7625 " , params : updatedParams. getRequestParameters () , successCallback : {
[CYBRequest markMessagesAsDelivered:[NSSet setWithArray:@[@"5b23aa4f5d0b0be0900041aa"]]
dialogID:@"5b23a9f38b518248d4fd7625"
} errorBlock:^(NSError * _Nonnull error) {
Request. markMessages ( asDelivered : Set < String > ( [ " 5b23aa4f5d0b0be0900041aa " ] ) ,
dialogID : " 5b23a9f38b518248d4fd7625 " , successBlock : {
The following method of a delegate is used to track ‘delivered’ status:
//MARK: ConnectycubeMessageStatusListener
ConnectyCube (). chat . addMessageStatusListener ( listener : self )
extension YourClass: ConnectycubeMessageStatusListener {
func onMessageDelivered ( messageId : String , dialogId : String , userId : Int32 ) {
func onMessageRead ( messageId : String , dialogId : String , userId : Int32 ) {
[CYBChat.instance addDelegate:self];
- (void)chatDidDeliverMessageWithID:(NSString *)messageID dialogID:(NSString *)dialogID toUserID:(NSUInteger)userID {
Chat. instance . addDelegate ( self )
func chatDidDeliverMessage ( withID messageID : String , dialogID : String , toUserID userID : UInt ) {
‘Read’ status
Send ‘read’ status:
ConnectyCube (). chat . sendReadStatus ( msg : message, successCallback : {
[CYBChat.instance readMessage:message completion:^(NSError * _Nullable error) {
Chat. instance . read ( message ) { (error) in
The following method of a delegate is used to track ‘read’ status:
//MARK: ConnectycubeMessageStatusListener
ConnectyCube (). chat . addMessageStatusListener ( listener : self )
extension YourClass: ConnectycubeMessageStatusListener {
func onMessageDelivered ( messageId : String , dialogId : String , userId : Int32 ) {
func onMessageRead ( messageId : String , dialogId : String , userId : Int32 ) {
- (void)chatDidReadMessageWithID:(NSString *)messageID dialogID:(NSString *)dialogID readerID:(NSUInteger)readerID {
func chatDidReadMessage ( withID messageID : String , dialogID : String , readerID : UInt ) {
‘Is typing’ status
The following ‘typing’ notifications are supported:
typing: The user is composing a message. The user is actively interacting with a message input interface specific to this chat session (e.g., by typing in the input area of a chat controller)
stopped: The user had been composing but now has stopped. The user has been composing but has not interacted with the message input interface for a short period of time (e.g., 30 seconds)
Send ‘is typing’ status:
ConnectyCube (). chat . sendIsTypingStatus ( dialog : dialog )
[chatDialog sendUserIsTyping];
chatDialog. sendUserIsTyping ()
Send ‘stop typing’ status:
ConnectyCube (). chat . sendStopTypingStatus ( dialog : dialog )
[chatDialog sendUserStoppedTyping];
chatDialog. sendUserStopTyping ()
The following block (closure) is used to track ‘is typing’ status:
//MARK: ConnectycubeChatTypingListener
ConnectyCube (). chat . addTypingStatusListener ( listener : self )
extension YourClass: ConnectycubeChatTypingListener {
func onUserIsTyping ( dialogId : String ? , userId : Int32 ) {
func onUserStopTyping ( dialogId : String ? , userId : Int32 ) {
chatDialog.onUserIsTyping = ^(NSUInteger userID) {
chatDialog. onUserIsTyping = { ( userID : UInt ) in
The following block (closure) is used to track ‘stopped typing’ status:
//MARK: ConnectycubeChatTypingListener
ConnectyCube (). chat . addTypingStatusListener ( listener : self )
extension YourClass: ConnectycubeChatTypingListener {
func onUserIsTyping ( dialogId : String ? , userId : Int32 ) {
func onUserStopTyping ( dialogId : String ? , userId : Int32 ) {
chatDialog.onUserStoppedTyping = ^(NSUInteger userID) {
chatDialog. onUserStoppedTyping = { ( userID : UInt ) in
Edit Message
The following snippet is used to edit chat message:
CYBChatDialog *dialog = ...
[dialog editMessageWithID:@"5356c64ab35c12bd3b10wa64" text:@"New message text" last:YES completion:^(NSError * _Nullable error) {
- (void)chatDidReceiveMessage:(CYBChatMessage \*)message {
dialog. editMessage ( withID : " 5356c64ab35c12bd3b10wa64 " , text : " New message text " , last : true ) { (error) in
func chatDidReceive ( _ message : ChatMessage ) {
Delete chat messages
The following snippet is used to remove chat message via REST:
ConnectyCube (). deleteMessages ( messagesIds : [ " 5b23aa4f5d0b0be0900041aa " , " bc23aa4f5d0b0be0900041ad " ], force : false , successCallback : {(result) in
[CYBRequest deleteMessagesWithIDs:[NSSet setWithArray:@[@"5b23aa4f5d0b0be0900041aa", @"bc23aa4f5d0b0be0900041ad"]]
} errorBlock:^(NSError * _Nonnull error) {
Request. deleteMessages ( withIDs : Set ( [ " 5b23aa4f5d0b0be0900041aa " , " bc23aa4f5d0b0be0900041ad " ] ) ,
This request will remove the messages from current user history only, without affecting the history of other users. The forAllUsers parameter is used to completely remove messages.
The following snippet is used to remove chat message in a real time:
CYBChatDialog *dialog = ...
[dialog removeMessageWithID:@"5356c64ab35c12bd3b10wa64" completion:^(NSError * _Nullable error) {
- (void)chatDidReceiveMessage:(CYBChatMessage \*)message {
dialog. removeMessage ( withID : " 5356c64ab35c12bd3b10wa64 " ) { (error) in
func chatDidReceive ( _ message : ChatMessage ) {
Self-destroy message
Self-destroy messages is used if you want to implement some sort of Secret Chat where messages are visible only for some limited amount of time.
It’s your responsibility to setup a timer in your app and remove messages from the client side.
Self-destroy messages are not stored in server history.
CYBChatMessage *message = [[CYBChatMessage alloc] init];
message.text = @"Self destroy message";
message.destroyAfterInterval = 10 // in seconds
CYBChatDialog _privateDialog = ...;
[privateDialog sendMessage:message completionBlock:^(NSError _ \_Nullable error) {
- (void)chatDidReceiveMessage:(CYBChatMessage \*)message {
//Handle destroyAfterInterval
if (message.destroyAfterInterval > 0) {
let message = ChatMessage ()
message.text = " Self destroy message "
message. destroyAfterInterval = 10 // in seconds
privateDialog. send ( message ) { (error) in
func chatDidReceive ( _ message : ChatMessage ) {
//Handle destroyAfterInterval
if ( message. destroyAfterInterval > 0 ) {
Attachments
Image/Video
Chat attachments are supported with the cloud storage API. In order to send a chat attachment you need to upload the file to ConnectyCube cloud storage and obtain a file UID. Then you need to include this UID into chat message and send it.
ConnectyCube (). uploadFile ( filePath : imageFilePath, public : false , successCallback : {(cubeFile) in
let message = ConnectycubeMessage ()
message. saveToHistory = true
message. recipientId = 10056
let attachment = ConnectycubeAttachment ()
attachment. type = " photo "
attachment. id = String ( cubeFile. id )
message. attachments ? . add ( attachment )
ConnectyCube () . chat . sendMessage ( msg : message )
}, errorCallback : { (error) in
}, progress : { (progress) in
NSURL *fileUrl = [NSURL fileURLWithPath:@"file_path"]; //Local file url
[CYBRequest uploadFileWithUrl:fileUrl fileName:@"image.png" contentType:@"image/png" isPublic:NO progressBlock:^(float progress) {
//Update UI with upload progress
} successBlock:^(CYBBlob * _Nonnull blob) {
CYBChatAttachment *attachment = [[CYBChatAttachment alloc] init];
attachment.ID = blob.UID;
attachment.type = @"image/png";
CYBChatMessage *message = [[CYBChatMessage alloc] init];
message.text = @"Image attachment";
message.attachments = @[attachment];
//Send message with attachment
[chatDialog sendMessage:message completionBlock:^(NSError * _Nullable error) {
} errorBlock:^(NSError * _Nonnull error) {
let url = URL ( fileURLWithPath : " file_path " )
Request. uploadFile ( with : url,
contentType : " image/png " ,
progressBlock : { (progress) in
//Update UI with upload progress
}, successBlock : { (blob) in
let attachment = ChatAttachment ()
attachment. type = " image/png "
let message = ChatMessage ()
message.text = " Image Attachment "
message. attachments = [attachment]
//Send message with attachment
chatDialog. send ( message, completionBlock : { (error) in
The same flow is supported on the receiver’s side. When you receive a message, you need to get the file UID and then you can build a file URL:
// ConnectycubeMessageListener
func onMessage ( message : ConnectycubeMessage ) {
if let attachment = message.attachments {
attachment. forEach { (attachment) in
if let uid = (attachment as! ConnectycubeAttachment).id {
let privateAvatarUrl = ConnectycubeFileKt. getPrivateUrlForUID ( uid : uid )
- (void)chatDidReceiveMessage:(CYBChatMessage *)message {
[message.attachments enumerateObjectsUsingBlock:^(CYBChatAttachment * _Nonnull attachment, NSUInteger idx, BOOL * _Nonnull stop) {
NSString *fileURL = [CYBBlob privateUrlForFileUID:attachment.ID]
func chatDidReceive ( _ message : ChatMessage ) {
if let attachment = message.attachments {
attachment. forEach { (attachment) in
if let uid = attachment.id {
let fileURL = CYBBlob. privateUrlForFileUID ( uid )
A contact profile can be send via chat attachments as well:
let customData = [ " phone " : " 180032323223 " , " name " : " Samuel Johnson " ]
if let theJSONData = try ? JSONSerialization. data ( withJSONObject : customData, options : . prettyPrinted ) {
let data = String ( data : theJSONData, encoding : .utf8 )
let attachment = ConnectycubeAttachment ()
let message = ConnectycubeMessage ()
message. body = " Contact Attachment "
message. attachments = [attachment]
CYBChatAttachment *attachment = [[CYBChatAttachment alloc] init];
attachment[@"phone"] = @"180032323223"
attachment[@"name"] = @"Samuel Johnson"
CYBChatMessage *message = [[CYBChatMessage alloc] init];
message.text = @"Contact attachment";
message.attachments = @[attachment];
let attachment = ChatAttachment ()
attachment[ " phone " ] = " 180032323223 "
attachment[ " name " ] = " Samuel Johnson "
let message = ChatMessage ()
message.text = " Contact Attachment "
message. attachments = [attachment]
On the receiver’s side, when you receive a message, you need to get a contact data from an attachment:
// ConnectycubeMessageListener
func onMessage ( message : ConnectycubeMessage ) {
if let attachment = message.attachments {
attachment. forEach { (attachment) in
if let data = (attachment as! ConnectycubeAttachment).data ? . data ( using : .utf8 ) {
if let contactData = try ? JSONSerialization. jsonObject ( with : data, options : [] ) as! [ String : String ] {
let phone = contactData[ " phone " ]
let name = contactData[ " name " ]
- (void)chatDidReceiveMessage:(CYBChatMessage *)message {
[message.attachments enumerateObjectsUsingBlock:^(CYBChatAttachment * _Nonnull attachment, NSUInteger idx, BOOL * _Nonnull stop) {
NSData *jsonData = [attachment.data dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *contactData = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:nil];
NSString *phone = contactData[@"phone"];
NSString *name = contactData[@"name"];
func chatDidReceive ( _ message : ChatMessage ) {
if let attachment = message.attachments {
attachment. forEach { (attachment) in
if let data = attachment.data ? . data ( using : .utf8 ) {
if let contactData = try ? JSONSerialization. jsonObject ( with : data, options : [] ) as! [ String : String ] {
let phone = contactData[ " phone " ]
let name = contactData[ " name " ]
Unread messages count
You can request total unread messages count and unread count for particular conversation:
ConnectyCube (). getUnreadMessagesCount ( dialogsIds : [ " 8b23aa4f5d0b0be0900041aa " , " 1c23aa4f5d0b0be0900041ad " ], successCallback : {(result) in
NSLog ( " total unread messages= " + result [ " 8b23aa4f5d0b0be0900041aa " ] ! .description )
NSLog ( " total unread messages= " + result [ " 1c23aa4f5d0b0be0900041ad " ] ! .description )
[CYBRequest totalUnreadMessageCountForDialogsWithIDs:[NSSet setWithArray:@[@"8b23aa4f5d0b0be0900041aa", @"1c23aa4f5d0b0be0900041ad"]]
successBlock:^(NSUInteger count, NSDictionary<NSString *,id> * _Nonnull dialogs) {
} errorBlock:^(NSError * _Nonnull error) {
Request. totalUnreadMessageCountForDialogs ( withIDs : Set ( [ " 8b23aa4f5d0b0be0900041aa " , " 1c23aa4f5d0b0be0900041ad " ] ) ,
successBlock : { (count, dialogs) in
Global search
Global search feature was developed to simplify search of dialogs, messages and users at the same time.
Similar functionality is used in most popular messengers and you can implement it in your app using Connectycube SDK.
Just use request from snippet below. SearchRequestBuilder
is optional parameter and it can be null
if you don’t need
additional configs for search request (only v2).
let searchText = " dialog name " // String or word. Should be longer than 4 symbols. Performs 'or' search.
// For an exact search, you need to wrap the search phrase in quotes.
let dialogIds = [ " 8b23aa4f5d0b0be0900041aa " , " 1c23aa4f5d0b0be0900041ad " ]
let searchParams: GlobalSearchParams = GlobalSearchParams () //class-helper to simple config search request
searchParams. dialogIds = dialogIds // List of dialog ids. Max cam include 10 items. Optional parameter.
// searchParams.startDate = startDate // Closest date to now. Uses lte comparison. Optional parameter.
// searchParams.endDate = endDate // Shouldn't differ by more than 3 months from the start_date. Uses gte comparison. Optional parameter.
searchParams. limit = 3 // Maximum number of items returned from the server in the search results. Max value - 100. Optional parameter.
ConnectyCube (). searchText ( searchText : searchText, params : searchParams. getSearchParams () as? [ String : Any ], successCallback : {(result) in
let dialogs = result. dialogs // found dialogs
let messages = result. messages // found messages
let users = result. users // found users
Chat alerts
When you send a chat message and the recipient/recipients is offline, then automatic push notification will be fired.
In order to receive push notifications you need to subscribe for it. Please refer to Push Notifications guide.
To configure push template which users receive - go to Dashboard Console, Chat Alerts page
Also, here is a way to avoid automatically sending push notifications to offline recipient/recipients. For it add the silent
parameter with value 1
to the properties
field of the instance of a ConnectycubeMessage
.
let message = ConnectycubeMessage ()
message. properties [ " silent " ] = " 1 "
After sending such a message, the server won’t create the push notification for offline recipient/recipients.
!> Note that currently push notifications are supported on mobile environment only.
Chat notifications settings
Update notifications settings
A user can turn on/off push notifications for offline messages in a dialog. By default push notification are turned ON,
so offline user receives push notifications for new messages in a chat.
let dialogId = " 8b23aa4f5d0b0be0900041aa "
let enabled = false //false - to disable push notification, true - to enable
ConnectyCube (). updateDialogNotificationsSettings ( dialogId : dialogId, enable : enabled, successCallback : {(result) in
NSLog ( " notification is enabled= " + result.description )
Get notifications settings
Check a status of notifications setting - either it is ON or OFF for a particular chat.
ConnectyCube (). getDialogNotificationsSettings ( dialogId : " 8b23aa4f5d0b0be0900041aa " , successCallback : {(result) in
NSLog ( " notification is enabled= " + result.description )
The Contact List API is rather straightforward. User A sends a request to become “friends” with user B. User B accepts the friend request. And now user A and B appear in each other’s roster.
To access contact list you should use the contactList property of CYBChat class:
// array of accepted contacts
CYBChat.instance.contactList.contacts;
// array of pending requests
CYBChat.instance.contactList.pendingApproval;
// array of accepted contacts
let contacts = Chat. instance . contactList ? . contacts
// array of pending requests
let pendingRequests = Chat. instance . contactList ? . pendingApproval
To add user to the contact list use the following method:
[CYBChat.instance addUserToContactListRequest:userID
completion:^(NSError * _Nullable error) {
Chat. instance . addUser ( toContactListRequest : userID ) { (error) in
Note
Maximum number of contacts is 300.
The CYBChat
instance will call its delegate’s chatDidReceiveContactAddRequestFromUser:
method and this user will receive the request to be added to the contact list:
- (void)chatDidReceiveContactAddRequestFromUser:(NSUInteger)userID {
func chatDidReceiveContactAddRequest ( fromUser userID : UInt ) {
To confirm the request use the following method:
[CYBChat.instance confirmAddContactRequest:userID completion:^(NSError * _Nullable error) {
Chat. instance . confirmAddContactRequest ( userID ) { (error) in
The CYBChat
instance will call its delegate’s chatDidReceiveAcceptContactRequestFromUser:
method and this user will be informed that you have accepted the contact request:
- (void)chatDidReceiveAcceptContactRequestFromUser:(NSUInteger)userID {
func chatDidReceiveAcceptContactRequest ( fromUser userID : UInt ) {
To reject the request use the following method:
[CYBChat.instance rejectAddContactRequest:userID completion:^(NSError * _Nullable error) {
Chat. instance . rejectAddContactRequest ( userID ) { (error) in
The CYBChat
instance will call its delegate’s chatDidReceiveRejectContactRequestFromUser:
method and this user will be informed that you have declined the contact request:
- (void)chatDidReceiveRejectContactRequestFromUser:(NSUInteger)userID {
func chatDidReceiveRejectContactRequest ( fromUser userID : UInt ) {
To remove a previously added user from the contact list use the following method:
[CYBChat.instance removeUserFromContactList:34 completion:^(NSError * _Nullable error) {
Chat. instance . removeUser ( fromContactList : 34 ) { (error) in
You can also track contact list updates in real time by using delegates:
- (void)chatContactListDidChange:(CYBContactList *)contactList {
func chatContactListDidChange ( _ contactList : ContactList ) {
The following method is called in case online status of a user from contact list has been changed:
- (void)chatDidReceiveContactItemActivity:(NSUInteger)userID isOnline:(BOOL)isOnline status:(NSString *)status {
func chatDidReceiveContactItemActivity ( _ userID : UInt , isOnline : Bool , status : String ? ) {
Privacy (black) list
Privacy list API allows enabling or disabling communication with other users in a chat. You can create, modify, or delete privacy lists, define a default list.
The user can have multiple privacy lists, but only one can be active.
Create privacy list
A privacy list must have at least one element in order to be created. If no elements specified, then the list with given name will be deleted.
CYBPrivacyItem *privateChatPrivacyItem =
[[CYBPrivacyItem alloc] initWithPrivacyType:CYBPrivacyTypeUserID
privateChatPrivacyItem.mutualBlock = YES;
CYBPrivacyItem *groupChatPrivacyItem =
[[CYBPrivacyItem alloc] initWithPrivacyType:CYBPrivacyTypeGroupUserID
CYBPrivacyList *privacyList =
[[CYBPrivacyList alloc] initWithName:@"PrivacyList"
items:@[privateChatPrivacyItem,groupChatPrivacyItem]];
[CYBChat.instance setPrivacyList:privacyList];
let privateChatPrivacyItem = PrivacyItem. init ( privacyType : . userID ,
privateChatPrivacyItem. mutualBlock = true
let groupChatPrivacyItem = PrivacyItem. init ( privacyType : . groupUserID ,
let privacyList = PrivacyList. init ( name : " PrivacyList " ,
items : [privateChatPrivacyItem, groupChatPrivacyItem] )
Chat. instance . setPrivacyList ( privacyList )
If the privacy list is set successfully, the CYBChat
instance will call its delegate’s chatDidSetPrivacyListWithName
: method:
- (void)chatDidSetPrivacyListWithName:(NSString *)name {
func chatDidSetPrivacyList ( withName name : String ) {
In case of error the CYBChat
instance will call its delegate’s chatDidNotSetPrivacyListWithName:error:
method:
- (void)chatDidNotSetPrivacyListWithName:(NSString *)name error:(NSError *)error {
func chatDidNotSetPrivacyList ( withName name : String , error : Error ) {
In order to be used the privacy list should be not only set, but also activated(set as default).
Activate privacy list
In order to activate rules from a privacy list you should set it as default:
[CYBChat.instance setDefaultPrivacyListWithName:@"PrivacyList"];
Chat. instance . setDefaultPrivacyListWithName ( " PrivacyList " )
If the privacy list is activated (set as default) successfully, the CYBChat
instance will call its delegate’s chatDidSetDefaultPrivacyListWithName:
method:
- (void)chatDidSetDefaultPrivacyListWithName:(NSString *)name {
func chatDidSetDefaultPrivacyList ( withName name : String ) {
Otherwise the CYBChat
instance will call its delegate’s chatDidNotSetDefaultPrivacyListWithName:error:
method:
- (void)chatDidNotSetDefaultPrivacyListWithName:(NSString *)name error:(NSError *)error {
func chatDidNotSetDefaultPrivacyList ( withName name : String , error : Error ) {
Update privacy list
There are some rules you should follow to update a privacy list:
Include all of the desired items (not a “delta”).
If you want to update or set new privacy list instead of current one, you should decline current default list first.
//Deactivating privacy list before update
[CYBChat.instance setDefaultPrivacyListWithName:nil];
//Activating privacy list
[CYBChat.instance setDefaultPrivacyListWithName:@"PrivacyList"];
//Deactivating privacy list before update
Chat. instance . setDefaultPrivacyListWithName ( nil )
//Activating privacy list
Chat. instance . setDefaultPrivacyListWithName ( " PrivacyList " )
Retrieve privacy list names
To get a list of all your privacy lists’ names use the following request:
[CYBChat.instance retrievePrivacyListNames];
Chat. instance . retrievePrivacyListNames ()
If the privacy list names are retrieved successfully, the CYBChat
instance will call its delegate’s didReceivePrivacyListNames:
method:
- (void)chatDidReceivePrivacyListNames:(NSArray<NSString *> *)listNames {
func chatDidReceivePrivacyListNames ( _ listNames : [ String ] ) {
Otherwise the CYBChat
instance will call its delegate’s didNotReceivePrivacyListNamesDueToError:
method:
- (void)chatDidNotReceivePrivacyListNamesDueToError:(NSError *)error {
func chatDidNotReceivePrivacyListNamesDue ( toError error : Error ) {
Retrieve privacy list with name
To get the privacy list by name you should use the following method:
[CYBChat.instance retrievePrivacyListWithName:@"PrivacyList"];
Chat. instance . retrievePrivacyList ( withName : " PrivacyList " )
If the privacy list is retrieved successfully, the CYBChat
instance will call its delegate’s chatDidReceivePrivacyList:
method:
- (void)chatDidReceivePrivacyList:(CYBPrivacyList *)privacyList {
func chatDidReceive ( _ privacyList : PrivacyList ) {
Otherwise the CYBChat
instance will call its delegate’s chatDidNotReceivePrivacyListWithName:error:
method
- (void)chatDidNotReceivePrivacyListWithName:(NSString *)name
func chatDidNotReceivePrivacyList ( withName name : String , error : Error ) {
Remove privacy list
To delete a list you can call a method below or you can edit a list and set items to nil
.
[CYBChat.instance removePrivacyListWithName:@"PrivacyList"];
Chat. instance . removePrivacyList ( withName : " PrivacyList " )
If the privacy list is removed successfully, the CYBChat
instance will call its delegate’s chatDidRemovedPrivacyListWithName:
method
- (void)chatDidRemovedPrivacyListWithName:(NSString *)name {
func chatDidRemovedPrivacyList ( withName name : String ) {
Blocked user attempts to communicate with user
Blocked users will be receiving an error when trying to chat with a user in a 1-1 chat and will be receiving nothing in a group chat:
chatDialog.onBlockedMessage = ^ ( NSError * _Nullable error) {
chatDialog. onBlockedMessage = { (error) in