Exporting to CSV & files
CSV
Every leaderboard (facet-*) and signature-stat command, plus player-position-pivot — 33 commands in all — accepts --export true and answers with CSV instead of JSON. Add --rsh-print b so Restish prints only the response body — no headers, no pretty-printing — and redirect it to a file:
restish pff passing --league nfl --season 2025 --export true --rsh-print b > passing-2025.csv
player,player_id,position,team_name,player_game_count,accuracy_percent,aimed_passes,attempts,...
Matthew Stafford,4924,QB,LA,20,72.3,672,716,...
Caleb Williams,144622,QB,CHI,21,69.9,614,683,...
The first line is the header, so it opens directly in Excel, Google Sheets, or pandas.read_csv().
Why
--rsh-print b? Restish normally renders responses as structured data and, in a terminal, pretty-prints them. Applied to a CSV body,-o jsonwould wrap the whole file in one quoted string with the line breaks escaped.--rsh-print bprints only the response body, with no headers and no pretty-printing — for a CSV response, that is the CSV text itself.
To check whether a command can export, look for --export in its help:
restish pff facet-rushing-summary --help | grep export
CSV from the team tables
The team-* tables — PFF’s own contract, see Querying — don’t use --export. Add --format csv instead; the header row is the table’s column keys:
restish pff team-directory nfl --season 2025 --format csv --rsh-print b > teams-2025.csv
franchiseId,slug,name,city,nickname,abbreviation,primaryColor,secondaryColor,groupIds
1,arizona-cardinals,Arizona Cardinals,Arizona,Cardinals,ARZ,#97233f,#ffffff,6;10
2,atlanta-falcons,Atlanta Falcons,Atlanta,Falcons,ATL,#a71930,#000000,6;9
team-rushing-direction carries two tables; --table totals exports the second one instead of the per-rusher rows:
restish pff team-rushing-direction nfl los-angeles-rams --season 2025 --format csv --table totals --rsh-print b > rams-rushing-totals.csv
--format csv spends the same per-minute export budget as --export true.
JSON
Every command returns JSON by default. Use -o json for a clean, uncoloured document and redirect it:
restish pff passing --league nfl --season 2025 -o json > passing-2025.json
restish pff player-passing-summary nfl 4924 --season 2025 -o json > stafford-2025.json
Pipe straight into jq to reshape it:
restish pff passing --league nfl --season 2025 -o json \
| jq -r '.passing_summary[] | [.player, .team, .grades_pass] | @csv'
Or let Restish do the filtering:
restish pff passing --league nfl --season 2025 -f 'body.passing_summary[].grades_pass' -o lines
Recipes
One file per week
for week in 1 2 3 4; do
restish pff passing --league nfl --season 2025 --week $week --export true --rsh-print b \
> "passing-2025-week-$week.csv"
done
Several seasons in one file — seasons take a comma-separated list, so you often don’t need a loop:
restish pff rushing --league nfl --season 2023,2024,2025 --export true --rsh-print b > rushing-3yr.csv
In CI — use an API-key profile (see Log in) with PFF_API_KEY in the job’s secrets, and add -p ci:
restish pff passing --league nfl --season 2025 --export true --rsh-print b -p ci > passing.csv
Be deliberate with exports. Exports —
--export trueand--format csvalike — are metered per account, per minute (see Troubleshooting for the429). Download a file once and work from the file rather than re-running the export in a loop. An export with no rows and no header line means your account isn’t entitled to that league or report — run the same query without--exportto see the columns you can access and, underrestricted, the ones withheld. (An entitled export with no matching records still has its header line.)
Next: Troubleshooting — every message you might see, and the fix for each.