Play-by-play of one finished game (2022-23 on) in game order, with shot x / y and the clip references.
Endpoint: GET https://pleagueofficial.com/api/playbyplay.php?uuid={uuid} (after the game page, which holds the uuid)
Value
A hoopR_data tibble: Play-by-play of one finished game (2022-23 on) in game order, with shot x / y and the
clip references. An empty valid answer is a zero-row tibble with these columns, in this order (sportsdataverse-py
pleague_pbp):
| col_name | type | description |
| gid | integer | P. LEAGUE+ game id on the site: ONE global integer sequence over every stage and season (1-12 = 2020-21 pre-season, 13 = the 2020-21 opener, 197 = the 2022-23 opener, 662 = the 2025-26 opener), with gaps; a row id, not a count. The {gid} of /game/{gid}. |
| seq | integer | Position of the play in game order, 1-based (the fragment lists plays oldest first within the fragment). |
| period | character | Period label: Q1-Q4, then OT1, OT2 for overtime. |
| period_no | integer | 1-based position of the period: 1-4 for Q1-Q4, then 5 for OT1, 6 for OT2. |
| clock | character | Game clock REMAINING in the period 'mm:ss' (counts down; Q1 opens at 12:00, OT at 05:00). |
| seconds_left | integer | The clock as whole seconds remaining in the period (08:34 = 514), derived by the parser. |
| side | character | Side of the acting team: away or home (the fragment places the play in the away or home column). |
| jersey | character | Shirt number of the acting player as printed; null on team rows and where the name is printed without a number. |
| player_zh | character | Acting player's name as printed; null on team rows (a team rebound, timeout or shot-clock violation). The page prints no player ids: join to the box on side, jersey and name_zh. |
| action | character | Action code (one of the codes listed under "Action codes" below; an unseen phrase is refused as layout drift). |
| action_zh | character | The action phrase as printed, Traditional Chinese ((Chinese text) = dunk, made; '#35 (Chinese text)' = '#35 {player} dunk, made'); blank on an unlabelled row. Each of the 82 observed phrases maps to one action code (see action). |
| action_en | character | English meaning of the play's phrase (see action), so a free throw reads its own trip, e.g. 'free throw 2, made'; null for a code outside the observed table. |
| text_zh | character | The whole printed text of the play, e.g. '#35 (Chinese text)' = '#35 {player} dunk, made'. |
| ft_number | integer | Which free throw of the trip this is (1, 2 or 3), from (Chinese text); null on every other play. |
| ft_awarded | integer | Free throws awarded in the trip (1, 2 or 3) from (Chinese text); set only on the FIRST free throw's row, null otherwise. |
| points | integer | Points scored by the play from the '+2' / '+3' / '+1' tag; null when the tag is a bare '+'. |
| score_away | integer | Away score after the play, from the 'A - H' cell (AWAY first, unlike the box); null on plays that print no score (substitutions, rebounds, jump balls). |
| score_home | integer | Home score after the play, from the 'A - H' cell; null when the play prints no score. |
| x | double | Shot / play x: PERCENT (0-100) of the court LENGTH in the PHYSICAL court frame (not normalised per team): baskets near x = 5 and x = 95, teams swap ends at half-time. The Preciser shot list uses a home-attacks-95 frame: x_vendor = 100 - x in the halves where the home team attacks x < 50. Null on plays without a location. Court 28.75 m long. |
| y | double | Shot / play y: PERCENT (0-100) of the court WIDTH in the physical frame (baskets at y = 50); y_vendor = 100 - y in the halves where the home team attacks x < 50. Which sideline is y = 0 is unverified. Court 15.25 m wide. |
| nice_play | logical | True when the site stars the play (a nice_play row class and a starred clip). |
| video_uuid | character | Clip uuid (key space: the clip vendor tryspot); null on plays without a clip (about 3 in 4). The clip urls are never kept: they carry a vendor access key. |
| synergy_play_id | character | Synergy Sports play uuid of the clip (the site links Synergy); a string on every one of the 50,862 clips in the corpus. |
| video_stat_category | character | The clip's own stat label (ast, blk, ft_made, ft_miss, pfoul, reb_d, reb_o, stl, three_made, three_miss, timeout, turnover, two_made, two_miss): it names the PLAY the clip shows, not always this row's action (a rebound row carries the missed shot's clip). |
| tryspot_player_id | integer | Player id in the clip vendor's key space (an integer such as 59476); NOT the box player_id. |
| video_created_at | character | When the clip was created, UTC ISO 8601 with milliseconds. |
Details
Source, terms of use, request pacing, seasons, ids, coverage and error classes of this family: see the notes in pleague_schedule().
Action codes
Each code of action, its meaning and [the number of plays] in 258,183 plays of 404 finished 2022-23..2025-26 games (82 printed phrases plus the blank row):
ast: assist [17,020]blk: block [3,181]fg2_alley_oop_made: 2-point alley-oop, made [205]fg2_alley_oop_missed: 2-point alley-oop, missed [81]fg2_driving_layup_made: 2-point driving layup, made [4,281]fg2_driving_layup_missed: 2-point driving layup, missed [3,961]fg2_dunk_made: 2-point dunk, made [1,316]fg2_dunk_missed: 2-point dunk, missed [162]fg2_fadeaway_jumper_made: 2-point fadeaway jumper, made [583]fg2_fadeaway_jumper_missed: 2-point fadeaway jumper, missed [1,121]fg2_floater_made: 2-point floater, made [1,920]fg2_floater_missed: 2-point floater, missed [3,052]fg2_hook_shot_made: 2-point hook shot, made [610]fg2_hook_shot_missed: 2-point hook shot, missed [773]fg2_jump_shot_made: 2-point jump shot, made [1,657]fg2_jump_shot_missed: 2-point jump shot, missed [3,606]fg2_layup_made: 2-point layup, made [4,428]fg2_layup_missed: 2-point layup, missed [3,403]fg2_pull_up_jumper_made: 2-point pull-up jumper, made [1,004]fg2_pull_up_jumper_missed: 2-point pull-up jumper, missed [1,564]fg2_putback_made: 2-point putback / tip-in, made [2,138]fg2_putback_missed: 2-point putback / tip-in, missed [1,539]fg2_step_back_shot_made: 2-point step-back shot, made [243]fg2_step_back_shot_missed: 2-point step-back shot, missed [410]fg2_turnaround_jumper_made: 2-point turnaround jumper, made [672]fg2_turnaround_jumper_missed: 2-point turnaround jumper, missed [1,158]fg3_fadeaway_jumper_made: 3-point fadeaway jumper, made [48]fg3_fadeaway_jumper_missed: 3-point fadeaway jumper, missed [92]fg3_made: 3-point shot, style not recorded, made [7,817]fg3_missed: 3-point shot, style not recorded, missed [17,046]fg3_pull_up_jumper_made: 3-point pull-up jumper, made [480]fg3_pull_up_jumper_missed: 3-point pull-up jumper, missed [922]fg3_step_back_shot_made: 3-point step-back shot, made [245]fg3_step_back_shot_missed: 3-point step-back shot, missed [559]fg3_turnaround_jumper_made: 3-point turnaround jumper, made [10]fg3_turnaround_jumper_missed: 3-point turnaround jumper, missed [23]fg_made: field goal made, shot type and distance not recorded [158]fg_missed: field goal missed, shot type and distance not recorded [168]foul: foul, kind not recorded (team row) [18]foul_bench_technical: technical foul on the bench [35]foul_coach_technical: technical foul on the coach [75]foul_disqualifying: disqualifying foul [2]foul_drawn: foul drawn (the opponent's foul on this player) [17,035]foul_offensive: offensive foul committed [1,024]foul_personal: personal foul committed [15,745]foul_technical: technical foul [210]foul_unsportsmanlike: unsportsmanlike foul [261]ft_made: free throw 1 of 1 awarded, made [1,326]ft_made: free throw 1 of 3 awarded, made [128]ft_made: free throw 1 of 2 awarded, made [5,187]ft_made: free throw 3, made [149]ft_made: free throw 2, made [5,798]ft_missed: free throw 1 of 1 awarded, missed [669]ft_missed: free throw 1 of 3 awarded, missed [67]ft_missed: free throw 1 of 2 awarded, missed [2,736]ft_missed: free throw 3, missed [46]ft_missed: free throw 2, missed [2,319]jump_ball_lost: jump ball lost [404]jump_ball_won: jump ball won [708]reb_def: defensive rebound (a team rebound has no player) [29,537]reb_off: offensive rebound (a team rebound has no player) [12,379]review_coach_challenge: video review: coach's challenge (2025-26 onward; the printed text ends with a bare comma) [videoReview, coachChallenge,, 82]review_instant_replay: video review: instant-replay system, started by the officials (2025-26 onward) [videoReview, instantReplaySystem,, 67]review_instant_replay_1: video review: instant-replay system, variant printed with a trailing '1' (meaning unexplained; the row also prints the running score and the points tag '+videoReview') [videoReview, instantReplaySystem, 1, 6]stl: steal [7,361]sub_in: substitution: enters the game [25,505]sub_out: substitution: leaves the game [25,532]timeout: timeout (a team row) [2,854]tov_3sec: turnover: 3-second violation [249]tov_5sec: turnover: 5-second violation [40]tov_8sec: turnover: 8-second violation [26]tov_backcourt: turnover: backcourt violation [96]tov_bad_pass: turnover: bad pass [6,325]tov_ball_handling: turnover: ball-handling [3,547]tov_carrying: turnover: carrying the ball [47]tov_double_dribble: turnover: double dribble [53]tov_offensive: turnover: offensive (kind not recorded) [1,007]tov_offensive_goaltending: turnover: offensive goaltending [4]tov_other: turnover: other [51]tov_out_of_bounds: turnover: ball out of bounds [441]tov_shot_clock: turnover: shot-clock violation [489]tov_travel: turnover: travelling [718]unlabelled: row has a player but no action text; in the corpus a shot with x/y followed by a rebound, i.e. a missed shot (inferred) [(blank), 169]
See also
Other P. LEAGUE+ Functions:
pleague_box_players(),
pleague_box_teams(),
pleague_game(),
pleague_officials(),
pleague_periods(),
pleague_player(),
pleague_player_seasons(),
pleague_preciser_injury(),
pleague_preciser_lead_flow(),
pleague_preciser_rotation(),
pleague_preciser_score_log(),
pleague_preciser_shots(),
pleague_preciser_summary_teams(),
pleague_preciser_win_probability(),
pleague_schedule(),
pleague_standings(),
pleague_stat_player(),
pleague_team_crosswalk()
Examples
# \donttest{
try(pleague_pbp(gid = 197))
#> ── P. LEAGUE+ Play-by-Play from pleagueofficial.com ───────────── hoopR 3.2.0 ──
#> ℹ Data updated: 2026-10-31 21:33:23 UTC
#> # A tibble: 630 × 26
#> gid seq period period_no clock seconds_left side jersey player_zh action
#> <int> <int> <chr> <int> <chr> <int> <chr> <chr> <chr> <chr>
#> 1 197 1 Q1 1 12:00 720 away 35 辛巴 jump_…
#> 2 197 2 Q1 1 12:00 720 home 5 強森 jump_…
#> 3 197 3 Q1 1 11:41 701 away 35 辛巴 fg2_d…
#> 4 197 4 Q1 1 11:41 701 away 31 阿提諾 ast
#> 5 197 5 Q1 1 11:20 680 home 5 強森 fg3_m…
#> 6 197 6 Q1 1 10:53 653 away 8 朱雲豪 tov_b…
#> 7 197 7 Q1 1 10:53 653 home 5 強森 stl
#> 8 197 8 Q1 1 10:49 649 home NA 賴廷恩 fg3_m…
#> 9 197 9 Q1 1 10:42 642 away 35 辛巴 fg2_l…
#> 10 197 10 Q1 1 10:42 642 away 9 田浩 ast
#> # ℹ 620 more rows
#> # ℹ 16 more variables: action_zh <chr>, action_en <chr>, text_zh <chr>,
#> # ft_number <int>, ft_awarded <int>, points <int>, score_away <int>,
#> # score_home <int>, x <dbl>, y <dbl>, nice_play <lgl>, video_uuid <chr>,
#> # synergy_play_id <chr>, video_stat_category <chr>, tryspot_player_id <int>,
#> # video_created_at <chr>
# }
