---
title: "Migrating from UOF Proxy to Stock"
canonical_url: "https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/migrate-uof-proxy-to-stock"
markdown_url: "https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/migrate-uof-proxy-to-stock.md"
last_updated: "2026-10-22T13:00:29Z"
---

# Migrating from UOF Proxy to Stock

This guide helps you move an existing Custom Bet integration from **`dataProvider: 'uofProxy'`** to **`dataProvider: 'stock'`**. For the target integration model, see [Stock Provider](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/stock.md). For legacy UOF Proxy behaviour, see [UOF Proxy (Deprecated)](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/uof-proxy.md).

## Why migrate

`uofProxy` is **deprecated** and not offered for new integrations. The stock provider:

- Removes the need for a **client-side proxy** that forwards UOF custom bet XML to the widget.
- Stops the widget from calling your page every **30 seconds** for `getFixture`, `getMarkets`, `getAvailableMarkets`, `calculate`, and `getProfile`.
- Moves offering, calculation, fixture, market descriptions, and competitor profiles to **Sportradar-hosted services** called directly by the widget.
- Keeps your integration surface to **`jwt`**, **`matchId`**, and **`addToBetSlip`** (plus existing display and theming props).

You can decommission UOF proxy routes used only for Custom Bet once migration is complete. Keep UOF feed access if other products still depend on it.

## Before you start

Confirm with Sportradar **client setup** that your **RSA public key** is **submitted and published** for JWT validation (the same onboarding step as other widget JWT integrations). See [JWT prerequisites](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/jwt.md#prerequisites-one-time-setup).

Implement a **backend endpoint** that issues a short-lived **JWT** for the current user or session, and pass it to the widget as the `jwt` prop. A JWT is a signed token (see [what a JWT is](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/jwt.md#what-a-jwt-is)) — not a static API secret. You sign it on your backend with your RSA private key (**RS256**). See [JWT authentication (Stock Provider)](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/jwt.md) for the full flow and signing guidance.

Use the same **`matchId`** values and event coverage as today. Coverage rules are unchanged; only the data path changes.

Plan a **staging validation** on at least one match with custom bet markets before you remove the proxy in production.

## What changes

| Area                                                   | UOF Proxy (`uofProxy`)                                                                                                                                      | Stock (`stock`)                                                                                                                                    |
| ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `dataProvider`                                         | `'uofProxy'` (also the [API default](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/api.md) if omitted)                                   | Set explicitly to `'stock'`                                                                                                                        |
| `jwt`                                                  | Not used                                                                                                                                                    | **Required** on the widget — [JWT authentication](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/jwt.md)             |
| `dataProviderConfig`                                   | **`getFixture`**, **`getMarkets`**, **`getAvailableMarkets`**, **`calculate`**, **`getProfile`** (forward UOF XML from your proxy), plus **`addToBetSlip`** | **`addToBetSlip` only** — remove the five UOF callbacks; offering and calculation are handled inside the widget via Sportradar custom bet services |
| `dataProviderConfig.addToBetSlip`                      | Required; you validate and add to bet slip                                                                                                                  | **Same contract** — see [addToBetSlip](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/overview.md#addtobetslip)      |
| UOF proxy / API key on your infra                      | Required so the five UOF callbacks can reach UOF                                                                                                            | Not required for Custom Bet widget traffic                                                                                                         |
| Display mode, market filters, theming, `dbg`, timeouts | Supported                                                                                                                                                   | **Unchanged**                                                                                                                                      |

## Step-by-step

### 1. Add JWT issuance on your backend

This is the main new piece when leaving UOF Proxy.

1. **One-time:** Generate your key pair, send **`rsa-public.pem`** to Sportradar, and wait until client setup confirms the public key is **published** for your bookmaker — [JWT prerequisites](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/jwt.md#prerequisites-one-time-setup).
2. **Per session:** After the user logs in, your frontend calls your backend (for example `GET /api/custom-bet/jwt`).
3. **Sign server-side:** Sign a short-lived token with **RS256** using your private key — [Sign tokens on your backend](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/jwt.md#sign-tokens-on-your-backend).
4. **Return** the token string to the browser and set it on `addWidget` as `jwt`.
5. **Refresh** when the token expires; missing or expired tokens produce widget errors or 401/403 from custom bet services.

If you already issue JWTs for Live Match Tracker, Virtual Stadium, or Bet Concierge, reuse the same key infrastructure where client setup allows (see [JWT prerequisites](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/jwt.md#prerequisites-one-time-setup)).

### 2. Update the widget configuration

Change `dataProvider` to `'stock'`, add `jwt`, and reduce `dataProviderConfig` to `addToBetSlip` only. See [Before and after](#before-and-after) below.

### 3. Remove UOF proxy callbacks

Delete `getFixture`, `getMarkets`, `getAvailableMarkets`, `calculate`, and `getProfile` from your page bundle, along with any shared fetch helpers that called your proxy with the UOF API key.

Keep **`addToBetSlip`** and your bet slip validation logic. Follow [Handling Selections and Odds](https://apidocs.sportradar.com/resources/widgets/docs/tutorials/handling-selections-and-odds.md) for odds snapshots and rejection reasons.

### 4. Validate on staging

Load the widget with a real `matchId` and JWT. Confirm markets load, selections recalculate, and `addToBetSlip` succeeds or fails with the correct user-facing reasons.

### 5. Decommission the Custom Bet proxy

After all environments use stock, remove proxy routes and credentials that existed only to serve the five UOF callbacks for Custom Bet.

## Before and after

### Before (UOF Proxy)

```javascript
SIR("addWidget", ".sr-widget", "customBet", {
  matchId: 123456789,
  dataProvider: "uofProxy",
  dataProviderConfig: {
    getFixture,
    getMarkets,
    calculate,
    getAvailableMarkets,
    getProfile,
    addToBetSlip,
  },
});
```

Each of `getFixture`, `getMarkets`, `getAvailableMarkets`, `calculate`, and `getProfile` fetched UOF XML via your proxy and invoked `callback(false, xmlString)` or a [`CBError`](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/overview.md#cberror). See [UOF Proxy](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/uof-proxy.md) for full examples.

### After (Stock)

```javascript
SIR("addWidget", ".sr-widget", "customBet", {
  matchId: 123456789,
  dataProvider: "stock",
  jwt: getCustomBetJwt(), // short-lived token from your backend
  dataProviderConfig: {
    addToBetSlip,
  },
});

function getCustomBetJwt() {
  // Request from your server — do not hard-code secrets in the browser.
  return "...";
}
```

See [Stock Provider — Integration Example](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/stock.md#integration-example) for a complete HTML snippet.

## Behaviour differences to verify

- **Errors:** You no longer return [`CBError`](https://apidocs.sportradar.com/resources/widgets/docs/custom-bet/integration/overview.md#cberror) from UOF callbacks (types 1–3). Failures such as invalid or expired JWT, missing coverage, or service errors are handled inside the widget and Sportradar services. Test 401/403 by using an expired JWT.
- **Market labels:** Labels and translations come from Sportradar match and translation data (aligned with other widgets), not from XML you forwarded.
- **Polling:** The widget no longer invokes your five UOF functions on a 30-second refresh cycle; service traffic goes to Sportradar from the widget runtime.
- **Token lifetime:** When the JWT expires, refresh the token and re-initialize or update the widget according to your SPA pattern.
- **`addToBetSlip`:** Contract, `UniqueOutcome` shape, and `displayedOdds` semantics are unchanged.
