Oddin.gg Ghost documentation
Introduction
Oddin.gg Ghost is a real-time, interactive 3D visualization of live Counter-Strike 2 (CS2) matches, designed to enhance engagement with immersive match views.
Ghost comes in two integration variants:
- Ghost — game visualization only (no betting UI)
- Betpeek — full experience including betting iframe, selections, wallet API, and risk management overlay
Ghost can be embedded in partner frontends using URLs served from Oddin’s CDN, while Betpeek is integrated via Oddin’s turnkey iframe solution.
1. Supported Esports
| Esport | BetPeek |
| Counter-Strike 2* | ✅ |
| Dota 2* | ✅ |
*Duels products are not supported
2. Ghost vs Betpeek
| Feature | Ghost | Betpeek |
| Game Visualization | ✅ | ✅ |
| Betting Overlay (stakes, selections, wallet) | ❌ | ✅ |
| Authentication | Token-based (per match / partner) | Token + Player session |
| API Interaction | gRPC call to retrieve Ghost URL | Integrated via Oddin iFrame |
| Embedding | Partner embeds directly from CDN | Oddin-hosted iFrame |
| Fullscreen Support | ✅ Desktop & Mobile |
✅ Desktop & Mobile |
ℹ Ghost is typically used when partners handle UI, wallet, and betting independently, and only need the in-game 3D visualization.
This documentation describes the integration process for Ghost (non-betting UI). For the full experience including betting overlay, please consult Oddin.gg’s BetPeek documentation.
3. Authentication & Access Control
3.1. Environments
We currently provide two different environments – Production and Integration. The Production environment is intended to be used only when you are finished with the integration and ready to go live. Please use the Integration environment for all testing and integration purposes.
You can find the endpoint for each environment in the following table:
| Environment | API URL |
| Production | api-ghost-grpc.oddin.gg |
| Integration | api-ghost-grpc-integration.oddin.gg |
3.2. URL Retrieval
- Ghost URLs are retrieved via gRPC, not hardcoded.
- The partner calls the
GetMatchInfomethod using:match_idclient_token
- The API validates:
- The token
- The IP/domain whitelist. We will require a full list of IPs to be whitelisted, including ones used for staging/integration.
3.3. Example gRPC Schema
service Ghost { rpc GetMatchInfo(MatchInfoRequest) returns (MatchInfoResponse); rpc GetMatchStatus(MatchStatusRequest) returns (MatchStatusResponse);}message CS2MatchInfoResponse { string map_name = 2; string map_asset_name = 3; string game_version = 4; string asset_url = 5; // Specifies the URL for the asset of the match.}
3.4. Public Access Rules
- For Ghost, you can share the same generated link publicly (token-authenticated at backend level).
- Authentication happens server-side (when retrieving the Ghost URL), not per player/user.
4. CDN URL Format
Each Ghost visualization is hosted on Oddin’s CDN and follows this pattern, which corresponds to the asset_url from MatchInfoResponse:
<https://cdn.oddin.gg/ghost-assets/v1.0.5/map/{map_asset_name}/Oddin-HTML5-Shipping.html?X-MatchURN={match_urn}&url={data_api_url}&token={access_token}>
4.1. Parameters
| Parameter | Description | Example |
v1.0.5 |
Version tag for caching and asset stability | /v1.0.5/ |
map_asset_name |
Map identifier (from the API, no de_ prefix) | mirage, ancient, dust2 |
X-MatchURN |
Match ID from Oddin Odds feed | 1895759 |
url |
Data API endpoint | https://api-ghost-integration.oddin.gg |
token |
Partner’s assigned Ghost token | a0a0a000-000a-000a-0aa0-0000000aa00a |
lang |
Language parameter (currently supported: English - en, Russian - ru) |
en |
5. Polling Logic & Match Lifecycle
Ghost availability is discovered after the match goes live, by using the Oddin Odds Feed (similar to Disir/live widgets integrations).
5.1. Workflow
- Detect
OnFixtureChange→ Match goes Live. - Poll
api-ghost-grpc-integration.oddin.ggfor MatchStatus. This indicates whether the live match supports Ghost. - When
Available, get CDN URL fromGetMatchInfoand display Ghost inside your own iFrame. - Ghost automatically transitions between maps during the match while the application is active.
5.2. Polling Intervals
| Parameter | Description | Example |
MatchStatus |
Detect match availability | Every 10–30 seconds once the match goes live |
MatchInfo |
Get current map name | On new map start only |
Polling during map transitions can be reduced. Cache the map info until the Odds Feed indicates a new map start.
6. Detecting Map Transitions (CS2)
Use the Odds Feed to identify when a new map begins.
6.1. Correct Trigger
Map transitions should be based on scoreboard activity, not just PeriodScores.
When the <scoreboard> data appears with current_round="1", the new map has officially started. This appears only when the first round actually starts and the timer starts ticking.
<scoreboard current_ct_team="2" home_won_rounds="0" away_won_rounds="0" current_round="1"></scoreboard>
6.2. Common Mistake
Polling on PeriodScores change may occur before the new map is live, resulting in reusing the old URL.
7. Embedding & Frontend Guidelines
- The Ghost client should be embedded in your platform using a standard
<iframe>element. - The CDN URL is the iFrame source.
- Partners are responsible for layout and UX integration.
7.1. Recommended Display Sizes
| Device | Minimum size | Notes |
| Desktop | 640×320 px | Readable UI, no scrollbars |
| Mobile | Fullscreen modal | Suboptimal in small containers |
7.2. Suggested Behavior
- Desktop: Show Ghost in theatre mode, or with the modal with the option to go fullscreen.
- Mobile: Trigger the fullscreen modal directly when the Ghost (or some other suggestive button name e.g. “3D Live”) button is pressed.
Example UX flow:
- User opens match details.
- User clicks “3D Live” → Ghost modal appears.
- User can switch to fullscreen → returns to modal on exit.
7.3. Handling Fullscreen & iOS Limitations
- On desktop, the embedded iframe can display the live mode directly.
- On mobile, opening Ghost in fullscreen provides the best experience.
- iOS does not support the standard fullscreen API. In this case:
- Implement a custom overlay to simulate fullscreen behavior.
- Disable
allowfullscreenon the<iframe>element, since the Ghost engine triggers fullscreen internally and your overlay would otherwise be hidden.
- To handle fullscreen toggling or exit events between the iframe and the host page, use a
toggle-fullscreenmessage:
// Inside the iframe
window.parent.postMessage({ type: 'toggle-fullscreen' }, '*')
// In React (host page)
useEffect(() => {
const handleMessage = (event) => {
if (event.data.type === 'toggle-fullscreen') onToggleFullscreen?.()
}
window.addEventListener('message', handleMessage)
return () => window.removeEventListener('message', handleMessage)
}, [onToggleFullscreen])
This allows the host app to control custom overlays or close fullscreen mode gracefully, even on platforms without fullscreen API support (e.g., iOS).
8. Supported Sports
| Sport URN | Description | Ghost Support |
od:sport:3 |
Counter-Strike 2 | ✅ Supported |
od:sport:21 |
CS2 Duels | ❌ Not supported |
od:sport:2 |
Dota 2 | Coming soon |
Only od:sport:3 should be considered Ghost-eligible for the time being.
9. Error Handling
| Error | Cause | Resolution |
Access Denied |
Missing or malformed url parameter |
Add proper API URL |
Not_found |
API mismatch | Fixed: now returns Unavailable |
StatusCode="Internal" |
Unsupported sport | Filter CS2 only |
MATCH_STATUS_UNAVAILABLE |
Wrong environment or inactive match | Verify endpoint, token, and match status |
10. Environments
Ensure each environment (integration, production) is configured with:
- Correct API URLs
- Whitelisted domains/IPs
If the staging environment receives no Ghost URLs, ensure the match belongs to a supported sport and that the environment permissions match your integration setup.
11. Summary of Best Practices
- Authenticate via the backend token and IP whitelist
- Filter for
od:sport:3only - Detect new maps using Odds Feed scoreboard events
- Poll
MatchStatusevery 10–30s - Fetch new map URLs only when round 1 starts
- Embed Ghost at minimum 640×320 px, but fullscreen with tailor made odds overlays is preferred for optimum UX
- Use fullscreen for mobile
- Cache URL per map, refresh on reload or reconnection