Zoom Video SDK: connection-change Event Not Firing

connection-change event no longer firing in Zoom Video SDK Web v2.x


Description

When using Zoom Video SDK for Web v2.x, the connection-change event is no longer firing when joining or leaving a session.

This behavior worked correctly in v1.12.17, where the event triggered:

  • { state: 'Connected' } * is emitted when calling join
  • { state: 'Closed' } * is emitted when calling leave

We are using this event to detect session connection status, but with v2.x it seems to be silently broken or changed.


Browser Console Error

No error is thrown. The callback simply doesn’t execute.


Which Web Video SDK version?

  • Working on: @zoom/videosdk v1.12.17
  • Not working on: @zoom/videosdk v2.x.x

Video SDK Code Snippets

const log = useCallback((state: ConnectionChangePayload) => {
  console.log(state)
}, [])

useEffect(() => {
  client.on('connection-change', log)
  return () => {
    client.off('connection-change', log)
  }
}, [log])


To Reproduce

  1. Initialize the Zoom Video SDK client
  2. Join a session
  3. Leave the session
  4. Observe: no log is printed from the connection-change event

Device

  • Device: MacBook Pro (M1)
  • OS: macOS Sonoma 14.3
  • Browser: Chrome
  • Browser Version: 138.0.7204.101 (Official Build) (arm64)

Additional context

If this is an intentional change in the Zoom SDK v2.x, what is the new way to detect connection status transitions like join/leave?

Are there any alternative events or lifecycle hooks we should use to track connection state?

Please advise.

I wanted to attach the log outputs for each SDK version, but I wasn’t able to.

Hey @user99

Thanks for your feedback.

We tested the connection-change event and confirmed that it is triggered correctly in version 2.x. Could it be that you didn’t properly register the listener using the client.on method?

One important note: if you destroy the instance using destroyClient and then create a new one with createClient, you need to rebind all event listeners.

Thanks
Vic

This issue occurred after upgrading the @zoom/videosdk version from 1.12.17 to 2.x.

Other than the version change, the implementation remains the same, so I believe it’s unlikely that the event listener is not being registered.

I did some additional testing.

In zoom/videosdk-web-sample, it has been confirmed that the connection-change event still fires correctly with Zoom SDK v2.2.5.

However, when using Next.js, it seems that event binding via useEffect no longer works correctly with v2.x. I believe this is due to differences in the lifecycle behavior under Next.js’s SSR and Client Component model.


:white_check_mark: Environment

  • React: 18.3.1
  • Next.js: 14.2.15
  • Zoom Video SDK: v1.12.17 / v2.2.5
  • Setup:
    • App Router
    • 'use client' directive
    • dynamic(..., { ssr: false }) to disable SSR

Test codes

Page.tsx

'use client'

import { generateZoomJWT, TOPIC } from '@/lib/utils/jwe-token'
import dynamic from 'next/dynamic'
import { useEffect, useState } from 'react'

const Sample = dynamic(() => import('@/components/Sample/Sample').then((mod) => mod.Sample), {
  ssr: false,
})

export default function Page() {
  const [sig, setSig] = useState<{ topic: string; token: string } | null>(null)

  useEffect(() => {
    console.log('generating Zoom JWT token...')
    const token = generateZoomJWT()

    setSig({
      topic: TOPIC,
      token: token,
    })
  }, [])

  return (
    sig && (
      <Sample
        token={sig.token}
        topic={sig.topic}
      />
    )
  )
}

###Sample.tsx

'use client'
import ZoomVideo from '@zoom/videosdk'
import { useEffect, useState } from 'react'

const client = ZoomVideo.createClient()

const log = (payload: any) => {
  console.log('Connection changed', payload)
}

export const Sample = ({ topic, token }: { topic: string; token: string }) => {
  const [joined, setJoined] = useState(false)

  // âś… Works with videosdk v1.12.17
  // ❌ Does not work with videosdk v2.2.5
  useEffect(() => {
    client.on('connection-change', log)
    return () => {
      client.off('connection-change', log)
    }
  }, [])

  // âś… Work with videosdk v2.2.5
  useEffect(() => {
    if (!joined) return

    client.on('connection-change', log)
    return () => {
      client.off('connection-change', log)
    }
  }, [joined])

  useEffect(() => {
    try {
      client.join(topic, token, 'userName')
      setJoined(true)
    } catch (e: any) {
      console.log(e)
    }
  }, [topic, token])

  return <button onClick={() => client.leave()}>LEAVE</button>
}

:light_bulb: Observations

In a Next.js app, I dynamically import the component and wrap it in a client component. I use a useEffect hook to generate the JWT token and pass it as props. Then, inside the component:

  • With v1.12.17, placing client.on('connection-change', ...) in a standard useEffect([]) hook successfully captures the event.
  • With v2.2.5, that same useEffect([]) hook no longer works. The event does not fire unless the event listener is attached after client.join(...) and a state like joined is set to true.

:thinking: Question

Is the binding and behavior of events such as connection-change in Zoom Video SDK v2.x working as intended according to the specification?

If so, is there an updated recommendation for when to attach event listeners like connection-change in client-only frameworks like Next.js?

Hi @user99

We haven’t made any changes to the event listening or triggering mechanisms — they are the same in versions 1.12.17 and 2.2.5.

As you confirmed in your testing, the sample app works as expected. I noticed that you’re using dynamic with ssr set to false, so the behavior should be consistent with the sample app, as both are using CSR.

Thanks
Vic

Hi @vic.yang

Thanks for getting back to me.

By the way, did you happen to try running the minimal reproduction code I shared earlier (specifically Page.tsx and Sample.tsx)?
I just want to confirm whether the issue might be related to how the listener is registered in that snippet.

Appreciate your help!

Hi, @vic.yang

I have additional question.

When calling the leave method of VideoClient with the end option like leave(true), are the event listeners registered via client.on automatically removed?

Hi @user99

When calling the leave method of VideoClient with the end option like leave(true), are the event listeners registered via client.on automatically removed?

Yes.

When calling leave(true) to end the session, all events registered via client.on will also become invalid. However, this is not the case for the leave() method without arguments.

The design rationale is that a regular leave() allows the client to rejoin the session later without needing to reinitialize, so event bindings are preserved. In contrast, after an end (via leave(true)), the full lifecycle—including init, join, and re-binding events—is required.

Thanks
Vic

1 Like