Watching a Channel

LAST EDIT Mar 04 2021

The call to channel.watch does a few different things in one API call:

  • It creates the channel if it doesn't exist yet (if this user has the right permissions to create a channel)

  • It queries the channel state and returns members, watchers and messages

  • It watches the channel state and tells the server that you want to receive events when anything in this channel changes

To start watching a channel

Copied!

The examples below show how to watch a channel. Note that you need to be connected as a user before you can watch a channel.

1
const state = await channel.watch();
1
final state = await channel.watch();
1
2
3
4
5
6
7
8
9
val channelClient = client.channel(channelType = "messaging", channelId = "general") 
 
channelClient.watch().enqueue { result -> 
    if (result.isSuccess) { 
        val channel: Channel = result.data() 
    } else { 
        // Handle result.error() 
    } 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/// Channels are watched automatically when they're synchronized. 
 
/// 1: Create a `ChannelId` that represents the channel you want to watch. 
let channelId = ChannelId(type: .messaging, id: "general") 
 
/// 2: Use the `ChatClient` to create a `ChatChannelController` with the `ChannelId`. 
let channelController = chatClient.channelController(for: channelId) 
 
/// 3: Call `ChatChannelController.synchronize` to watch the channel. 
channelController.synchronize { error in 
    if let error = error { 
        /// 4: Handle possible errors 
        print(error) 
    } 
}
1
2
3
4
5
6
7
8
9
ChannelClient channelClient = client.channel("messaging", "general"); 
 
channelClient.watch().enqueue(result -> { 
    if (result.isSuccess()) { 
        Channel channel = result.data(); 
    } else { 
        // Handle result.error() 
    } 
});

Response Schema

Name

Type

Description

config

object

The configuration for the channel type.

channel

object

The Channel object.

online

integer

Number of online members.

watchers

object

Users that are watching this channel. Represented as a mapping from the user id to the user object.

members

object

Channel members. Represented as a mapping from the user id to the user object.

read

object

Read messages grouped by user id. Represented as a mapping from the user id to the message object.

Watching a channel only works if you have connected as a user to the chat API

Watchers vs Members

Copied!

The concepts of watchers vs members can require a bit of clarification:

  • members: a permanent association between a user and a channel. If the user is online and not watching the channel they will receive a notification event, if they are offline they will receive a push notification.

  • watchers: the list of watchers is temporary. It's anyone who is currently watching the channel.

Being able to send messages, and otherwise engage with a channel as a non-member requires certain permissions. For example, we have pre-configured permissions on our livestream channel type to allow non-members to interact, but in the messaging channel type, only members of the channel can interact.

Watching Multiple Channels

Copied!

The default queryChannels API returns channels and starts watching them. There is no need to also use channel.watch on the channels returned from queryChannels

1
2
3
4
5
6
7
8
// first let’s create a filter to make messaging channels that include a specific user 
const filter = { type: 'messaging', members: { $in: [user_id] } }; 
// we can also define a sort order of most recent messages first 
const sort = { last_message_at: -1 }; 
  
// finally, we can query for those channels, automatically watching them for the 
// currently connected user  
const channels = await client.queryChannels(filter, sort, {watch:true});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
val request = QueryChannelsRequest( 
    filter = Filters.and( 
        Filters.eq("type", "messaging"), 
        Filters.`in`("members", listOf(currentUserId)), 
    ), 
    offset = 0, 
    limit = 10, 
    querySort = QuerySort.desc("last_message_at") 
).apply { 
    // Watches the channels automatically 
    watch = true 
    state = true 
} 
 
// Run query on ChatClient 
client.queryChannels(request).enqueue { result -> 
    if (result.isSuccess) { 
        val channels: List<Channel> = result.data() 
    } else { 
        // Handle result.error() 
    } 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
FilterObject filter = Filters.and( 
        Filters.eq("type", "messaging"), 
        Filters.in("members", Collections.singletonList(currentUserId)) 
); 
int offset = 0; 
int limit = 10; 
QuerySort<Channel> sort = new QuerySort<Channel>().desc("last_message_at"); 
int messageLimit = 0; 
int memberLimit = 0; 
 
QueryChannelsRequest request = new QueryChannelsRequest(filter, offset, limit, sort, messageLimit, memberLimit) 
        .withWatch() // Watches the channels automatically 
        .withState(); 
 
// Run query on ChatClient 
client.queryChannels(request).enqueue((result) -> { 
    if (result.isSuccess()) { 
        List<Channel> channels = result.data(); 
    } else { 
        // Handle result.error() 
    } 
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// first let’s create a filter to make messaging channels that include a specific user 
final filter = { 
  "type": "messaging", 
  "members": { 
    "\$in": [user_id] 
  } 
}; 
 
// we can also define a sort order of most recent messages first 
final sort = [SortOption("last_message_at", direction: SortOption.DESC)]; 
  
// finally, we can query for those channels, automatically watching them for the 
// currently connected user  
final channels = await client.queryChannels( 
  filter: filter, 
  sort: sort, 
  options: { 
    "watch": true,  
    "state": true, 
  }, 
);

Stop Watching a Channel

Copied!

To stop receiving channel events:

1
2
// we can also stop watching a channel  
const stopWatching = await channel.stopWatching();
1
2
3
4
5
6
7
channelClient.stopWatching().enqueue { result -> 
    if (result.isSuccess) { 
        // Channel unwatched 
    } else { 
        // Handle result.error() 
    } 
}
1
2
3
4
5
6
7
channelClient.stopWatching().enqueue(result -> { 
    if (result.isSuccess()) { 
        // Channel unwatched 
    } else { 
        // Handle result.error() 
    } 
});
1
2
// we can also stop watching a channel  
final stopWatching = await channel.stopWatching();

Watcher Count

Copied!

To get the watcher count of a channel:

1
2
3
4
5
6
7
8
9
10
// filter on a specific channel cid  
const filter = { cid: channelCID }; 
// sort by most recent messages first 
 const sort = { last_message_at: -1 }; 
  
// retrieve our channels 
 const channels = await client.queryChannels(filter, sort); 
  
// each channel object has a state collection with a watcher_count property 
 return channels[0].state.watcher_count
1
2
3
4
5
6
7
8
9
val request = QueryChannelRequest().withState() 
channelClient.query(request).enqueue { result -> 
    if (result.isSuccess) { 
        val channel: Channel = result.data() 
        channel.watcherCount 
    } else { 
        // Handle result.error() 
    } 
}
1
2
3
4
5
6
7
8
9
QueryChannelRequest request = new QueryChannelRequest().withState(); 
channelClient.query(request).enqueue((result) -> { 
    if (result.isSuccess()) { 
        Channel channel = result.data(); 
        channel.getWatcherCount(); 
    } else { 
        // Handle result.error() 
    } 
});
1
2
3
4
5
6
7
8
// create a new channel of type “livestream” with name “watch-this-channel” 
final channel = client.channel("livestream", id: "watch-this-channel");  
  
// retrieve our channels 
channel.query(); 
  
// each channel object has a state collection with a watcher_count property 
 return channel.state.watcherCount;

Paginating Channel Watchers with channel.query

Copied!
1
2
3
4
5
6
7
8
9
// create a new channel of type “livestream” with name “watch-this-channel” 
const channel = client.channel("livestream", "watch-this-channel", {});  
  
// now query the newly created channel for watchers, retrieving the first 5 
const result = await channel.query({ 
   watchers: { limit: 5, offset: 0 }, 
 }); 
  
 return result.watchers;
1
2
3
4
5
6
7
8
9
10
val request = QueryChannelRequest() 
    .withWatchers(limit = 5, offset = 0) 
channelClient.query(request).enqueue { result -> 
    if (result.isSuccess) { 
        val channel: Channel = result.data() 
        val watchers: List<User> = channel.watchers 
    } else { 
        // Handle result.error() 
    } 
}
1
2
3
4
5
6
7
8
9
10
11
int limit = 5; 
int offset = 0; 
QueryChannelRequest request = new QueryChannelRequest().withWatchers(limit, offset); 
channelClient.query(request).enqueue((result) -> { 
    if (result.isSuccess()) { 
        Channel channel = result.data(); 
        List<User> watchers = channel.getWatchers(); 
    } else { 
        // Handle result.error() 
    } 
});
1
2
3
4
5
6
7
8
9
10
11
12
// create a new channel of type “livestream” with name “watch-this-channel” 
final channel = client.channel("livestream", id: "watch-this-channel");  
  
// now query the newly created channel for watchers, retrieving the first 5 
final result = await channel.query( 
    watchersPagination: PaginationParams( 
      limit: 5, 
      offset: 0, 
    ), 
  ); 
  
 return result.watchers;

Listening to Changes in Watchers

Copied!

A user already watching the channel can listen to users starting and stopping watching the channel with the realtime events:

1
2
3
4
5
6
7
8
9
10
11
12
const channel = client.channel("livestream", "watch-this-channel", {}); 
  
 channel.watch(); 
  
 channel.on("user.watching.start", (event) => { 
   // handle watch started event 
   console.log(`${event.user.id} started watching`); 
 }); 
 channel.on("user.watching.stop", (event) => { 
   // handle watch stopped event 
   console.log(`${event.user.id} stopped watching`); 
 });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Start watching channel 
channelClient.watch().enqueue { 
    /* Handle result */ 
} 
 
// Subscribe for watching events 
channelClient.subscribeFor( 
    UserStartWatchingEvent::class, 
    UserStopWatchingEvent::class, 
) { event -> 
    when (event) { 
        is UserStartWatchingEvent -> { 
            // User who started watching the channel 
            val user = event.user 
        } 
        is UserStopWatchingEvent -> { 
            // User who stopped watching the channel 
            val user = event.user 
        } 
    } 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Start watching channel 
channelClient.watch().enqueue((result) -> { 
    /* Handle result */ 
}); 
 
// Subscribe for watching events 
channelClient.subscribeFor( 
        new Class[]{ 
                UserStartWatchingEvent.class, 
                UserStopWatchingEvent.class, 
        }, 
        (event) -> { 
            if (event instanceof UserStartWatchingEvent) { 
                // User who started watching the channel 
                User user = ((UserStartWatchingEvent) event).getUser(); 
            } else if (event instanceof UserStopWatchingEvent) { 
                // User who stopped watching the channel 
                User user = ((UserStopWatchingEvent) event).getUser(); 
            } 
        } 
);
1
2
3
4
5
6
7
8
9
10
11
12
13
final channel = client.channel("livestream", id: "watch-this-channel"); 
  
await channel.watch(); 
  
// handle watch started event 
channel 
      .on("user.watching.start") 
      .listen((event) => print('${event.user.id} started watching')); 
 
// handle watch stopped event 
channel 
      .on("user.watching.stop") 
      .listen((event) => print('${event.user.id} stopped watching'));