Call Attendance
The QueryCallParticipantSessions endpoint retrieves a paginated list of participant sessions for a given call session. Each entry describes an individual join/leave event for a user within that session. This data is not real-time — stats may be delayed or incomplete during an active call. The complete and final data becomes available after the call ends and the call.stats_report_ready event is received.
Response overview
call_type: Type of the call.call_id: ID of the call.call_session_id: ID of the call session being queried.total_participant_sessions: Total number of participant sessions in the call session.total_participant_duration: Sum of all participant durations in seconds.participants_sessions: Array of participant session details. Available for 90 days after the call session ends — after that, this array will be empty while all other response fields remain available:user_id: ID of the user.user_session_id: ID of the user's session.joined_at: Timestamp when the participant joined.left_at: Timestamp when the participant left.duration_in_seconds: Duration of the participant's session in seconds.publisher_type: Type of publisher (webrtc,rtmp,srt, etc.).roles: Roles assigned to the participant.
next/prev: Cursors for pagination.
const call = client.video.call("default", "call-id");
const response = await call.queryCallParticipantSessions({
session: "<session-id>",
limit: 25,
});call = client.video.call("default", "call-id")
response = call.query_call_participant_sessions(session="<session-id>", limit=25)call := client.Video().Call("default", "call-id")
response, err := call.QueryCallParticipantSessions(ctx, "<session-id>", &getstream.QueryCallParticipantSessionsRequest{
Limit: getstream.PtrTo(25),
})
if err != nil {
return err
}var call = client.video().call("default", "call-id");
var response = call.queryCallParticipantSessions(
"<session-id>",
QueryCallParticipantSessionsRequest.builder().limit(25).build()
);curl -X GET "https://video.stream-io-api.com/api/v2/video/call/${CALL_TYPE}/${CALL_ID}/session/${SESSION_ID}/participant_sessions?api_key=${API_KEY}&limit=25" \
-H "Authorization: ${TOKEN}" \
-H "stream-auth-type: jwt"Filtering
You can narrow down results using filter_conditions. Filters follow the same syntax as other query endpoints. Note that filters only affect the participants_sessions list — aggregated fields such as total_participant_sessions and total_participant_duration always reflect the full call session.
const response = await call.queryCallParticipantSessions({
session: "<session-id>",
filter_conditions: { user_id: { $eq: "alice" } },
});response = call.query_call_participant_sessions(
session="<session-id>",
filter_conditions={"user_id": {"$eq": "alice"}},
)response, err := call.QueryCallParticipantSessions(ctx, "<session-id>", &getstream.QueryCallParticipantSessionsRequest{
FilterConditions: map[string]interface{}{
"user_id": map[string]interface{}{"$eq": "alice"},
},
})var response = call.queryCallParticipantSessions(
"<session-id>",
QueryCallParticipantSessionsRequest.builder()
.filterConditions(Map.of("user_id", Map.of("$eq", "alice")))
.build()
);curl -X GET "https://video.stream-io-api.com/api/v2/video/call/${CALL_TYPE}/${CALL_ID}/session/${SESSION_ID}/participant_sessions?api_key=${API_KEY}&filter_conditions%5Buser_id%5D%5B%24eq%5D=alice" \
-H "Authorization: ${TOKEN}" \
-H "stream-auth-type: jwt"To compute aggregated values (such as total duration or session count) for a filtered subset of participants, paginate through all pages and accumulate the results manually:
const filter_conditions = { user_id: { $eq: "alice" } };
let cursor;
let totalDuration = 0;
let totalSessions = 0;
do {
const response = await call.queryCallParticipantSessions({
session: "<session-id>",
limit: 100,
next: cursor,
filter_conditions,
});
for (const s of response.data.participants_sessions) {
totalDuration += s.duration_in_seconds;
totalSessions += 1;
}
cursor = response.data.next;
} while (cursor);filter_conditions = {"user_id": {"$eq": "alice"}}
cursor = None
total_duration = 0
total_sessions = 0
while True:
response = call.query_call_participant_sessions(
session="<session-id>", limit=100, next=cursor,
filter_conditions=filter_conditions,
)
for s in response.data.participants_sessions:
total_duration += s.duration_in_seconds
total_sessions += 1
cursor = response.data.next
if not cursor:
breakvar cursor *string
totalDuration := 0
totalSessions := 0
for {
response, err := call.QueryCallParticipantSessions(ctx, "<session-id>", &getstream.QueryCallParticipantSessionsRequest{
Limit: getstream.PtrTo(100),
Next: cursor,
FilterConditions: map[string]interface{}{
"user_id": map[string]interface{}{"$eq": "alice"},
},
})
if err != nil {
return err
}
for _, s := range response.Data.ParticipantsSessions {
totalDuration += s.DurationInSeconds
totalSessions++
}
cursor = response.Data.Next
if cursor == nil {
break
}
}String cursor = null;
long totalDuration = 0;
int totalSessions = 0;
do {
var response = call.queryCallParticipantSessions(
"<session-id>",
QueryCallParticipantSessionsRequest.builder()
.limit(100)
.next(cursor)
.filterConditions(Map.of("user_id", Map.of("$eq", "alice")))
.build()
);
for (var s : response.getData().getParticipantsSessions()) {
totalDuration += s.getDurationInSeconds();
totalSessions++;
}
cursor = response.getData().getNext();
} while (cursor != null);Pagination
Use next and prev cursors from the response to paginate through results.
let cursor;
do {
const response = await call.queryCallParticipantSessions({
session: "<session-id>",
limit: 25,
next: cursor,
});
cursor = response.data.next;
} while (cursor);cursor = None
while True:
response = call.query_call_participant_sessions(
session="<session-id>", limit=25, next=cursor
)
cursor = response.data.next
if not cursor:
breakvar cursor *string
for {
response, err := call.QueryCallParticipantSessions(ctx, "<session-id>", &getstream.QueryCallParticipantSessionsRequest{
Limit: getstream.PtrTo(25),
Next: cursor,
})
if err != nil {
return err
}
cursor = response.Data.Next
if cursor == nil {
break
}
}String cursor = null;
do {
var response = call.queryCallParticipantSessions(
"<session-id>",
QueryCallParticipantSessionsRequest.builder().limit(25).next(cursor).build()
);
cursor = response.getData().getNext();
} while (cursor != null);curl -X GET "https://video.stream-io-api.com/api/v2/video/call/${CALL_TYPE}/${CALL_ID}/session/${SESSION_ID}/participant_sessions?api_key=${API_KEY}&limit=25&next=${NEXT_CURSOR}" \
-H "Authorization: ${TOKEN}" \
-H "stream-auth-type: jwt"