Every field-goal attempt of one finished game with court x / y (vendor frame), zone, style and result.
Endpoint: GET https://api.preciser.io/v1/chart-data/id/{uuid}
Arguments
- uuid
Required. The Preciser game uuid the site's game page embeds (
uuidof pleague_game; empty before 2022-23, which have no vendor data), e.g. 'e6f98675-3e5b-11ed-949e-5d17350689cf' (gid 197).- gid
Optional. The site's game id for this uuid. When given the runtime also fetches the site's game page and box (cached) and checks the vendor body against them (uuid, final score, made shots, roster and minutes); the uuid must be the game page's. Without it only the checks the body allows by itself run.
Value
A hoopR_data tibble: Every field-goal attempt of one finished game with court x / y (vendor frame), zone,
style and result. An empty valid answer is a zero-row tibble with these columns, in this order (sportsdataverse-py
pleague_preciser_shots):
| col_name | type | description |
| game_uuid | character | Preciser game uuid (key space: the vendor's games, a version-1 uuid), the uuid asked for; uuid of pleague_game. |
| shot_no | integer | 1-based position in the order the vendor sent the shots, which is NOT guaranteed game order: sort on period and seconds_left. |
| period | integer | Period number: 1-4, 5 and up for overtime (OT1 = 5). |
| period_label | character | Period label: Q1-Q4, then OT1, OT2. |
| clock | character | Game clock REMAINING in the period 'mm:ss' (counts down). |
| seconds_left | integer | The clock as whole seconds remaining in the period (08:34 = 514), derived by the parser. |
| side | character | Which team took the shot: home or away, from the shooter's team uuid against home_id / away_id. |
| team_uuid | character | Preciser team uuid (key space: the vendor's teams; the file name of the club logo). Joins the site team_id through pleague_standings.team_uuid: 1 = e86394aa-3d88-11ed-8ba8-7f44ba46b0b1 ((Chinese text), Taipei Fubon Braves); 2 = e865bb20-3d88-11ed-a956-7f44ba46b0b1 ((Chinese text), Taoyuan Pauian Pilots (Taoyuan Pilots from 2024-25)); 3 = e8674343-3d88-11ed-98b4-7f44ba46b0b1 ((Chinese text), Hsinchu Jko Lioneers (Toplus Lioneers from 2023-24)); 4 = e869743f-3d88-11ed-925e-7f44ba46b0b1 ((Chinese text), Formosa Taishin Dreamers (Formosa Dreamers from 2022-23)); 5 = e86cac11-3d88-11ed-8637-7f44ba46b0b1 ((Chinese text), Kaohsiung 17LIVE Steelers); 6 = e86b0ecc-3d88-11ed-bed5-7f44ba46b0b1 ((Chinese text), New Taipei Kings); 7 = 3c3a601a-358a-11ed-ab92-711c34ed1298 ((Chinese text), TSG Ghosthawks); 8 = bf957f5a-9389-11f0-812c-a38482ec4d30 ((Chinese text), Yankey Ark). |
| person_id | character | Preciser person uuid (key space: the vendor's persons): equal to the site box person_id of the same player, the join between this row and pleague_box_players (2022-23 on). |
| player_name | character | Shooter's name as printed (Traditional Chinese or a transliteration); equals the box name_zh. |
| type | character | Shot value: 2pt or 3pt. |
| subtype | character | Shot style: jumpShot, layup, drivingLayup, floatingJumpShot (floater), tipIn (putback), pullUpJumpShot, fadeAway, dunk, turnAroundJumpShot, hookShot, stepBackJumpShot, alleyOop; null on a few shots (7 of 2,566). |
| area | character | Shot zone, English label '{side} {distance band}': 'Center 8ft' (restricted-area band, within 8 ft), 'Center 8-16ft', 'Left 8-16ft', 'Right 8-16ft', 'Left 16-23ft', 'Center 16-23ft', 'Right 16-23ft', 'Left Center 16-23ft', ... and the three-point zones; null on some shots. |
| success | logical | True when the shot was made, false when missed. |
| x | double | Shot x: PERCENT (0-100) of the court LENGTH in the VENDOR frame, in which the HOME team always attacks the basket at x = 95 and the away team the basket at x = 5 (the frame does not flip at half-time). x_vendor = 100 - x_pbp in the halves where the home team attacks x < 50 (pleague_pbp.x is the physical frame). Court 28.75 m long: distance = hypot((x - 5) x 0.2875, (y - 50) x 0.1525) m (mean error 0.010 m on 1,893 shots). |
| y | double | Shot y: PERCENT (0-100) of the court WIDTH in the vendor frame (baskets at y = 50); y_vendor = 100 - y_pbp in the halves where the home team attacks x < 50 (held for 166 of the 168 shots of gid 197 matched to the play-by-play; one shot differs in y only). Which sideline is y = 0 is unverified. Court 15.25 m wide. |
| message_zh | character | Play text in Traditional Chinese, '{player}((Chinese text))(Chinese text)((Chinese text)){distance}(Chinese text){shot}' = '{player} made / missed a {distance} m {shot}'; the distance is in metres and matches x / y. |
| has_video | logical | True when the shot has a clip. The clip url is never kept: it carries a vendor access key. |
| home_team_uuid | character | Preciser team uuid (key space: the vendor's teams; the file name of the club logo). Joins the site team_id through pleague_standings.team_uuid: 1 = e86394aa-3d88-11ed-8ba8-7f44ba46b0b1 ((Chinese text), Taipei Fubon Braves); 2 = e865bb20-3d88-11ed-a956-7f44ba46b0b1 ((Chinese text), Taoyuan Pauian Pilots (Taoyuan Pilots from 2024-25)); 3 = e8674343-3d88-11ed-98b4-7f44ba46b0b1 ((Chinese text), Hsinchu Jko Lioneers (Toplus Lioneers from 2023-24)); 4 = e869743f-3d88-11ed-925e-7f44ba46b0b1 ((Chinese text), Formosa Taishin Dreamers (Formosa Dreamers from 2022-23)); 5 = e86cac11-3d88-11ed-8637-7f44ba46b0b1 ((Chinese text), Kaohsiung 17LIVE Steelers); 6 = e86b0ecc-3d88-11ed-bed5-7f44ba46b0b1 ((Chinese text), New Taipei Kings); 7 = 3c3a601a-358a-11ed-ab92-711c34ed1298 ((Chinese text), TSG Ghosthawks); 8 = bf957f5a-9389-11f0-812c-a38482ec4d30 ((Chinese text), Yankey Ark). |
| away_team_uuid | character | Preciser team uuid (key space: the vendor's teams; the file name of the club logo). Joins the site team_id through pleague_standings.team_uuid: 1 = e86394aa-3d88-11ed-8ba8-7f44ba46b0b1 ((Chinese text), Taipei Fubon Braves); 2 = e865bb20-3d88-11ed-a956-7f44ba46b0b1 ((Chinese text), Taoyuan Pauian Pilots (Taoyuan Pilots from 2024-25)); 3 = e8674343-3d88-11ed-98b4-7f44ba46b0b1 ((Chinese text), Hsinchu Jko Lioneers (Toplus Lioneers from 2023-24)); 4 = e869743f-3d88-11ed-925e-7f44ba46b0b1 ((Chinese text), Formosa Taishin Dreamers (Formosa Dreamers from 2022-23)); 5 = e86cac11-3d88-11ed-8637-7f44ba46b0b1 ((Chinese text), Kaohsiung 17LIVE Steelers); 6 = e86b0ecc-3d88-11ed-bed5-7f44ba46b0b1 ((Chinese text), New Taipei Kings); 7 = 3c3a601a-358a-11ed-ab92-711c34ed1298 ((Chinese text), TSG Ghosthawks); 8 = bf957f5a-9389-11f0-812c-a38482ec4d30 ((Chinese text), Yankey Ark). |
Details
Unofficial use of a THIRD-PARTY host: api.preciser.io is the analytics vendor behind the P. LEAGUE+ game page, not the league's own API. It is keyless, CORS-open, has no robots.txt (404) and no terms were found; it serves the data the league's own game page displays. The league's /user-policy reserves its content, so check it before you republish the data. Requests are spaced at least 1 s apart per host, retries included.
Wrappers take the Preciser game uuid (the
uuidcolumn ofpleague_game(); empty before 2022-23, which have no vendor data). Pass the optionalgidto verify the body against the site's game page and box: the shot list and the rotation echo nothing about the game, so only then are the uuid, the final score, the made-shot counts, the roster and the court time (rotation minutes within 30 s of the box) checked. An unknown uuid answers 200[](hoopR_no_data) or HTTP 500 (hoopR_asset_fetch, not retried).Id key spaces: the vendor names teams by uuid (
team_uuid/home_team_uuid/away_team_uuid) and persons byperson_id(the same value as the site box row'sperson_id); the site'steam_id(1-8) joins to a team uuid throughpleague_team_crosswalk()(the standings logo file name).Shot x / y are in the VENDOR frame (percent of the court, the home team always attacks x = 95) while the site's play-by-play x / y are in the physical court frame (teams swap ends at half-time): x_vendor = 100 - x_pbp and y_vendor = 100 - y_pbp in the halves where the home team attacks x < 50. The court is 28.75 x 15.25 m. Clip urls carry a vendor access key (?key=): it is scrubbed from every body, a body that still holds one is refused, and no frame keeps a url.
Errors are classed conditions, all inheriting
hoopR_error:hoopR_no_data(HTTP 404, a body of[], empty rotation lists),hoopR_bad_request(a uuid that is not a uuid, agidthat is not an integer, HTTP 400 / 422) andhoopR_asset_fetch(any other failed or wrong answer, including agidwhose game has another uuid and a redirect off the vendor host). HTTP 429 / 502 / 503 / 504 are retried, up to three attempts.
See also
Other P. LEAGUE+ Functions:
pleague_box_players(),
pleague_box_teams(),
pleague_game(),
pleague_officials(),
pleague_pbp(),
pleague_periods(),
pleague_player(),
pleague_player_seasons(),
pleague_preciser_injury(),
pleague_preciser_lead_flow(),
pleague_preciser_rotation(),
pleague_preciser_score_log(),
pleague_preciser_summary_teams(),
pleague_preciser_win_probability(),
pleague_schedule(),
pleague_standings(),
pleague_stat_player(),
pleague_team_crosswalk()
Examples
# \donttest{
try(pleague_preciser_shots(uuid = "e6f98675-3e5b-11ed-949e-5d17350689cf"))
#> ── P. LEAGUE+ Shots from api.preciser.io ──────────────────────── hoopR 3.2.0 ──
#> ℹ Data updated: 2026-10-31 21:33:26 UTC
#> # A tibble: 168 × 20
#> game_uuid shot_no period period_label clock seconds_left side team_uuid
#> <chr> <int> <int> <chr> <chr> <int> <chr> <chr>
#> 1 e6f98675-3e5b… 1 4 Q4 03:42 222 away e8674343…
#> 2 e6f98675-3e5b… 2 2 Q2 00:17 17 home e86394aa…
#> 3 e6f98675-3e5b… 3 2 Q2 05:57 357 home e86394aa…
#> 4 e6f98675-3e5b… 4 1 Q1 11:41 701 away e8674343…
#> 5 e6f98675-3e5b… 5 3 Q3 03:33 213 home e86394aa…
#> 6 e6f98675-3e5b… 6 1 Q1 06:19 379 home e86394aa…
#> 7 e6f98675-3e5b… 7 4 Q4 07:12 432 away e8674343…
#> 8 e6f98675-3e5b… 8 1 Q1 11:20 680 home e86394aa…
#> 9 e6f98675-3e5b… 9 4 Q4 10:45 645 away e8674343…
#> 10 e6f98675-3e5b… 10 3 Q3 09:34 574 home e86394aa…
#> # ℹ 158 more rows
#> # ℹ 12 more variables: person_id <chr>, player_name <chr>, type <chr>,
#> # subtype <chr>, area <chr>, success <lgl>, x <dbl>, y <dbl>,
#> # message_zh <chr>, has_video <lgl>, home_team_uuid <chr>,
#> # away_team_uuid <chr>
# }
