---
title: "Web Integration Guide"
canonical_url: "https://apidocs.sportradar.com/resources/sport-sdk/docs/integration/web"
markdown_url: "https://apidocs.sportradar.com/resources/sport-sdk/docs/integration/web.md"
last_updated: "2026-06-10T08:48:04Z"
---

# Web Integration Guide

This guide covers the JavaScript / TypeScript API exposed by the generated `sport-sdk` package.

The most important integration details for Web are:

- initialize the SDK before fetching data
- use `CommonResult<T>` (`data`, `errorMessage`, `isSuccess`)
- convert Kotlin `KtList` values to JS arrays when needed
- use `bigint` for most domain identifiers (`sportId`, `seasonId`, `matchId`, ...)

Reference implementation:

- `jsApp/`
- generated package typings in `build/js/packages/sport-sdk/kotlin/sport-sdk.d.mts`

> **Quick start**
>
> Install `sport-sdk`, call `SportSdkJs.init(...)` once with `clientId`, `appKey`, and `appIdentifier`, then verify the setup with `SportSdkJs.getSports()`.

**TypeScript**

```ts
import { ClientConfig, SportSdkJs } from 'sport-sdk';

const initialized = await SportSdkJs.init(
  new ClientConfig(
    YOUR_CLIENT_ID,
    'YOUR_APP_KEY',
    'com.example.webapp',
    undefined,
    false,
  ),
);

if (!initialized) {
  throw new Error('Sport SDK failed to initialize');
}

const sports = (await SportSdkJs.getSports()).data?.asJsReadonlyArrayView() ?? [];
console.log(`Loaded ${sports.length} sports`);
```

**JavaScript**

```js
import { ClientConfig, SportSdkJs } from 'sport-sdk';

const ok = await SportSdkJs.init(
  new ClientConfig(YOUR_CLIENT_ID, 'YOUR_APP_KEY', 'com.example.webapp', undefined, false)
);

if (!ok) {
  throw new Error('SDK initialization failed');
}

const sports = (await SportSdkJs.getSports()).data?.asJsReadonlyArrayView() ?? [];
console.log(sports.map((sport) => sport.name));
```

## Start here

### Install

Use your team’s npm distribution channel or a locally packed `.tgz` during repository development.

### Initialize

Call `SportSdkJs.init(...)` before any data request and wait for the promise to resolve.

### Normalize

Convert `KtList<T>` values with `asJsReadonlyArrayView()` at your app boundary.

### Keep IDs precise

Most domain identifiers are `bigint`, not `number`.

## Prerequisites

> **Web requirements**
>
> - a modern ESM-capable toolchain
> - browser/runtime support for `BigInt`
> - Sportradar credentials: `clientId`, `appKey`, `appIdentifier`
>
> Type expectations:
>
> - `clientId` = `number`
> - most sports-data IDs = `bigint`

## Installation

**Private npm package**

If your team consumes a published package, install `sport-sdk` from your configured npm registry.

```bash
npm install sport-sdk
```

**Local package from this repository**

This repository includes a local workflow for producing a `.tgz` package.

Build and pack it:

```zsh
cd /Users/k.gabersek/Documents/Development/Sportradar/Android/Sport-SDK
./gradlew clean sport-sdk:assembleJsPackage sport-sdk:packJsPackage
```

Then install the generated tarball in your app:

```json
{
  "dependencies": {
    "sport-sdk": "file:../sport-sdk/build/packages/<generated-package>.tgz"
  }
}
```

This is the same local-dev flow used by `jsApp/run.sh`.

> **Note**
>
> If the package is hosted in a private GitLab/npm registry, configure your `.npmrc` according to your organization’s release instructions before running `npm install`.

## Quick start

**TypeScript**

```ts
import { ClientConfig, SportSdkJs } from 'sport-sdk';

const initialized = await SportSdkJs.init(
  new ClientConfig(
    YOUR_CLIENT_ID,
    'YOUR_APP_KEY',
    'com.example.webapp',
    undefined,
    false,
  ),
);

if (!initialized) {
  throw new Error('Sport SDK failed to initialize');
}

const result = await SportSdkJs.getSports();

if (result.isSuccess) {
  const sports = result.data?.asJsReadonlyArrayView() ?? [];
  console.log(`Loaded ${sports.length} sports`);
} else {
  console.error(result.errorMessage);
}
```

