ShotTracker Developer

Unparalleled data set + realtime API = future of sports. Build with live tracking, stats, and broadcast-ready endpoints.

Broadcast API

Broadcast API — Code examples

Authentication and Stats SSE connection examples for the Broadcast API. For full details see the Broadcast API overview; for the Live Game Stats SSE and Game Stats endpoints see the Stats group in the sidebar.

API key in query string (cURL)

Example (bash)
# cURL with API key in query string
curl "https://api.shottracker.com/broadcast/v1/games/schedule?apikey=YOUR_API_KEY"

# With other params
curl "https://api.shottracker.com/broadcast/v1/games/teams?apikey=YOUR_API_KEY"

Live Game Stats SSE (JavaScript)

Example (javascript)
var EventSource = require("eventsource");
var fs = require("fs");

const SCHEDULE_ID = process.env.SCHEDULE_ID || "<schedule id>";
const API_KEY = process.env.BROADCAST_API_KEY || "<your api key>";

var es = new EventSource(
  "https://api.shottracker.com/broadcast/v1/stats/event-stream?schedule_id=" +
  SCHEDULE_ID + "&apikey=" + API_KEY
);

es.addEventListener("message", function (event) {
  var data = event.data;
  console.log(data);
  fs.writeFile("./sse_data.json", data, function (err) {
    if (err) return console.log(err);
    console.log("The file was saved!");
  });
});

es.addEventListener("error", function (event) {
  console.error("SSE error", event);
});

Live Game Stats SSE (Go)

Example (go)
package main

import (
  "bufio"
  "fmt"
  "io"
  "net/http"
  "os"
  "strings"
  "time"
)

const CONNECTED_STATUS = "CONNECTED"
const DISCONNECTED_STATUS = "DISCONNECTED"

var timer *time.Timer

func main() {
  reader := bufio.NewReader(os.Stdin)
  fmt.Println("ShotTracker SSE Download Utility")
  fmt.Println("--------------------------------")
  fmt.Print("Enter Event Stream URL (e.g. https://api.shottracker.com/broadcast/v1/stats/event-stream?schedule_id=ID&apikey=KEY)\n> ")
  url, _ := reader.ReadString('\n')
  fmt.Print("Enter Output File Name\n> ")
  fileName, _ := reader.ReadString('\n')
  fmt.Println("================================")
  run(strings.TrimSpace(url), strings.TrimSpace(fileName))
}

func run(url string, fileName string) {
  for {
    response, _ := getResponse(nil, url)
    if response == nil {
      time.Sleep(5000 * time.Millisecond)
      continue
    }
    logToConsole(CONNECTED_STATUS, "waiting for data ...")
    read(response, fileName)
    response.Body.Close()
  }
}

func getResponse(body io.Reader, url string) (*http.Response, error) {
  request, requestErr := http.NewRequest(http.MethodGet, url, body)
  if requestErr != nil {
    panic(fmt.Sprintf("Error creating request: %s", requestErr))
  }
  request.Header.Add("Accept", "text/event-stream")
  response, err := http.DefaultClient.Do(request)
  if err != nil {
    logToConsole(DISCONNECTED_STATUS, fmt.Sprintf("error connecting to %s: %s", url, err))
    return nil, err
  }
  if response.StatusCode != http.StatusOK {
    panic(fmt.Sprintf("Expected %d; got %d", http.StatusOK, response.StatusCode))
  }
  return response, err
}

func read(response *http.Response, fileName string) {
  handleHeartbeat(response)
  reader := bufio.NewReader(response.Body)
  for {
    data, err := reader.ReadString('\n')
    if err != nil && err != io.EOF {
      fmt.Fprintf(os.Stderr, "Error reading: %s\n", err)
      break
    }
    if strings.HasPrefix(data, "data:") {
      logToConsole(CONNECTED_STATUS, "data received, updating "+fileName)
      writeToFile(fileName, strings.TrimSpace(data[5:]))
    }
    if data == ":
" {
      logToConsole(CONNECTED_STATUS, "server heartbeat received")
      handleHeartbeat(response)
    }
  }
}

func handleHeartbeat(response *http.Response) {
  if timer != nil {
    timer.Stop()
  }
  timer = time.NewTimer(30 * time.Second)
  go func() {
    <-timer.C
    logToConsole(DISCONNECTED_STATUS, "no heartbeat in 30s; reconnecting...")
    response.Body.Close()
  }()
}

func writeToFile(filename string, data string) {
  file, _ := os.Create(filename)
  defer file.Close()
  io.WriteString(file, data)
  file.Sync()
}

func logToConsole(status string, value string) {
  fmt.Printf("
%s [%s] %s", status, time.Now().Format("2006.01.02 15:04:05"), value)
}