npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

owls-insight-ts

v0.2.1

Published

Official TypeScript SDK for the Owls Insight real-time sports betting odds API

Readme

Owls Insight SDK

Official TypeScript/JavaScript SDK for the Owls Insight real-time sports betting odds API.

Features

  • Full TypeScript types for all endpoints and events
  • REST client for odds, scores, props, history, and stats
  • WebSocket client for real-time streaming updates
  • Works in Node.js, Bun, Deno, and modern browsers
  • ESM and CommonJS support

Installation

npm install owls-insight-ts

Quick Start

import { OwlsInsight } from "owls-insight-ts";

const client = new OwlsInsight({ apiKey: process.env.OWLS_INSIGHT_API_KEY! });

// Get NBA odds from all books
const odds = await client.rest.getOdds("nba");

// odds.data is keyed by book: { pinnacle: [...], fanduel: [...], ... }
for (const [book, events] of Object.entries(odds.data)) {
  console.log(`${book}: ${events.length} events`);
}

// Get odds from specific books
const filtered = await client.rest.getOdds("nba", {
  books: ["pinnacle", "fanduel"],
});

REST API

Odds

// All markets (moneyline + spreads + totals)
const odds = await client.rest.getOdds("nba");

// Single market
const ml = await client.rest.getMoneyline("nba");
const spreads = await client.rest.getSpreads("nfl");
const totals = await client.rest.getTotals("nhl");

// With filters
const filtered = await client.rest.getOdds("soccer", {
  books: ["pinnacle", "bet365"],
  league: "England - Premier League",
  alternates: true, // requires Rookie+ tier
});

International Basketball

International basketball leagues (EuroLeague, Spanish ACB, etc.) are available under the basketball sport key, separate from NBA/NCAAB.

// All international basketball odds
const intlBball = await client.rest.getOdds("basketball");

// Filter by league
const euroleague = await client.rest.getOdds("basketball", {
  league: "EuroLeague",
});

// Real-time Pinnacle odds (MVP+ tier)
const realtime = await client.rest.getRealtime("basketball");

Available leagues include EuroLeague, Spanish ACB, Italian Serie A, Greek League, Lithuanian NBL, Argentine La Liga, Venezuelan Superliga, and more.

Esports (CS2, Valorant, LoL)

const cs2 = await client.rest.getOdds("cs2");
const valorant = await client.rest.getOdds("valorant");
const lol = await client.rest.getOdds("lol");

CS2 odds from 1xBet. Valorant and LoL from both 1xBet and Pinnacle. Esports use a separate WebSocket event (esports-update).

Live Scores

// All sports
const allScores = await client.rest.getScores();

// Specific sport
const nbaScores = await client.rest.getScores("nba");

Player Props

// All books
const props = await client.rest.getProps("nba");

// Filtered
const filtered = await client.rest.getProps("nba", {
  player: "LeBron",
  category: "points",
  books: ["pinnacle", "fanduel"],
});

// Single book (typed per-book response)
const fdProps = await client.rest.getBookProps("nba", "fanduel");
const mgmProps = await client.rest.getBookProps("nba", "betmgm"); // BetMGMPropsResponse
const b365Props = await client.rest.getBookProps("nba", "bet365"); // Bet365PropsResponse

// Props line movement history
const propsHistory = await client.rest.getPropsHistory("nba", {
  game_id: "game_123",
  player: "LeBron James",
  category: "points",
  book: "pinnacle",
  hours: 24,
});

// Props cache statistics
const propsStats = await client.rest.getPropsStats();
const bet365Stats = await client.rest.getBookPropsStats("bet365");

Box Scores & Stats (Rookie+ tier)

// NBA box scores for today
const stats = await client.rest.getStats("nba");

// Filter by date and player
const filtered = await client.rest.getStats("nba", {
  date: "2026-03-05",
  player: "LeBron",
});

// Rolling averages (L5/L10/L20)
const averages = await client.rest.getStatsAverages("nba", {
  playerName: "LeBron James",
  opponent: "Lakers", // optional H2H filter
});

Real-Time Odds (MVP+ tier)