**Vanilla JavaScript**

```js
import { ClientConfig, SportSdkJs } from 'sport-sdk';

const ok = await SportSdkJs.init(
  new ClientConfig(YOUR_CLIENT_ID, 'YOUR_APP_KEY', 'com.example.webapp', undefined, false)
);

if (!ok) {
  throw new Error('SDK initialization failed');
}

const result = await SportSdkJs.getSports();
const sports = result.data?.asJsReadonlyArrayView() ?? [];
console.log(sports.map((sport) => sport.name));
```

## Understanding the Web API shape

### `CommonResult<T>`

Every SDK call returns a result wrapper. Always inspect:

- `result.isSuccess`
- `result.data`
- `result.errorMessage`

### `KtList<T>`

SDK lists are Kotlin collections, not plain JS arrays. Convert them with `asJsReadonlyArrayView()`.

### `bigint`

Most domain IDs are `bigint`. Keep them that way unless you are certain downcasting is safe.

### `KtList<T>` conversion examples

```ts
const sports = result.data?.asJsReadonlyArrayView() ?? [];
const categories = sport.categories.asJsReadonlyArrayView();
const tournaments = category.tournaments.asJsReadonlyArrayView();
const matches = tournament.matches.asJsReadonlyArrayView();
```

### `bigint` examples

```ts
const sportId = 1n;
const seasonId = 123456789n;
const matchId = 987654321n;
```

> **Warning**
>
> If you serialize these IDs, remember that `JSON.stringify()` does not support `bigint` directly without conversion.

## Available methods

| Method                                                     | Returns                                          |
| ---------------------------------------------------------- | ------------------------------------------------ |
| `SportSdkJs.getSports()`                                   | `Promise<CommonResult<KtList<Sport>>>`           |
| `SportSdkJs.getSportCategories(sportId)`                   | `Promise<CommonResult<KtList<Sport>>>`           |
| `SportSdkJs.getSportMatchesForDate(timestamp)`             | `Promise<CommonResult<KtList<Sport>>>`           |
| `SportSdkJs.getTournamentSeasons(uniqueTournamentId)`      | `Promise<CommonResult<KtList<Season>>>`          |
| `SportSdkJs.getSeasonStanding(seasonId, isCurrentSeason?)` | `Promise<CommonResult<Standings>>`               |
| `SportSdkJs.getSeasonFixtures(seasonId, isCurrentSeason?)` | `Promise<CommonResult<KtList<Match>>>`           |
| `SportSdkJs.getMatchStatistics(matchId)`                   | `Promise<CommonResult<KtList<MatchStatistics>>>` |
| `SportSdkJs.getMatchLineups(matchId)`                      | `Promise<CommonResult<MatchLineups>>`            |
| `SportSdkJs.getSoccerMatchTimelineEvents(matchId)`         | `Promise<CommonResult<KtList<SoccerEvent>>>`     |
| `SportSdkJs.getTeamSquad(teamId, seasonId)`                | `Promise<CommonResult<TeamSquad>>`               |

Top-level function exports also exist, for example:

- `topLvlGetSportsList()`
- `topLvlGetSportMatchesForDate(timestamp)`
- `topLvlGetTournamentSeasons(uniqueTournamentId)`

## Sports feed example

```ts
import { SportSdkJs } from 'sport-sdk';

export async function loadSports(): Promise<void> {
  const result = await SportSdkJs.getSports();

  if (!result.isSuccess) {
    console.error('Error loading sports:', result.errorMessage);
    return;
  }

  const sports = result.data?.asJsReadonlyArrayView() ?? [];

  for (const sport of sports) {
    const categories = sport.categories.asJsReadonlyArrayView();
    console.log(`${sport.name}: ${categories.length} categories`);
  }
}
```

## Seasons, standings, fixtures, and squad

**Season data**

