runmypr Guides · Mergestorm affiliate Try it free

Guides · Metrics

How to measure PR review time on GitHub (free script)

Published Oct 6, 2026 · ~8 min

A terminal showing PR review time statistics

GitHub does not show you how long pull requests wait for review. Insights shows how many PRs were opened and merged, not how long anyone waited. Paid engineering-metrics tools do, but you do not need one to get the number this week.

This guide gives you a free script that measures PR review time for any repo you can read, explains what each number means, and lists the mistakes that make these numbers lie.

What to measure

Report each as a median and a p90 (the time nine out of ten PRs beat). Averages are useless here: one PR forgotten for a month distorts them for weeks.

The script

pr_review_stats.py is about 150 lines of Python with no dependencies. It uses the GitHub CLI you probably already have, so it works on private repos without creating a token.

curl -O https://runmypr.com/tools/pr_review_stats.py
gh auth status        # must be logged in
python3 pr_review_stats.py your-org/your-repo --prs 200

It reads your most recent merged PRs through the GitHub GraphQL API and handles the details that trip up most homemade versions:

Example output

Here is the real output for the last 100 merged PRs in facebook/react, run on Oct 6, 2026:

facebook/react: last 100 merged PRs, 99 with a human review

  Time to first review     median    5.4h   p75   22.1h   p90    5.2d   n=99
  Time to merge            median   40.5h   p75    8.1d   p90   13.1d   n=100
  Cycle time               median   37.0h   p75    7.4d   p90   13.4d   n=100

Time to first review by PR size (lines added + deleted)
  0-50 lines               median    6.9h   p75   18.4h   p90    5.2d   n=29
  51-200 lines             median    3.5h   p75   24.8h   p90    6.1d   n=45
  201-400 lines            median    3.7h   p75   12.6h   p90   38.4h   n=13
  401-1000 lines           median   19.7h   p75   22.1h   p90    8.6d   n=7
  1001+ lines              median   44.4h   p75    2.8d   p90    2.9d   n=5

1 PRs merged with no human review.

How to read it

Median vs p90

React’s median first review is 5.4 hours, which is excellent. Its p90 is 5.2 days. Both are true at once: most PRs are picked up fast, and a meaningful minority are forgotten. If your p90 is more than five times your median, you do not have a speed problem, you have an ownership problem: some PRs have no obvious reviewer.

Time to first review vs time to merge

React picks PRs up in hours but takes 40 hours to merge them. That gap is review rounds, CI and approval. If your gap is large, the first review is not the bottleneck; the rounds after it are.

The size table

This is usually the most persuasive part for a team. In React’s data, PRs up to 400 lines get a first review in a median of 4.5 hours; PRs over 1,000 lines wait 44. Small samples in the big buckets, but the pattern is the reason to read how big a pull request should be.

The quick version: one line of gh

If you just want to eyeball the last few PRs, this prints the hours from PR open to first non-bot review (it does not handle drafts, so use the script for real numbers):

gh pr list -R your-org/your-repo --state merged --limit 20 \
  --json number,createdAt,author,reviews --jq '.[]
  | .author.login as $me
  | ([.reviews[] | select(.author.login != $me
      and (.author.login | test("\\[bot\\]$|-app$|^copilot") | not))
      | .submittedAt] | min) as $first
  | [.number, (if $first then
      (((($first | fromdateiso8601) - (.createdAt | fromdateiso8601))
        / 3600 * 10 | floor) / 10 | tostring) + "h"
      else "no human review" end)]
  | @tsv'

Mistakes that make the numbers lie

What to do with the numbers

  1. Run it today and write down the median and p90 for time to first review.
  2. Pick one change: a review rotation, a size limit, or an automated first pass on every PR.
  3. Run it again in two weeks with the same --prs value and compare.

For what a good number looks like, see how long a PR review should take.