Sub-second Pinnacle odds via dedicated real-time pipeline. Available for all sports including international basketball.

const realtime = await client.rest.getRealtime("nba");

console.log(realtime.meta.source);    // "pinnacle"
console.log(realtime.meta.events);    // number of events
console.log(realtime.meta.available); // true if data exists
console.log(realtime.meta.freshness); // { ageSeconds, stale, threshold: 30 }

The freshness object indicates data age. Data is considered stale after 30 seconds.

Odds History (MVP+ tier)

// Line movement history
const history = await client.rest.getOddsHistory({
  eventId: "event_123",
  book: "pinnacle",
  market: "spreads",
  side: "home",
  hours: 24,
});

Historical Archive (MVP+ tier)

// List completed games
const games = await client.rest.getHistoryGames({
  sport: "nba",
  startDate: "2026-03-01",
  endDate: "2026-03-06",
});

// Get archived odds snapshots
const snapshots = await client.rest.getHistoryOdds({
  eventId: "event_123",
  book: "pinnacle",
  market: "spreads",
});

// Get archived props snapshots
const propsSnapshots = await client.rest.getHistoryProps({
  eventId: "event_123",
  playerName: "LeBron James",
  propType: "points",
});

// Get archived player stats
const playerStats = await client.rest.getHistoryStats({
  sport: "nba",
  playerName: "LeBron James",
  startDate: "2026-01-01",
  endDate: "2026-03-01",
});

// Get historical rolling averages
const histAvg = await client.rest.getHistoryStatsAverages({
  playerName: "LeBron James",
  sport: "nba",
});

// Get archived tennis match stats
const tennisStats = await client.rest.getHistoryTennisStats("event_123");

// CS2 match history
const cs2Matches = await client.rest.getCS2Matches({
  team: "Natus Vincere",
  stars: 4,
});

// Full match detail with map scores and player stats
const matchDetail = await client.rest.getCS2Match(2374324);

// Player stats across matches
const playerStats = await client.rest.getCS2Players({
  playerName: "s1mple",
  minRating: 1.3,
});

Kalshi Prediction Markets

const markets = await client.rest.getKalshiMarkets("nba", {
  status: "open",
});

// Browse series (e.g., KXNBAGAME, KXNFLSBMVP)
const series = await client.rest.getKalshiSeries();

// Markets within a series
const nbaGame = await client.rest.getKalshiSeriesMarkets("KXNBAGAME");

Polymarket

Polymarket odds are also included as a bookmaker in the standard /odds response.

const markets = await client.rest.getPolymarketMarkets("nba");

WebSocket Streaming

Real-time odds updates via WebSocket (Rookie+ tier).

Connect & Subscribe

const client = new OwlsInsight({ apiKey: process.env.OWLS_INSIGHT_API_KEY! });

await client.ws.connect();

// Subscribe to sports and books
client.ws.subscribe({
  sports: ["nba", "nfl"],
  books: ["pinnacle", "fanduel", "draftkings"],
});

// Listen for odds updates
client.ws.on("odds-update", (data) => {
  console.log(`Update at ${data.timestamp}`);
  // data.last_odds_change — when prices actually changed (vs heartbeat)
  for (const [sport, events] of Object.entries(data.sports)) {
    console.log(`${sport}: ${events.length} events`);
    for (const event of events) {
      console.log(`  ${event.away_team} @ ${event.home_team}`);
    }
  }
});

Update & Query Subscription

// Update an existing subscription
client.ws.updateSubscription({ sports: ["nba", "nhl", "soccer"] });

// Query current subscription state
client.ws.getSubscription();
client.ws.on("subscription", (sub) => {
  console.log("Current subscription:", sub.sports, sub.books);
});

Props Streaming

// Subscribe to Pinnacle props for specific sports
client.ws.subscribeProps({ sports: ["nba", "nhl"] });

// Subscribe to a specific book's props
client.ws.subscribeProps({ sports: ["nba"] }, "fanduel");

// Filter by categories
client.ws.subscribeProps({
  sports: ["nba"],
  categories: ["points", "rebounds", "assists"],
});