```ts
const seasonsResult = await SportSdkJs.getTournamentSeasons(uniqueTournamentId);
const standingsResult = await SportSdkJs.getSeasonStanding(seasonId, true);
const fixturesResult = await SportSdkJs.getSeasonFixtures(seasonId, true);

const seasons = seasonsResult.data?.asJsReadonlyArrayView() ?? [];
const fixtures = fixturesResult.data?.asJsReadonlyArrayView() ?? [];
const standings = standingsResult.data;
```

**Squad data**

```ts
const squadResult = await SportSdkJs.getTeamSquad(teamId, seasonId);
const squad = squadResult.data;
```

Type reminders:

- `uniqueTournamentId`: `bigint`
- `seasonId`: `bigint`
- `teamId`: `number`

## Match details

```ts
const statisticsResult = await SportSdkJs.getMatchStatistics(matchId);
const lineupsResult = await SportSdkJs.getMatchLineups(matchId);
const timelineResult = await SportSdkJs.getSoccerMatchTimelineEvents(matchId);

const statistics = statisticsResult.data?.asJsReadonlyArrayView() ?? [];
const lineups = lineupsResult.data;
const timeline = timelineResult.data?.asJsReadonlyArrayView() ?? [];
```

## Framework examples

**### Angular service example**

```ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { ClientConfig, SportSdkJs, Sport } from 'sport-sdk';

@Injectable({ providedIn: 'root' })
export class SportSdkService {
  private readonly sportsSubject = new BehaviorSubject<readonly Sport[]>([]);
  readonly sports$ = this.sportsSubject.asObservable();

  async initialize(): Promise<boolean> {
    return SportSdkJs.init(
      new ClientConfig(YOUR_CLIENT_ID, 'YOUR_APP_KEY', 'com.example.angular', undefined, false)
    );
  }

  async loadSports(): Promise<void> {
    const result = await SportSdkJs.getSports();

    if (!result.isSuccess) {
      throw new Error(result.errorMessage ?? 'Failed to load sports');
    }

    this.sportsSubject.next(result.data?.asJsReadonlyArrayView() ?? []);
  }
}
```

```ts
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { SportSdkService } from './sport-sdk.service';

export function initializeSdk(service: SportSdkService) {
  return () => service.initialize();
}

@NgModule({
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: initializeSdk,
      deps: [SportSdkService],
      multi: true,
    },
  ],
})
export class AppModule {}
```

## Environment configuration

**### Keep credentials in one config object**

```ts
export const environment = {
  production: false,
  sportSdk: {
    clientId: YOUR_CLIENT_ID,
    appKey: 'YOUR_APP_KEY',
    appIdentifier: 'com.example.webapp',
  },
};
```

```ts
const config = new ClientConfig(
  environment.sportSdk.clientId,
  environment.sportSdk.appKey,
  environment.sportSdk.appIdentifier,
  undefined,
  false,
);
```

## Best practices

### Initialize before rendering data screens

Whether you use Angular, React, Vue, or vanilla JS, wait for `SportSdkJs.init(...)` before making controller calls.

### Normalize `KtList` at your app boundary

Convert SDK collections to plain arrays once, then pass arrays through your UI state/store.

### Keep `bigint` IDs as `bigint`

Do not downcast IDs to `number` unless you are certain precision is safe.

### Use milliseconds for date queries

`getSportMatchesForDate(timestamp)` expects milliseconds since epoch.

> **Tip**
>
> Always inspect `errorMessage`. An empty result without error handling is the most common cause of confusing “nothing rendered” states.

## Troubleshooting

**### TypeScript says a list is not iterable**

You are probably working with `KtList<T>`. Convert it first:

```ts
const items = result.data?.asJsReadonlyArrayView() ?? [];
```

**### TypeScript rejects `number` IDs**

Use `bigint` literals for domain IDs:

```ts
const matchId = 123456789n;
```

**### SDK initializes but no data appears**

Check:

1. `result.errorMessage`
2. package credentials / registry access
3. timestamp units (milliseconds)
4. that initialization completed before the request fired

**### Browser/build issues with `BigInt`**

Make sure your target runtime and bundler output support ES2020+ `BigInt`.

**### Package not found**

Check:

1. `npm list sport-sdk`
2. your `.npmrc` / registry auth
3. local `.tgz` path if using a file dependency
