Implement the Co-Watching API

This page describes how to use the Co-Watching API to support a co-watching scenario.

Initial setup

To prepare the library for use, the live sharing application should initialize a CoWatchingClient object which represents a co-watching session.

To use the Meet Live Sharing SDK, call the AddonClientFactory.getClient method. This returns an AddonClient that serves as the entry point for the co-watching session.

To use the client, call the newSessionBuilder method from the AddonClient to return a builder for a new AddonSession. The newSessionBuilder implements the AddonSessionHandler interface to handle the callbacks provided by the add-on for the session.

To begin a session, add the withCoWatching method onto the builder.

The following code sample shows a basic initialization of the co-watching client object:


class AwesomeVideoAddonSessionHandler implements AddonSessionHandler {}

// For sample implementation, see the "Manage remote state" section below.
class AwesomeVideoCoWatchingHandler implements CoWatchingHandler {}

public ListenableFuture<AddonSession> initialSetup() {
  AddonClient meetClient = AddonClientFactory.getClient();
  return meetClient
          new AwesomeVideoAddonSessionHandler())
      .withCoWatching(new AwesomeVideoCoWatchingHandler())

Notify on user actions

When the local user performs actions—for example, pausing or seeking the media playout on their device—the library must be informed so those actions can be mirrored to other participants in the co-watching experience. For an example of how to notify the library for multiple states, see Get started.

You can control the co-watching state using these methods:

The following code sample shows how to notify users:


public void onVideoPaused(Duration currentTimestamp) {
  // Use Meet to broadcast the pause state to ensure other participants also pause.
  this.session.getCoWatching().notifyPauseState(/* paused= */ true, currentTimestamp);

Manage remote state

To apply incoming updates from remote participants, you must offer Meet a way to directly manage the local media playout state using the CoWatchingHandler.onCoWatchingStateChanged() callback.

Meet also needs to retrieve the current position of the media playout by calling the CoWatchingHandler.onStateQuery() callback. This is called regularly, so it should be written to be performant (for example, <100 ms).

The following code sample shows an implementation of the CoWatchingHandler:


class AwesomeVideoCoWatchingHandler implements CoWatchingHandler {
  /** Applies incoming playback state to the local video. */
  public void onCoWatchingStateChanged(CoWatchingState newState) {
    // Handle transition to new video.
    if (!newState.mediaId().equals(this.videoPlayer.videoUrl)) {

    // Only adjust the local video playout if it's sufficiently diverged from the timestamp in the
    // applied update.
    if (newState
        > 0) {;

    // Update pause state, if necessary.
    if (newState.playbackState().equals(PLAY) && this.videoPlayer.isPaused) {
    } else if (newState.playbackState().equals(PAUSE) && !this.videoPlayer.isPaused) {

  /** Returns local video playback state. */
  public Optional<QueriedCoWatchingState> onStateQuery() {
    return Optional.of(QueriedCoWatchingState.of(
      /* mediaPlayoutPosition= */ this.videoPlayer.videoTimestamp));