// Subscribe to all books
client.ws.subscribeProps({ sports: ["nba"] });                    // Pinnacle
client.ws.subscribeProps({ sports: ["nba"] }, "fanduel");         // FanDuel
client.ws.subscribeProps({ sports: ["nba"] }, "draftkings");      // DraftKings
client.ws.subscribeProps({ sports: ["nba"] }, "bet365");          // Bet365
client.ws.subscribeProps({ sports: ["nba"] }, "betmgm");          // BetMGM
client.ws.subscribeProps({ sports: ["nba"] }, "caesars");          // Caesars

client.ws.on("player-props-update", (data) => {
  console.log("Pinnacle props:", data.sports);
});

client.ws.on("fanduel-props-update", (data) => {
  console.log("FanDuel props:", data.sports);
});

// Confirmation events
client.ws.on("props-subscribed", (sub) => {
  console.log("Pinnacle props active:", sub);
});

// Unsubscribe
client.ws.unsubscribeProps();           // Pinnacle
client.ws.unsubscribeProps("fanduel");  // FanDuel

Real-Time Pinnacle (MVP+ tier)

Pushed automatically to all MVP+ clients — no subscription needed.

client.ws.on("pinnacle-realtime", (data) => {
  // data contains per-sport arrays: nba, ncaab, nfl, nhl, ncaaf, mlb, tennis, soccer, basketball
  for (const event of data.nba) {
    console.log(`${event.away_team} @ ${event.home_team}`);
    const pinnacle = event.bookmakers.find((b) => b.key === "pinnacle");
    for (const market of pinnacle?.markets || []) {
      console.log(`  ${market.key}:`, market.outcomes);
    }
  }
});

Esports Updates

// Opt in to all esports via subscribe
client.ws.subscribe({
  sports: ["nba"],
  books: ["pinnacle"],
  esports: true,
});

// Or filter to specific esports
client.ws.subscribe({
  sports: ["nba"],
  esports: ["cs2", "valorant"],
});

client.ws.on("esports-update", (data) => {
  console.log(`CS2: ${data.sports.cs2?.length}`);
  console.log(`Valorant: ${data.sports.valorant?.length}`);
  console.log(`LoL: ${data.sports.lol?.length}`);
});

Game-Specific Updates

client.ws.subscribeGame("event_123");

client.ws.on("odds-update", (data) => {
  // Will include targeted updates for subscribed games
});

client.ws.unsubscribeGame("event_123");

Line History via WebSocket

// Request odds history
client.ws.requestHistory({
  requestId: "req_1",
  eventId: "event_123",
  book: "pinnacle",
  market: "spreads",
  side: "home",
  hours: 24,
});

client.ws.on("history-response", (data) => {
  if (data.success && data.data) {
    console.log(`${data.data.history.length} data points`);
  }
});

// Request props history
client.ws.requestPropsHistory({
  requestId: "req_2",
  gameId: "game_123",
  player: "LeBron James",
  category: "points",
  book: "pinnacle",
  hours: 12,
});

client.ws.on("props-history-response", (data) => {
  if (data.success && data.data) {
    console.log(`${data.data.dataPoints} data points`);
  }
});

Promise-Based Waiting

// Wait for the next odds update
const update = await client.ws.waitFor("odds-update", 10_000);

// Wait for subscription confirmation
client.ws.subscribe({ sports: ["nba"], books: ["pinnacle"] });
const sub = await client.ws.waitFor("subscribed");
console.log("Subscribed to:", sub.sports);

Error Handling

client.ws.on("error", (err) => {
  console.error("WebSocket error:", err.message, err.code);
});

client.ws.on("disconnect", (reason) => {
  console.log("Disconnected:", reason);
});

Cleanup

// Disconnect WebSocket
client.ws.disconnect();

// Or destroy everything
client.destroy();

Error Handling

The SDK throws typed errors for different failure modes:

import {
  OwlsInsightError,
  AuthenticationError,
  ForbiddenError,
  RateLimitError,
} from "owls-insight-ts";

