@pythiasport/betting-widget
v1.1.2
Published
TypeScript SDK for embedding Pythia betting widget
Downloads
272
Maintainers
Readme
@pythiasport/betting-widget
A modern, framework-agnostic TypeScript SDK for embedding the Pythia betting widget into any web application.
Features
- ✅ TypeScript-first with full type safety
- 🎯 Framework-agnostic - works with React, Vue, Angular, or vanilla JS
- 🎨 Theme support with dark/light modes
- 📡 Event-driven architecture using EventEmitter pattern
- 🔒 Type-safe APIs with comprehensive JSDoc documentation
- 📦 Multiple build formats - ESM, CommonJS, and UMD/IIFE
- 🎪 Zero dependencies in runtime
Installation
npm install @pythiasport/betting-widgetyarn add @pythiasport/betting-widgetpnpm add @pythiasport/betting-widgetQuick Start
1. Add container to your HTML
<div id="betting-widget-container"></div>2. Initialize the SDK
import { PythiaSDK } from '@pythiasport/betting-widget';
const sdk = new PythiaSDK();
// Listen to events
sdk.on('betslip:open', () => {
console.log('Betslip opened!');
});
sdk.on('ready', () => {
console.log('Widget is ready!');
});
// Initialize with configuration
sdk.init({
tenantId: 'your-tenant-id',
jwtToken: 'user-jwt-token',
userId: 'user-123',
currencyCode: 'USD',
currencySymbol: '',
theme: 'dark',
style: 'width: 100%; height: 100%; border: none;',
onLoginRequest: () => {
// Handle login request
console.log('User needs to login');
}
});Framework Integration
React
import { useEffect, useRef } from 'react';
import { PythiaSDK } from '@pythiasport/betting-widget';
function BettingWidget() {
const sdkRef = useRef<PythiaSDK | null>(null);
useEffect(() => {
const sdk = new PythiaSDK();
sdkRef.current = sdk;
sdk.on('betslip:open', () => {
console.log('Betslip opened');
});
sdk.init({
tenantId: 'your-tenant-id',
jwtToken: 'user-token',
userId: 'user-123',
currencyCode: 'USD',
currencySymbol: '',
theme: 'dark',
});
return () => {
sdk.destroy();
};
}, []);
const handleThemeToggle = () => {
sdkRef.current?.setTheme('light');
};
return (
<div>
<button onClick={handleThemeToggle}>Toggle Theme</button>
<div id="betting-widget-container" />
</div>
);
}Vue 3
<template>
<div>
<button @click="toggleTheme">Toggle Theme</button>
<div id="betting-widget-container"></div>
</div>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue';
import { PythiaSDK } from '@pythiasport/betting-widget';
const sdk = ref<PythiaSDK | null>(null);
onMounted(() => {
const instance = new PythiaSDK();
sdk.value = instance;
instance.on('betslip:open', () => {
console.log('Betslip opened');
});
instance.init({
tenantId: 'your-tenant-id',
jwtToken: 'user-token',
userId: 'user-123',
currencyCode: 'USD',
currencySymbol: '',
theme: 'dark',
});
});
onUnmounted(() => {
sdk.value?.destroy();
});
const toggleTheme = () => {
sdk.value?.setTheme('light');
};
</script>Angular
import { Component, OnInit, OnDestroy } from '@angular/core';
import { PythiaSDK } from '@pythiasport/betting-widget';
@Component({
selector: 'app-betting-widget',
template: `
<div>
<button (click)="toggleTheme()">Toggle Theme</button>
<div id="betting-widget-container"></div>
</div>
`
})
export class BettingWidgetComponent implements OnInit, OnDestroy {
private sdk: PythiaSDK | null = null;
ngOnInit() {
this.sdk = new PythiaSDK();
this.sdk.on('betslip:open', () => {
console.log('Betslip opened');
});
this.sdk.init({
tenantId: 'your-tenant-id',
jwtToken: 'user-token',
userId: 'user-123',
currencyCode: 'USD',
currencySymbol: '',
theme: 'dark',
});
}
ngOnDestroy() {
this.sdk?.destroy();
}
toggleTheme() {
this.sdk?.setTheme('light');
}
}Vanilla JavaScript (UMD)
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/@pythiasport/betting-widget@latest/dist/index.global.js"></script>
</head>
<body>
<div id="betting-widget-container"></div>
<script>
const sdk = new PythiaSDK.PythiaSDK();
sdk.on('betslip:open', function() {
console.log('Betslip opened');
});
sdk.init({
tenantId: 'your-tenant-id',
jwtToken: 'user-token',
userId: 'user-123',
currencyCode: 'USD',
currencySymbol: ',
theme: 'dark'
});
</script>
</body>
</html>API Reference
Constructor
const sdk = new PythiaSDK();Methods
init(options: PythiaSDKOptions): void
Initializes the SDK with configuration options.
Parameters:
tenantId(string, required) - Unique identifier for the tenantjwtToken(string, required) - JWT token for authenticationuserId(string, required) - User identifiercurrencyCode(string, required) - ISO currency code (e.g., 'USD', 'EUR')currencySymbol(string, required) - Currency symbol (e.g., ', '€')style(string, optional) - CSS styles for the iframetheme('light' | 'dark', optional) - Initial theme (default is 'dark')bettingAppUrl(string, optional) - URL of the betting applicationoddsFormat('decimal' | 'fractional' | 'moneyline', optional) - a parameter that defines which price format should be used (default is 'decimal').language(optional) - the interface language, specified as a country/language code (e.g. 'en', 'de'; default is 'en').timeFormat('24h' | '12h', optional) - the time display format (default is '24h').userLocation('string', optional) - The user’s location in country code format is used to display only the streams available for that specific location. If this parameter is not provided, all streams will be displayed, but not all of them will be playable. (e.g. 'US', 'DE').onLoginRequest(function, optional) - Callback when login is requested
updateUserInfo(userInfo: UserInfo): void
Updates user authentication information after login/logout.
sdk.updateUserInfo({
jwtToken: 'new-jwt-token',
userId: 'user-123',
currencyCode: 'EUR',
currencySymbol: '€'
});It can be used to change the price type and the time format.
sdk.updateUserInfo({
timeFormat: '12h',
oddsFormat: 'moneyline'
});setTheme(theme: 'light' | 'dark'): void
Changes the widget theme.
sdk.setTheme('dark');setLanguage(theme: string): void
Changes the widget language.
sdk.setLanguage('en');notifyScrollChange(scrollY: number, scrollX?: number): void
Manually notifies the iframe of scroll position changes.
sdk.notifyScrollChange(window.scrollY);setBetslipButtonOffset(offset: BetslipButtonOffset): void
Sets the offset for betslip floating button positioning.
sdk.setBetslipButtonOffset({
top: 80, // pixels from top
bottom: 20 // pixels from bottom
});destroy(): void
Destroys the SDK instance and cleans up all resources.
sdk.destroy();getIsInitialized(): boolean
Checks if the SDK is initialized.
if (sdk.getIsInitialized()) {
// SDK is ready
}Events
The SDK uses an EventEmitter pattern for all events. Use on(), once(), and off() methods.
Event Types
betslip:open- Emitted when the betslip is openedbetslip:close- Emitted when the betslip is closedlogin:request- Emitted when the iframe requests loginscroll:up- Emitted when the iframe requests scroll to topheight:change- Emitted when iframe height changes (receives height string)ready- Emitted when the iframe is loaded and ready
Event Methods
// Listen to an event
sdk.on('betslip:open', () => {
console.log('Betslip opened');
});
// Listen once
sdk.once('ready', () => {
console.log('Widget ready - this will only fire once');
});
// Remove listener
const handler = () => console.log('Betslip closed');
sdk.on('betslip:close', handler);
sdk.off('betslip:close', handler);
// Remove all listeners for an event
sdk.removeAllListeners('betslip:open');
// Remove all listeners
sdk.removeAllListeners();
// Get listener count
const count = sdk.listenerCount('betslip:open');TypeScript Support
The SDK is written in TypeScript and provides full type definitions:
import { PythiaSDK, PythiaSDKOptions, UserInfo, ThemeType } from '@pythiasport/betting-widget';
const options: PythiaSDKOptions = {
tenantId: 'tenant-123',
jwtToken: 'token',
userId: 'user-123',
currencyCode: 'USD',
currencySymbol: '',
theme: 'dark'
};
const sdk = new PythiaSDK();
sdk.init(options);Legacy Version
For projects that require compatibility with older browsers, a legacy (umd) version of the SDK is available. To use it you can include it via CDN:
<script src="https://unpkg.com/@pythiasport/betting-widget@latest/dist/index.global.js"></script>
<script>
window.pythiaSDK.init({
tenantId: 'your-tenant-id',
jwtToken: 'user-token',
currencyCode: 'USD',
currencySymbol: '$',
theme: 'dark'
onLoginRequest: () => {
// Handle login request
console.log('User needs to login');
}
})
</script># Migration Guide
This guide helps you migrate from the original JavaScript SDK to the new TypeScript version.
Two Options
You have two options when upgrading to the new SDK:
- Use the Legacy API - Zero code changes, backward compatible
- Migrate to Modern API - Better features, type safety, and developer experience
Option 1: Legacy API (Zero Changes) ✨
What You Need to Do
Simply replace your script tag with the new legacy build:
Before:
<script src="path/to/old-pythia-sdk.js"></script>After:
<script src="https://unpkg.com/@pythiasport/betting-widget@latest/dist/legacy.global.js"></script>That's it! Your existing code will work without any changes:
// All your existing code works exactly as before
window.pythiaSDK.onBetslipOpen = function() {
console.log('Betslip opened');
};
window.pythiaSDK.init({
tenantId: 'your-tenant-id',
jwtToken: 'token',
userId: 'user-123',
currencyCode: 'USD',
currencySymbol: '$',
theme: 'dark'
});
window.pythiaSDK.setTheme('light');
window.pythiaSDK.updateUserInfo({ /* ... */ });What's Different (Behind the Scenes)
- ✅ Modern TypeScript implementation
- ✅ Better performance and optimization
- ✅ Improved error handling
- ✅ Automatic setup of internal listeners
- ⚠️ Some internal methods log deprecation warnings (but still work)
Deprecation Warnings
You might see console warnings for these methods (they still work, but are no longer necessary):
insertIframe()- Auto-handled on init()sendAuthDataToIframe()- Auto-sent on init()listenToIframeEvents()- Auto-setup on init()sendInitialTheme()- Auto-sent on init()syncParentScroll()- Auto-setup on init()syncParentHeight()- Auto-setup on init()sendIframeTopOffset()- Auto-sent on init()
You can safely remove calls to these methods if you want to clean up your code.
Option 2: Migrate to Modern API 🚀
Benefits
- ✅ Multiple event listeners per event
- ✅ Type safety with TypeScript
- ✅ Better IDE autocomplete
- ✅ One-time listeners with
once() - ✅ Cleaner event management
- ✅ Tree-shakeable imports
- ✅ Modern module system
Step-by-Step Migration
Step 1: Install via NPM
npm install @pythiasport/betting-widgetStep 2: Import the SDK
Before (Global Script):
<script src="path/to/pythia-sdk.js"></script>After (ES Module):
import { PythiaSDK } from '@pythiasport/betting-widget';Step 3: Create Instance
Before:
// Used global window.pythiaSDK
window.pythiaSDK.init({ /* ... */ });After:
// Create your own instance
const sdk = new PythiaSDK();
sdk.init({ /* ... */ });Step 4: Replace Callback Properties with Events
Before:
window.pythiaSDK.onBetslipOpen = function() {
console.log('Opened');
};
window.pythiaSDK.onBetslipClose = function() {
console.log('Closed');
};After:
sdk.on('betslip:open', () => {
console.log('Opened');
});
sdk.on('betslip:close', () => {
console.log('Closed');
});Step 5: Update Method Calls
Most methods stay the same, just called on your instance:
Before:
window.pythiaSDK.setTheme('light');
window.pythiaSDK.updateUserInfo({ /* ... */ });
window.pythiaSDK.setBetslipButtonOffset({ top: 80 });
window.pythiaSDK.scrollChanged(window.scrollY);After:
sdk.setTheme('light');
sdk.updateUserInfo({ /* ... */ });
sdk.setBetslipButtonOffset({ top: 80 });
sdk.notifyScrollChange(window.scrollY); // Renamed for clarityStep 6: Remove Unnecessary Method Calls
These methods are no longer needed (handled automatically):
Before:
window.pythiaSDK.init({ /* ... */ });
window.pythiaSDK.insertIframe(); // Remove this
window.pythiaSDK.sendAuthDataToIframe(); // Remove this
window.pythiaSDK.listenToIframeEvents(); // Remove this
window.pythiaSDK.sendInitialTheme(); // Remove thisAfter:
sdk.init({ /* ... */ });
// That's it! Everything else is automaticStep 7: Add Cleanup (Recommended)
Before:
// No cleanup mechanismAfter:
// Clean up when done (e.g., component unmount)
sdk.destroy();Complete Example: Before & After
Before (Legacy JavaScript)
<!DOCTYPE html>
<html>
<head>
<script src="pythia-sdk.js"></script>
</head>
<body>
<div id="betting-widget-container"></div>
<script>
window.pythiaSDK.onBetslipOpen = function() {
console.log('Betslip opened');
};
window.pythiaSDK.onBetslipClose = function() {
console.log('Betslip closed');
};
window.pythiaSDK.init({
tenantId: 'tenant-123',
jwtToken: 'token-abc',
userId: 'user-456',
currencyCode: 'USD',
currencySymbol: '$',
theme: 'dark',
onLoginRequest: function() {
alert('Please login');
}
});
// Later...
window.pythiaSDK.setTheme('light');
window.pythiaSDK.scrollChanged(window.scrollY);
</script>
</body>
</html>After (Modern TypeScript)
import { PythiaSDK } from '@pythiasport/betting-widget';
// Create instance
const sdk = new PythiaSDK();
// Set up event listeners
sdk.on('betslip:open', () => {
console.log('Betslip opened');
});
sdk.on('betslip:close', () => {
console.log('Betslip closed');
});
// Initialize
sdk.init({
tenantId: 'tenant-123',
jwtToken: 'token-abc',
userId: 'user-456',
currencyCode: 'USD',
currencySymbol: '$',
theme: 'dark',
onLoginRequest: () => {
alert('Please login');
}
});
// Later...
sdk.setTheme('light');
sdk.notifyScrollChange(window.scrollY);
// Clean up when done
// sdk.destroy();Framework-Specific Examples
React
import { useEffect, useRef } from 'react';
import { PythiaSDK } from '@pythiasport/betting-widget';
function BettingWidget() {
const sdkRef = useRef<PythiaSDK | null>(null);
useEffect(() => {
const sdk = new PythiaSDK();
sdkRef.current = sdk;
// Events
sdk.on('betslip:open', () => console.log('Opened'));
sdk.on('betslip:close', () => console.log('Closed'));
// Initialize
sdk.init({
tenantId: 'tenant-123',
jwtToken: 'token-abc',
userId: 'user-456',
currencyCode: 'USD',
currencySymbol: '$',
theme: 'dark',
});
// Cleanup
return () => {
sdk.destroy();
};
}, []);
return <div id="betting-widget-container" />;
}Vue 3
<template>
<div id="betting-widget-container"></div>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue';
import { PythiaSDK } from '@pythiasport/betting-widget';
const sdk = ref<PythiaSDK | null>(null);
onMounted(() => {
const instance = new PythiaSDK();
sdk.value = instance;
// Events
instance.on('betslip:open', () => console.log('Opened'));
instance.on('betslip:close', () => console.log('Closed'));
// Initialize
instance.init({
tenantId: 'tenant-123',
jwtToken: 'token-abc',
userId: 'user-456',
currencyCode: 'USD',
currencySymbol: '$',
theme: 'dark',
});
});
onUnmounted(() => {
sdk.value?.destroy();
});
</script>API Changes Summary
| Legacy API | Modern API | Notes |
|------------|------------|-------|
| window.pythiaSDK.onBetslipOpen = fn | sdk.on('betslip:open', fn) | Event-based |
| window.pythiaSDK.onBetslipClose = fn | sdk.on('betslip:close', fn) | Event-based |
| window.pythiaSDK.init(opts) | sdk.init(opts) | Same |
| window.pythiaSDK.setTheme(theme) | sdk.setTheme(theme) | Same |
| window.pythiaSDK.setLanguage(language) | sdk.setLanguage(language) | Same |
| window.pythiaSDK.updateUserInfo(info) | sdk.updateUserInfo(info) | Same |
| window.pythiaSDK.setBetslipButtonOffset(o) | sdk.setBetslipButtonOffset(o) | Same |
| window.pythiaSDK.scrollChanged(y, x) | sdk.notifyScrollChange(y, x) | Renamed |
| window.pythiaSDK.getIframe() | Internal | Not exposed |
| window.pythiaSDK.insertIframe() | Auto-handled | Not needed |
| window.pythiaSDK.config | Internal | Not exposed |
| window.pythiaSDK.$iframe | Internal | Not exposed |
| - | sdk.destroy() | New method |
| - | sdk.on(event, fn) | New method |
| - | sdk.once(event, fn) | New method |
| - | sdk.off(event, fn) | New method |
Event Names
| Legacy Callback | Modern Event | Description |
|----------------|--------------|-------------|
| onBetslipOpen | 'betslip:open' | Betslip opened |
| onBetslipClose | 'betslip:close' | Betslip closed |
| onLoginRequest callback | 'login:request' | Login requested |
| - | 'scroll:up' | Scroll to top requested |
| - | 'height:change' | Iframe height changed |
| - | 'ready' | Widget loaded |
TypeScript Support
Add types to your project:
import type {
PythiaSDKOptions,
UserInfo,
ThemeType,
BetslipButtonOffset
} from '@pythiasport/betting-widget';
const options: PythiaSDKOptions = {
tenantId: 'tenant-123',
jwtToken: 'token',
userId: 'user-456',
currencyCode: 'USD',
currencySymbol: '$',
theme: 'dark'
};Testing Your Migration
- Keep the old implementation running in parallel for testing
- Test all events - make sure they fire as expected
- Test theme switching - verify dark/light mode works
- Test user updates - ensure auth updates work
- Test scroll sync - verify scroll position updates
- Test cleanup - ensure
destroy()works properly
Rollback Plan
If you need to rollback, you can always switch back to the legacy API:
<!-- Rollback: use legacy build -->
<script src="https://unpkg.com/@pythiasport/betting-widget@latest/dist/legacy.global.js"></script>Your original code will work immediately.
Recommended Migration Path
- Week 1-2: Install new SDK, use legacy API (zero changes)
- Week 3-4: Migrate one component/page to modern API
- Week 5-6: Gradually migrate remaining components
- Week 7+: Complete migration, remove legacy API
This gradual approach minimizes risk and allows thorough testing.
Browser Support
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
License
MIT
