Appearance
Clips
GET /clipGenerates a clip and returns a URL that you can stream in a video player or download. Clips are generated on demand, fast enough to request one when a user presses play.
Clips are cached. If a clip with the same parameters already exists, its URL is returned without generating it again.
Do not store clip URLs
Clip URLs are not permanent, because generated clips are deleted from time to time. Always request clips through this endpoint each time and use the returned URL instead of saving a prior URL. A clip that still exists is returned from the cache, so this shouldn't create a problem but will ensure the URL does not disappear on you.
Parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
league | Yes | string | NBA, GLEAGUE, or NBASL |
game_id_nba | One of these two | string | NBA game ID, as in the data feed |
game_id | One of these two | UUID | Video game ID from /available_game_periods. See Game IDs |
period | Yes | integer | Period number |
start_game_clock | One of these two | number | Seconds left in the period, such as 581 for 9:41 |
start_timestamp | One of these two | integer | Wall clock time in epoch milliseconds |
start_padding | No | integer | Seconds of video before the start time. Default 0 |
end_padding | No | integer | Seconds of video after the start time. Default 5 |
audio | No | true or false | Include broadcast audio. Default false |
regenerate | No | true or false | Skip the cache and generate the clip again. Default false |
A clip can be up to 5 minutes long: start_padding plus end_padding cannot exceed 300.
A padding of 10 seconds before and 5 seconds after usually shows what leads up to an event.
Game Clock or Timestamp
Check wall_clock_timing_available in the period's video_metrics from /available_game_periods:
true: use either. A timestamp points to one exact moment, so it is the better choice when you have one, such as a*_wall_clockvalue from the data feed. This covers nearly all NBA games, and G League and Summer League games for which we have tracking data.false: usestart_game_clock. A request with onlystart_timestampreturns a400error.
NOTE
When using the start_game_clock method, remember that a game clock can repeat during a stoppage. Suppose there is a foul at 9:41, then an inbound with 9:41 still on the clock. When wall_clock_timing_available is true, passing 581 starts at the first moment 9:41 appears and shows the foul. To show the inbound, pass 580 with a larger start_padding. When it is false, a repeated clock time can start the clip at the end of the stoppage instead, showing the inbound. To show the foul, pass 582 with a smaller start_padding.
Response
| Field | Type | Description |
|---|---|---|
result | string | Success, Imputed, or an error message |
clip_url | string or null | URL of the MP4 clip |
closest_prev_time | number | Only when result is Imputed (see below) |
closest_next_time | number | Only when result is Imputed (see below) |
Example
bash
curl --request GET \
--url 'https://api.cleaningtheglass.com/video/clip?league=NBA&game_id=00124539-08e3-4174-bd7f-db5e96a904fb&period=1&start_game_clock=581&start_padding=10&end_padding=5' \
--header 'X-API-KEY: YOUR_VIDEO_API_KEY'json
{
"result": "Success",
"clip_url": "https://..."
}Imputed Clips
Older G League and Summer League video that does not have tracking data may not have a match for every game clock time. In that case the clip is estimated from the nearest matched times before and after the requested time, and result is Imputed:
json
{
"result": "Imputed",
"clip_url": "https://...",
"closest_prev_time": 573.0,
"closest_next_time": 568.0
}The estimate is accurate while the clock is running. If the clock was stopped, the clip may not show what you expect. You can request one of the two closest times instead.
Building Your Own Player
This page plays a clip in a standard HTML video element. Save it as an HTML file, replace YOUR_VIDEO_API_KEY, open it in a browser, and press Play Clip.
Keep your key on the server
This example calls the API from the browser, which exposes your key to anyone who can open the page. In production, call /clip from your server and pass only clip_url to the browser.
html
<!DOCTYPE html>
<html lang="en">
<body>
<video id="video-player" controls width="1280"></video>
<button
id="play-clip"
data-league="NBA"
data-game="00124539-08e3-4174-bd7f-db5e96a904fb"
data-period="1"
data-start="581"
data-start-padding="10"
data-end-padding="5"
>
Play Clip
</button>
<script>
const API_KEY = "YOUR_VIDEO_API_KEY";
document.getElementById("play-clip").addEventListener("click", async (event) => {
const clip = event.target.dataset;
const params = new URLSearchParams({
league: clip.league,
game_id: clip.game,
period: clip.period,
start_game_clock: clip.start,
start_padding: clip.startPadding,
end_padding: clip.endPadding,
});
const response = await fetch(
"https://api.cleaningtheglass.com/video/clip?" + params,
{ headers: { "X-API-KEY": API_KEY } }
);
const data = await response.json();
if (data.result === "Success" || data.result === "Imputed") {
const player = document.getElementById("video-player");
player.src = data.clip_url;
player.play();
} else {
console.error("Could not get the clip:", data.result);
}
});
</script>
</body>
</html>Change data-start, data-start-padding, and data-end-padding to see how the clip changes.
If you would rather not build a player, create a playlist and open it in the CTG video player.