try {
  const odds = await client.rest.getOdds("nba");
} catch (err) {
  if (err instanceof RateLimitError) {
    console.log(`Rate limited. Retry in ${err.retryAfterMs}ms`);
  } else if (err instanceof AuthenticationError) {
    console.log("Invalid API key");
  } else if (err instanceof ForbiddenError) {
    console.log("Upgrade your subscription tier");
  } else if (err instanceof OwlsInsightError) {
    console.log(`API error ${err.status}: ${err.message}`);
  }
}

The API returns rate limit headers on every response:

  • X-RateLimit-Remaining-Minute — requests left this minute
  • X-RateLimit-Remaining-Month — requests left this month
  • X-RateLimit-Reset-Minute — Unix timestamp (ms) when the minute limit resets
  • X-RateLimit-Reset-Month — ISO 8601 timestamp when the month limit resets

Configuration

const client = new OwlsInsight({
  apiKey: process.env.OWLS_INSIGHT_API_KEY!,  // Required
  baseUrl: "https://api.owlsinsight.com", // Optional (default)
  wsUrl: "https://api.owlsinsight.com",   // Optional (default, same as baseUrl)
  timeout: 30000,                  // Optional request timeout in ms (default: 30s)
});

Supported Sports

| Sport | Key | Props | Real-Time | Scores | |-------|-----|-------|-----------|--------| | NBA | nba | Yes | Yes | Yes | | NCAAB | ncaab | Yes | Yes | Yes | | NFL | nfl | Yes | Yes | Yes | | NHL | nhl | Yes | Yes | Yes | | NCAAF | ncaaf | Yes | Yes | Yes | | MLB | mlb | Yes | Yes | Yes | | Soccer | soccer | Yes | Yes | Yes | | Tennis | tennis | - | Yes | Yes | | MMA | mma | - | - | - | | CS2 | cs2 | - | - | Yes | | Valorant | valorant | - | - | Yes | | LoL | lol | - | - | Yes | | Intl Basketball | basketball | - | Yes | - |

Sportsbooks & Coverage

| Book | Game Odds | Player Props | Notes | |------|-----------|-------------|-------| | Pinnacle | NBA, NCAAB, NFL, NHL, NCAAF, MLB, Soccer, Tennis | NBA, NCAAB, NFL, NHL, NCAAF, MLB, Soccer | Sharp/reference line | | FanDuel | NBA, NCAAB, NFL, NHL, NCAAF, MLB, Soccer, Tennis | NBA, NCAAB, NFL, NHL, NCAAF | | | DraftKings | NBA, NCAAB, NFL, NHL, NCAAF, MLB, Soccer, Tennis | NBA, NCAAB, NFL, NHL, NCAAF | | | BetMGM | NBA, NCAAB, NFL, NHL, NCAAF, MLB | NBA, NCAAB, NFL, NHL, NCAAF | | | Bet365 | NBA, NCAAB, NFL, NHL, NCAAF, MLB | NBA, NCAAB, NFL, NHL, NCAAF | | | Caesars | NBA, NCAAB, NFL, NHL, NCAAF, MLB | NBA, NCAAB, NFL, NHL, NCAAF | | | BetOnline | MMA | - | UFC/MMA only | | 1xBet | CS2, Valorant, LoL, Soccer | - | Esports + soccer | | Circa Sports | NBA, NCAAB, NFL, NHL, NCAAF, MLB | - | Vegas sharp book | | South Point | NBA, NCAAB, NFL, NHL, NCAAF, MLB | - | Vegas | | Westgate SuperBook | NBA, NCAAB, NFL, NHL, NCAAF, MLB | - | Vegas | | Wynn | NBA, NCAAB, NFL, NHL, NCAAF, MLB | - | Vegas | | Stations Casinos | NBA, NCAAB, NFL, NHL, NCAAF, MLB | - | Vegas | | Kalshi | NBA, NCAAB, NFL, NHL, MLB | - | Prediction market | | Polymarket | NBA, NCAAB, NFL, NHL, MLB, Soccer | - | Decentralized exchange |

Pricing

See owlsinsight.com for current plans and pricing.

License

MIT