---
title: "Creating Custom Views"
canonical_url: "https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/custom-views/overview"
markdown_url: "https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/custom-views/overview.md"
last_updated: "2026-03-23T13:02:40Z"
---

# Creating Custom Views

This section provides a simple tutorial on how to create custom views for data adapter integration in the Custom Bet widget.
You will learn how to implement the necessary callback functions to customize the display of data within the widget.
This section covers various view types including lists, grids, accordions, rows, and tabs, with examples and visual representations of each view.

To create custom views for data adapter integration, you need to implement the following functions:

- `getOffering` - function that provides the [OfferingResponse](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/data-adapter.md#offeringresponse) data to the widget.
- `calculate` - function that provides the [CalculateResponse](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/data-adapter.md#calculateresponse) data to the widget.

The main focus of this tutorial is the getOffering function (specifically markets and metaMarkets) as it configures the views in the widget.
But calculate function is also needed to display markets in Custom Bet views.

```html
<script>
   (function (a, b, c, d, e, f, g, h, i) {
    a[e] || (i = a[e] = function () {
        (a[e].q = a[e].q || []).push(arguments)
    }, i.l = 1 * new Date, i.o = f,
        g = b.createElement(c), h = b.getElementsByTagName(c)[0], g.async = 1, g.src = d, g
       .setAttribute("n", e), h.parentNode.insertBefore(g, h)
    )
    })(window, document, "script",
    "https://master-cb.review.widgets.bets-stg.euc1.srcloud.io/betradarsolid/widgetloader", "SIR", {
    language: "en",
    oddsType: "eu" // eu, uk, us is accepted
    });

    SIR("addWidget", ".sr-widget", "customBet", {
    matchId: 123,
    dataProvider: 'custom',
    dataProviderConfig: {
        getOffering,
        calculate,
        addToBetslip
    }
    });
</script>
<div id="sr-widget"></div>
```

We will start with the simplest views and build up to the more complex ones.

## getOffering

The **getOffering** function is used to provide the OfferingResponse data to the widget. This data is used to configure the views in the Custom Bet widget.

**List, grid** and **accordion** are base views that can be used to create more complex views like **rows** and **tabs**. **Rows** are combinations of base views, and **tabs** are combinations of rows and base views.

A custom icon can be provided for each market (in **markets** or **metaMarkets** array) and it will be displayed in the market list in the category tab. If a custom icon is not provided, the default icon will be shown.

- #### Markets

  The **base views** are configured in the `markets` array.
  The `markets` array is described in detail with examples here: [Markets](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/custom-views/markets.md)

- #### Meta markets

  The **rows** and **tabs** are configured in the `metaMarkets` array.
  The `metaMarkets` array is described in detail with examples here: [Meta Markets](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/custom-views/meta-markets.md)

- #### Market categories

  The `markets` and `metaMarkets` are then displayed in custom categories, defined in the `marketCategories` array.
  The `marketCategories` array is described in detail with examples here: [Market Categories](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/custom-views/market-categories.md)

- #### Match name & Teams

  The additional info about match used in Custom Bet view is provided in the `matchName` and `teams` fields.
  The `matchName` & `teams` fields are described in detail with example here: [Match Name & Teams](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/custom-views/match-name.md)

## Calculate

- #### Calculation markets

  The available markets are configured in the `cbMarkets` array.
  The `cbMarkets` array is described in detail with example here: [CalculationMarket](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/data-adapter.md#calculationmarket)

- #### Odds

  The current **odds** calculated based on `selectedOutcomes` and provided in `odds` field.
  The `odds` field is described in detail with example here: [Odds](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/custom-views/odds.md)

If you followed all the examples linked above, you should have the following data structure:

```javascript
function getOffering(data, callback) {
  callback(undefined, {
    matchName: "PSG vs Monaco",
    teams: { home: "PSG", away: "Monaco" },
    marketCategories: [
      {
        id: "main",
        name: "Highlights",
        cbCategoryItems: ["oneXtwo", "total"],
      },
      {
        id: "players",
        name: "Players",
        cbCategoryItems: ["playerPasses", "shots"],
      },
    ],
    metaMarkets: [
      {
        id: "playerPasses",
        name: "Player passes",
        status: {
          isActive: true,
        },
        marketList: ["homeTeamPlayerPasses", "awayTeamPlayerPasses"],
        cbViewLayout: "tabs",
      },
      {
        id: "homeTeamPlayerPasses",
        name: "PSG",
        status: {
          isActive: true,
        },
        marketList: ["passes:playerId=333", "passes:playerId=444"],
        cbViewLayout: "rows",
      },
      {
        id: "awayTeamPlayerPasses",
        name: "Monaco",
        status: {
          isActive: true,
        },
        marketList: ["passes:playerId=111", "passes:playerId=222"],
        cbViewLayout: "rows",
      },
    ],
    markets: [
      {
        id: "oneXtwo",
        name: "3 Way",
        status: {
          isActive: true,
        },
        outcomes: [
          {
            id: "1",
            name: "PSG",
            status: {
              isActive: true,
            },
          },
          {
            id: "2",
            name: "draw",
            status: {
              isActive: true,
            },
          },
          {
            id: "3",
            name: "Monaco",
            status: {
              isActive: true,
            },
          },
        ],
        iconUrl:
          "https://cdn-icons-png.flaticon.com/512/4768/4768606.png",
      },
      {
        id: "total",
        name: "Total goals",
        status: {
          isActive: true,
        },
        srMarketLayout: "grid",
        outcomes: [
          {
            id: "10",
            name: "0.5",
            status: {
              isActive: true,
            },
            cbColumn: "under",
          },
          {
            id: "11",
            name: "0.5",
            status: {
              isActive: true,
            },
            cbColumn: "over",
          },
        ],
      },
      {
        id: "shots",
        name: "Player shots on goal",
        status: {
          isActive: true,
        },
        srMarketLayout: "accordion",
        outcomes: [
          {
            id: "20",
            name: "1",
            status: {
              isActive: true,
            },
            cbAccordionName: "Achraf Hakimi",
          },
          {
            id: "21",
            name: "3",
            status: {
              isActive: true,
            },
            cbAccordionName: "Achraf Hakimi",
          },
          {
            id: "23",
            name: "2",
            status: {
              isActive: true,
            },
            cbAccordionName: "Ousmane Dembélé",
          },
          {
            id: "24",
            name: "4",
            status: {
              isActive: true,
            },
            cbAccordionName: "Ousmane Dembélé",
          },
        ],
        iconUrl:
          "https://cdn-icons-png.flaticon.com/512/1107/1107163.png",
      },
      {
        id: "passes:playerId=111",
        name: "Takumi Minamino",
        status: {
          isActive: true,
        },
        srMarketLayout: "grid",
        outcomes: [
          {
            id: "10",
            name: "43.5",
            status: {
              isActive: true,
            },
            cbColumn: "under",
          },
          {
            id: "11",
            name: "43.5",
            status: {
              isActive: true,
            },
            cbColumn: "over",
          },
        ],
      },
      {
        id: "passes:playerId=222",
        name: "Breel Embolo",
        status: {
          isActive: true,
        },
        srMarketLayout: "grid",
        outcomes: [
          {
            id: "10",
            name: "43.5",
            status: {
              isActive: true,
            },
            cbColumn: "under",
          },
          {
            id: "11",
            name: "43.5",
            status: {
              isActive: true,
            },
            cbColumn: "over",
          },
        ],
      },
      {
        id: "passes:playerId=333",
        name: "Bradley Barcola",
        status: {
          isActive: true,
        },
        srMarketLayout: "grid",
        outcomes: [
          {
            id: "10",
            name: "43.5",
            status: {
              isActive: true,
            },
            cbColumn: "under",
          },
          {
            id: "11",
            name: "43.5",
            status: {
              isActive: true,
            },
            cbColumn: "over",
          },
        ],
      },
      {
        id: "passes:playerId=444",
        name: "Ousmane Dembélé",
        status: {
          isActive: true,
        },
        srMarketLayout: "grid",
        outcomes: [
          {
            id: "10",
            name: "43.5",
            status: {
              isActive: true,
            },
            cbColumn: "under",
          },
          {
            id: "11",
            name: "43.5",
            status: {
              isActive: true,
            },
            cbColumn: "over",
          },
        ],
      },
    ],
  });
}


function calculate(data, callback) {
  callback(undefined, {
    cbMarkets: [
      {
        id: "oneXtwo",
        status: {
          isActive: true,
        },
        outcomes: [
          {
            id: "1",
            status: {
              isActive: true,
            },
          },
          {
            id: "2",
            status: {
              isActive: true,
            },
          },
          {
            id: "3",
            status: {
              isActive: true,
            },
          },
        ],
      },
      {
        id: "total",
        status: {
          isActive: true,
        },
        outcomes: [
          {
            id: "10",
            status: {
              isActive: true,
            },
          },
          {
            id: "11",
            status: {
              isActive: true,
            },
          },
        ],
      },
      {
        id: "shots",
        status: {
          isActive: true,
        },
        outcomes: [
          {
            id: "20",
            status: {
              isActive: true,
            },
          },
          {
            id: "21",
            status: {
              isActive: true,
            },
          },
          {
            id: "22",
            status: {
              isActive: true,
            },
          },
          {
            id: "23",
            status: {
              isActive: true,
            },
          },
          {
            id: "24",
            status: {
              isActive: true,
            },
          },
        ],
      },
      {
        id: "playerPasses",
        status: {
          isActive: true,
        },
        outcomes: [],
      },
      {
        id: "passes:playerId=111",
        status: {
          isActive: true,
        },
        outcomes: [
          {
            id: "10",
            status: {
              isActive: true,
            },
          },
          {
            id: "11",
            status: {
              isActive: true,
            },
          },
        ],
      },
      {
        id: "passes:playerId=222",
        status: {
          isActive: true,
        },
        outcomes: [
          {
            id: "10",
            status: {
              isActive: true,
            },
          },
          {
            id: "11",
            status: {
              isActive: true,
            },
          },
        ],
      },
      {
        id: "passes:playerId=333",
        status: {
          isActive: true,
        },
        outcomes: [
          {
            id: "10",
            status: {
              isActive: true,
            },
          },
          {
            id: "11",
            status: {
              isActive: true,
            },
          },
        ],
      },
      {
        id: "passes:playerId=444",
        status: {
          isActive: true,
        },
        outcomes: [
          {
            id: "10",
            status: {
              isActive: true,
            },
          },
          {
            id: "11",
            status: {
              isActive: true,
            },
          },
        ],
      },
    ],
    odds: "1.59",
  });
}
```
