Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Table of Contents

Introduction

The BetVision product overlays contextual information, such as sports and betting information, inside the Genius Live Player. The goal of this document is to outline the following:

  • What native events the video player has to be able to listen to on mobile devices.

  • DMA enforcement and how this influences the user experience.

  • How the visuals inside the video player can be styled.

  • How the user can select a curated betting opportunity inside the video player and have the application betslip be populated with the selection or trigger placing a bet.

  • How Genius Sports can receive a curated list of live betting outcomes and their prices.

Integrating Player

For integrating the Genius Live player please follow the Genius Live Player Integration Guide Documentation.

Integrating Prices

Providing prices and markets for the overlays

In order to push prices from the bookmaker to Genius Sports so that prices and markets in overlays can be repriced, added and removed in seconds, we supply the OddsFeed Platform Ingestion API with this https://swaggerui.api.geniussports.com/?url=https://explorer.api.geniussports.com/OddsFeed-Ingestion%2Fv1%2FProduction%2Fswagger-latest.yaml.

As a new customer you need to receive

  1. an API key to push prices to the OddsFeed Platform Ingestion API

  2. a sourceId for your prices

Please confirm that Genius Sports is able to match all the markets (with sourceMarketId), that you wish to push to the OddsFeed Platform Ingestion API.

Handling Events

What is the Genius Sports message bus and how to integrate with it

The geniussportsmessagebus is a messaging bus used to communicate information from our video player to other components of an integrating application, typically not controlled by Genius Sports, with the necessary information to react to a specific event.

To listen to events from the messagebus, clients should bind an event listener to the window object, as shown below:

Code Block
window.addEventListener('geniussportsmessagebus', (event) => {
    if (typedEvent.detail.type = 'an-event-type') {
    ...
    } else if (typedEvent.detail.type === 'another-event-type') {
    ....
    }

The event type that is dispatched onto the window object is a CustomEvent (MDN docs).

Video player event 'player_ready'

The existing video player integration relies on the 'player_ready' event that the video player dispatches. This event is used to obtain a video streaming URL with an authentication token. All communication to and from the video player utilizes events.

...

Moved to https://dap-docs.betstream.betgenius

...

Betslip interaction based on 'multibet-event'

The existing video player integration relies on an event named 'player_ready'. Similarly, to facilitate interaction with the betslip, an event named 'multibet-event' needs to be consumed.

 

Code Block
window.addEventListener('geniussportsmessagebus', (event) => {
    if (typedEvent.detail.type = 'multibet-event') {
    ...
    } else if (typedEvent.detail.type === 'player_ready') {
    ....
    }

The ‘multibet-event' supports ‘addToBetslip’, ‘removeFromBetslip’, ‘placeBet’ and the 'openBetslip’ commands inside the body.

These commands are accessible in the body of the events raised by the video player.

Code Block
if (typedEvent.detail.type = 'multibet-event') {
        switch(typedEvent.detail.body.command) {
            case "addToBetslip":
            ...
            break;
            case 'removeFromBetslip':
            ...
            break;
            case "placeBet":
            ...
            break;
            case "openBetslip":
            ...
            break;
        }
} else ...
  

The data contained in the betslip command to "addToBetslip" | "removeFromBetslip" is structured as follows:

Code Block
interface BetslipEvent {
    command: "addToBetslip" | "removeFromBetslip",
    sportsbookFixtureId: string,
    marketId: string,
    sportsbookMarketId: string,
    sportsbookMarketContext: string,
    sportsbookSelectionId: string,
    decimalPrice: string,
    stake?: number //optional
}

The following is an example of the structure of these events:

Code Block
{
    "command": "addToBetslip",
    "sportsbookFixtureId": "56789",
    "marketId": "100120022",
    "sportsbookMarketId": "1234567",
    "sportsbookMarketContext": "ABCDE",
    "sportsbookSelectionId": "2132365",
    "decimalPrice": "1.66",
    "stake": undefined
}

The data contained in the betslip command to "placeBet" is structured as follows:

Code Block
interface BetslipEvent {
    command: "placeBet" ,
    markets: [ 
        {
            sportsbookFixtureId: string,
            marketId: string,
            sportsbookMarketId: string,
            sportsbookMarketContext: string,
            sportsbookSelectionId: string,
            decimalPrice: string,
            stake?: number //optional
        },
    ]
}

The following is an example of the structure of these events:

Code Block
{
  "command": "placeBet",
  "markets": [ 
    {
      "sportsbookFixtureId": "56789",
      "marketId": "100120022",
      "sportsbookMarketId": "1234567",
      "sportsbookMarketId: "",
      "sportsbookMarketContext": "ABCDE",
      "sportsbookSelectionId": "2132365",
      "decimalPrice": "1.66",
      "stake": undefined
    },
    {
      "sportsbookFixtureId": "56789",
      "marketId": "100120023",
      "sportsbookMarketId": "1234567",
      "sportsbookMarketContext": "ABCDE",
      "sportsbookSelectionId": "2132365",
      "decimalPrice": "1.32",
      "stake": undefined
    }
  ] 
}
  • sportsbookFixtureId - customer fixture ID

  • marketId - Genius Sports market ID

  • sportsbookMarketId - customer market ID

  • sportsbookMarketContext - customer market context. This field will be populated only if the customer provided it in UpdategramResponse

  • sportsbookSelectionId - customer selection ID

  • decimalPrice - the price that was displayed in the Multibet Widget when the player pressed the "Add to betslip" button. This value should NOT be used for bet acceptance.

  • An optional stake value which is can be one of the following values: a number, null, or undefined.

The data contained in the betslip command to "openBetslip" is structured as follows:

Code Block
interface BetslipEvent {
    command: "openBetslip"
}

The following is an example of the structure of these events:

Code Block
{
  "command": "openBetslip"
}

Tilting the native device and full screen

...

.

...

To enable the end user switching from a traditional betting page layout to overlaid full screen streaming the hosting mobile application has to raise an event through the hosting “webview” into the Genius Live Video player. This requires development work from the bookmaker

...

Sample code how to allow fullscreen mode and traditional betting view based on user device tilt actions can be found in this repository:

...

com

...

/

...

Restrictions

Geographic Restrictions

Geo location for DMA’s

After consulting with several customers, we have determined that customers often don't have easy access to the viewer DMA since the user identity component of the application is frequently outsourced to third-party providers. Genius Sports will perform region detection and blocking on the edge. If a user is not in a DMA where they can view a fixture, the video player will never dispatch the 'player_ready' event, and the player will not be visible. We would like to understand the preferred workflow from customers. If desired, Genius Sports can emit additional information about the user DMA to the hosting application.

Knowing in which DMA’s a fixture is viewable

An example DMA map where different fixtures are denoted by different colors. Viewers in the red and blue areas cannot watch the same fixture at the same time

...

We have made some additive changes to our Video API to indicate which DMA’s a fixture is available in. Notice the "dmas" : []field

Code Block
{
  "data": [
    {
      "id": 1300290721,
      "name": "Team A v Team B",
      "phase": "PRE_MATCH",
      "bookingStatus": "BOOKED",
      "startAt": "2021-07-29T13:00:00Z",
      "competitionId": "9530",
      "competitionName": "Test Comp",
      "sportId": 10,
      "sportName": "Football",
      "liveStreams": [
        {
          "id": "c8ed9f88",
          "permissions": [
                {
                    "device": "MOBILE",
                    "maxPlayerSizePercentage": 100,
                    "region": "US_CA"
                },
                {
                    "device": "TABLET",
                    "maxPlayerSizePercentage": 100,
                    "region": "US_CA"
                }
            ],
          "dmas": [
                {
                    "dma": "753"
                },
                {
                    "dma": "771"
                },
                {
                    "dma": "800"
                },
                {
                    "dma": "802"
                },
                {
                    "dma": "804"
                },
                {
                    "dma": "807"
                },
                {
                    "dma": "811"
                },
                {
                    "dma": "813"
                },
                {
                    "dma": "825"
                },
                {
                    "dma": "828"
                },
                {
                    "dma": "855"
                },
                {
                    "dma": "862"
                },
                {
                    "dma": "866"
                },
                {
                    "dma": "868"
                }
            ],
          "deliveries": {
            "hls": [
              {
                "id": "AKAMAI"
              }
            ],
            "dash": []
          }
        }
      ]
    }
  ]
}

Permitted Devices & Connectivity

  • CBS, FOX, NBC, ESPN/ABC and Amazon Games: Accessible on mobile phones and tablets, via wireless networks (e.g. 4G LTE, 5G) and WiFi.

  • NFL Network Games: Accessible solely on mobile phones via wireless networks and Wi-Fi.

Permitted Users

Limited to Active Bettors (as defined below) currently logged-in to the bookmaker account, and physically located in a state where betting on such account is legal and regulated.

Info

  “Active Bettor” means any registered user with an active betting account with the applicable operator (meaning such registered user
(A) has placed a bet with such operator within the immediately prior ten (10) months

and

(B) has (1) a payment mechanism (e.g., credit card) on file with such operator and/or (2) cash and/or credits available in such account to place wagers), and either of

(i) an active bet that includes the relevant Live Content being reviewed (e.g., a pre-match or in-play bet involving the Live Content or a player in the Live Content, including as part of a parlay bet); or

(ii) access to the Live Content for a promotional period if no bet has been placed (Genius and NFL shall have approval rights over the promotional period).

Use Restrictions

No simultaneous streams: Live Game streams must be limited to one stream at a time per Active Bettor account, i.e. No in-app multi-view.

...

Theming of video player controls

Documentation for Styling of the Genius Live player controls can be found here: https://dap-docs.betstream.betgenius.com/styling-genius-live-player.html

Theming the content in the video player

Genius Sports will take care of applying the desired themes to the overlays on behalf of customers. The theming of content will follow the same approach as outlined here.

Examples

An example of an Event listener loading the auth token and listening for betslip interaction

You need to have a listener to receive the events that the Multibet Widget will send when the player sends their bet in the "Add to betslip" action.

An example of how the code will look that listens to the video player events:

Code Block
window.addEventListener('geniussportsmessagebus', async (event: Event) => {
    let typedEvent = event as unknown as GeniusSportsEvent
    if (typedEvent.detail.type = 'multibet-event') {
        switch(typedEvent.detail.body.command) {
            case "addToBetslip":
            /**
             * {
             *             command: 'addToBetslip',
             *             sportsbookMarketContext: tradingPlatformMetadata,
             *             sportsbookFixtureId: tradingPlatformFixtureId,
             *             sportsbookMarketId: tradingPlatformId,
             *             marketId: id,
             *             decimalPrice: totalOdds
             *           }
             */
             break;
             case "removeFromBetslip":
             break;
            case "placeBet":
            /**
             *  {
             *             command: 'placeBet',
             *             sportsbookMarketContext: tradingPlatformMetadata,
             *             sportsbookFixtureId: tradingPlatformFixtureId,
             *             sportsbookMarketId: tradingPlatformId,
             *             marketId: id,
             *             decimalPrice: totalOdds,
             *             stake: 100
             *           }
             */
        }
    } else if (typedEvent.detail.type === 'player_ready') {
        const playerReadyEvent = typedEvent as PlayerReadyEvent
        const deliveryType = playerReadyEvent.detail.body.deliveryType
        const streamId = playerReadyEvent.detail.body.streamId
        const deliveryId = playerReadyEvent.detail.body.deliveryId
        const geniusSportsFixtureId = playerReadyEvent.detail.body.geniusSportsFixtureId
        const dataToPost = {
            endUserSessionId: document.cookie, //user session id
            region: 'CO', //region
            device: 'DESKTOP', //device
        }
        postData(
            `${domain}/v3/fixtures/${geniusSportsFixtureId}/live-streams/${streamId}/deliveries/${deliveryType}/${deliveryId}`,
            dataToPost
        )
            .then((data) => {
                console.log('Token data arrived', JSON.stringify(data))
                // @ts-ignore
                GeniusLivePlayer.player.start(data)
            })
            .catch((error) => {
                console.error(error)
            })
    }
})

async function postData(url = '', data = { }) {
    // Default options are marked with *
    const response = await fetch(url, {
        method: 'POST', // *GET, POST, PUT, DELETE, etc.
        mode: 'cors', // no-cors, *cors, same-origin
        cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
        credentials: 'include', // include, *same-origin, omit
        headers: {
            'Content-Type': 'application/json',
        },
        redirect: 'follow', // manual, *follow, error
        referrerPolicy: 'no-referrer',
        body: JSON.stringify(data),
    })

    return response.json()
}

Checklist

Checklist for Bookmaker client

Betting prices and markets

Push prices
  •  Received an API key to push prices to the Odds ingestion API.
  •  Received a Source ID for our prices.
  •  Genius Sports has confirmed to be able to match all the markets we as bookmaker wish to push.

Video Player and Front End

  •  We have integrated the normal video player.
  •  We have added the extra event handlers for listening to the “Add to Betslip” event.
  •  We have supplied the styling information for the overlays.