JS SDK Callbacks to Promises Transition Guide

This guide explains how to migrate existing Vonage Video API JavaScript SDK code from callback-based completion handlers to promise-based APIs.

Overview

Starting with version 2.35.1, the JavaScript SDK supports promise-based completion across OT namespace utilities and a broad set of Session, Publisher, and Subscriber APIs. This lets you:

  • Replace nested callbacks with async / await
  • Handle errors with standard try / catch
  • Sequence publish and subscribe flows more clearly
  • Migrate incrementally, because callback signatures remain available for backward compatibility

There are two migration patterns:

  • Direct promise return: Use this when the method itself resolves or rejects a promise. Example: const devices = await OT.getDevices()
  • .promise helper: Use this when the legacy method still returns Session, Publisher, or Subscriber, and the promise API is exposed on the method as a .promise(...) helper. Example: await session.connect.promise(token)

Note: Event listeners do not change. Continue to use session.on(...), publisher.on(...), and subscriber.on(...) for asynchronous events.

What Changed

The promisification work was rolled out in stages:

  • OT namespace utilities such as device lookup, screen-sharing capability checks, and issue reporting
  • Session lifecycle and moderation helpers
  • Session.publish() and Session.subscribe()
  • Publisher stats and publisher control APIs
  • Subscriber stats and subscriber control APIs

In practice, this means that most completion-handler code in a web client can now be rewritten using promises.

Migration Strategy

  1. Convert the function that owns your Vonage Video API flow to async.
  2. Replace completion handlers with await.
  3. Wrap related API calls in try/catch.
  4. Keep event-driven code as events.
  5. Use the .promise form when the legacy method still returns an object for chaining.

Common Before and After Pattern

Callback-based flow

const session = OT.initSession(apiKey, sessionId);

session.connect(token, function(connectError) {
  if (connectError) {
    console.error(connectError);
    return;
  }

  const publisher = OT.initPublisher('publisher', publisherOptions, function(publisherError) {
    if (publisherError) {
      console.error(publisherError);
      return;
    }

    session.publish(publisher, function(publishError) {
      if (publishError) {
        console.error(publishError);
      }
    });
  });
});

Promise-based flow

async function joinAndPublish() {
	const session = OT.initSession(apiKey, sessionId);

	try {
		await session.connect.promise(token);

		const publisher = await OT.initPublisher.promise('publisher', publisherOptions);

		await session.publish.promise(publisher);
	} catch (error) {
		console.error(error.name, error.message);
	}
}

Direct Promise-returning APIs

These APIs can be migrated by removing the completion handler and awaiting the result directly.

OT namespace

Callback style Promise style
OT.getDevices(function(error, devices) { ... }) const devices = await OT.getDevices()
OT.checkScreenSharingCapability(function(response) { ... }) const response = await OT.checkScreenSharingCapability()
OT.reportIssue(function(error, issueId) { ... }) const issueId = await OT.reportIssue()

Example:

try {
	const capability = await OT.checkScreenSharingCapability();

	if (!capability.supported) {
		console.warn('Screen sharing is not supported in this browser.');
		return;
	}

	const devices = await OT.getDevices();
	console.log(devices);
} catch (error) {
	console.error(error.name, error.message);
}

Session APIs

Callback style Promise style
session.signal(options, function(error) { ... }) await session.signal(options)
session.forceDisconnect(connection, function(error) { ... }) await session.forceDisconnect(connection)
session.forceUnpublish(stream, function(error) { ... }) await session.forceUnpublish(stream)

The following Session methods also return promises directly:

  • session.disconnect()
  • session.disableForceMute()
  • session.forceMuteStream(stream)
  • session.forceMuteAll(excludedStreams)
  • session.setEncryptionSecret(secret)
  • session.setIceConfig(iceConfig)

Publisher APIs

Callback style Promise style
publisher.getStats(function(error, stats) { ... }) const stats = await publisher.getStats()

