Website Integration

Because every game exposes Genvid differently, every game requires a customized website. This includes both the skinning aspect (HTML and CSS) as well as the functional side (JavaScript). You also need to run a web server hosting the web application for the browser.

Since there are multiple ways of creating websites, this section only covers steps common to the Genvid SDK.

Backend integration

The Genvid web client needs to access a single service, called the leaf, which provides a websocket server from which the client will access the game data. To get the connection URL for this service, two web requests must be sent to the Disco service API:

The APIs use a secret code for security, so they should only be called from a trusted website. In the tutorial website, we route them inside the routes/streams.t.ts file to the /streams and /channels/join URLs, respectively.

The disco service is registered with Consul and you can find its URL this way.


Future versions of the API will expose more API for authenticating the user with a third party service and using this authentication for assigning the websocket, which is the main reason why this API is protected. For now, this functionality is disabled and no authentication is done in this version.

Commands integration

The command service enables sending commands directly to the game, which is useful for an admin website. See Command service API: for more information.

JavaScript API

Genvid provides 3 distributions of the JavaScript API.

  • Browser Backward compatible distribution. Use JavaScript global variables packaged with webpack. Available under api/web/dist/browser.
  • Common-js A browser compatible distribution with Common-JS modules. Available under api/web/dist/commonjs.
  • Node.js Common-JS modules to be used with Node.js. Available under api/web/dist/node.

All of the distributions have TypeScript definition files with them.

The following code uses the Browser distribution. You can use the Common-js distribution instead if you want to use modules.

Frontend integration

The first step in integrating Genvid into your frontend is to instantiate a genvidClient.IGenvidClient() object using the genvidClient.createGenvidClient():

let client = genvid.createGenvidClient(streamInfo, websocketURL, websocketToken, video_player_id);

The first parameter, streamInfo, corresponds to an genvidClient.IStreamInfo() structure, typically returned by the backend service from the POST /disco/stream/join call.

The next two parameters, websocketURL and websocketToken, are the two values specifying the websocket address and security token, respectively. They are provided by the backend through the POST /disco/stream/join call.

The last parameter, video_player_id, is a string referencing an HTML element that you want to use for the live streaming video player. When the IGenvidClient() creates the video player, it will replace this HTML element with the one from the live streaming service.

onVideoPlayerReady callback

When you create the player, IGenvidClient() calls the function specified with genvidClient.IGenvidClient.onVideoPlayerReady(). This is typically used to hook up the overlay.

client.onVideoPlayerReady( function(elem) { console.log('Create the overlay!'); } );

onAuthenticated callback

The onAuthenticated() callback tells the user when the IGenvidClient() successfully connects to the Genvid Services:

client.onAuthenticated( function(succeed) { if (succeeded) { console.log('Connected!'); } });

onStreamsReceived callback

The onStreamsReceived() callback tells you when you receive new stream data. It’s useful for decoding or analyzing the data before it’s rendered.

client.onStreamsReceived((streams) => { myGameOverlay.onStreamsReceived(streams); });

onNotificationsReceived callback

Notifications transfer information as fast as possible and are not related to a timecode. They are described with the IDataNotifications() interface.

client.onNotificationsReceived((notifications) => { myGameOverlay.onNotificationsReceived(notifications); });

onDraw callback

The onDraw() callback specifies a routine to call regularly (generally 30 times per second) to draw the overlay:

client.onDraw((frame) => { myGameOverlay.onDraw(frame); });

When you invoke the onDraw() callback, it receives an genvidClient.IDataFrame() instance as a parameter containing the timecode for this video frame, the data coming from the different streams, and information about the video composition. The frame data is organized in the following ways:

  • If you have several sources of data, you can obtain it inside the sessions property, which exposes streams and annotations data for each session.
  • If you only have one stream, you can also access to the streams and annotations in the root of the IDataFrame instance.

Composition data (an array of genvidClient.ISourceCompositionData()) is information about what transformations were applied to the different video streams. Some of the ways you can use it include knowing what pixel of the video overlay matches which video source or to performing a clipping operation to prevent an overlay related to one video source overlaying another video.

Streams and annotation behave differently but are both described with the structure genvidClient.IDataStreamFrame().

The current streams contain only the latest frame for each while the annotations hold all of the previous frames accumulated so far and they will not get repeated next time.

Genvid carries data in binary form using the field rawdata, which is a JavaScript ArrayBuffer(). You can interpret the data in any way, but Genvid provides a few utility routines which can help decoding.

For example, if the game sends JSON data encoded as UTF-8, the website code needs to decode the rawdata binary field as UTF-8, and then parse that resulting string as JSON.

onDraw(frame) {
   let stream = frame.streams["position"]
   let datastr = genvid.UTF8ToString(frame.rawdata);
   stream.user = JSON.parse(datastr);

Because Genvid sometimes repeats data (for example, when a stream has a low framerate value), we include a mechanism for avoiding decoding identical data multiple times. The IGenvidClient() includes an onStreamsReceived() which passes a genvidClient.IDataStreams() collection upon reception of the data. The data streams contain a collection of video streams and their frames which you can modify before they get integrated into the Genvid synchronization engine. For example, parsing a collection to detect an upcoming event or removing the collection entirely.

You could also modify the function to decode differently based on the streamId, as long as you’re consistent with the format used when sending data from the game process (see Game-Data Streaming).

Once everything is ready in the game’s website code, you can start the GenvidClient streaming:


The IGenvidClient() automatically uses configured callbacks and handles synchronization between the streaming video and the game data sent in the onDraw().


While Genvid doesn’t provide a strict overlay API, it does expose everything necessary in the IGenvidClient() for the overlay to work. We also expose WebGL utility-routines which we use for all of our samples.

The main entry point to the overlay is the callback set using onDraw(). On regular intervals, the specified callback is invoked, with a frame of data for all streams existing in the game.

This callback receives the latest game-data frame for every stream. You have full control of what to do with that data: render some 3D highlights in a WebGL canvas, tweak HTML elements to display current game stats, adjust button visibility to allow new game events from the spectator, etc.

To facilitate WebGL rendering, Genvid provides a genvidWebGL.IWebGLContext() class which simplifies repetitive tasks in WebGL. You can create it with the genvidWebGL.createWebGLContext() method.


You can send events back to the Genvid Services through the IGenvidClient() instance. See sendEvent() and sendEventObject() for more information.