The following Publisher methods also return promises directly:

  • publisher.publishCaptions(value)
  • publisher.cycleVideo()
  • publisher.setAudioSource(audioSource)
  • publisher.setVideoSource(videoSourceId)
  • publisher.setVideoContentHint(hint)
  • publisher.setPreferredFrameRate(frameRate)
  • publisher.setPreferredResolution(resolution)
  • publisher.setMaxVideoBitrate(bitrateBps)
  • publisher.setVideoBitratePreset(preset)
  • publisher.setVideoMediaProcessorConnector(connector)
  • publisher.setAudioMediaProcessorConnector(connector)

Subscriber APIs

Callback style Promise style
subscriber.getStats(function(error, stats) { ... }) const stats = await subscriber.getStats()

The following Subscriber methods also return promises directly:

  • subscriber.subscribeToCaptions(value)
  • subscriber.setPreferredFrameRate(frameRate)
  • subscriber.setPreferredResolution(resolution)
  • subscriber.setCaptionsTranslationLanguage(langCode)
  • subscriber.setVideoMediaProcessorConnector(connector)
  • subscriber.setAudioMediaProcessorConnector(connector)

APIs That Use .promise

Some methods keep their legacy return value so existing chaining code continues to work. Use the .promise helper when you need to wait for completion.

OT namespace

Callback style Promise style
OT.initPublisher(targetElement, properties, callback) const publisher = await OT.initPublisher.promise(targetElement, properties)

Session helpers

Callback style Promise style
session.connect(token, callback) await session.connect.promise(token)
session.publish(publisher, callback) await session.publish.promise(publisher)
session.publish(targetElement, properties, callback) const publisher = await session.publish.promise(targetElement, properties)
session.subscribe(stream, targetElement, properties, callback) const subscriber = await session.subscribe.promise(stream, targetElement, properties)

Publisher helpers

Callback style Promise style
publisher.publishAudio(value) await publisher.publishAudio.promise(value)
publisher.publishVideo(value, callback) await publisher.publishVideo.promise(value)

Subscriber helpers

Callback style Promise style
subscriber.subscribeToAudio(value) await subscriber.subscribeToAudio.promise(value)
subscriber.subscribeToVideo(value) await subscriber.subscribeToVideo.promise(value)
subscriber.setAudioVolume(value) await subscriber.setAudioVolume.promise(value)
subscriber.restrictFrameRate(value) await subscriber.restrictFrameRate.promise(value)

Example:

try {
	await publisher.publishAudio.promise(false);
	await publisher.publishVideo.promise(true);

	const subscriber = await session.subscribe.promise(stream, 'subscriber', {
		insertMode: 'append',
		width: '100%',
		height: '100%'
	});

	await subscriber.subscribeToAudio.promise(true);
	await subscriber.setAudioVolume.promise(40);
} catch (error) {
	console.error(error.name, error.message);
}

Error Handling

In callback-based code, errors are usually passed as the first argument to the completion handler. In promise-based code, the same failures are surfaced as rejected promises.

try {
	const stats = await subscriber.getStats();
	console.log(stats);
} catch (error) {
	console.error(error.name);
	console.error(error.message);
}

This makes it easier to use a single try/catch block for a sequence of related operations.

Incremental Adoption

You do not need to migrate the entire application in one pass. A recommended approach is:

  1. Start with connection, publish, and subscribe flows
  2. Migrate moderation and signaling helpers next
  3. Migrate publisher and subscriber control code last

Because callback compatibility remains in place, you can move one code path at a time.

Compatibility Notes

  • OT.initSession() still returns a Session synchronously.
  • session.unpublish() and session.unsubscribe() remain immediate teardown helpers.
  • Event listeners such as streamCreated, sessionDisconnected, and videoDisabled remain event-based.
  • If your application must support older SDK releases, keep the callback form until every deployed client is updated to a release that includes these promise APIs.

Next Steps