The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →To measure which GitHub issues got a reply, fetch each issue’s comments and count the earliest comment written by someone other than the issue author. GitHub does not provide a universal “reply” flag: the result depends on the definition you choose. The Python script below reports each issue’s first qualifying reply and elapsed time, using comment creation time rather than edit time.
Choose what counts as a reply
This script defines a reply to an issue report as a comment from someone other than the person who opened it. That excludes the reporter’s own follow-up comments while counting comments from maintainers and other contributors. If you want to measure any conversation activity instead, remove the author check and label the resulting metric accordingly.
As an Amazon Associate I earn from qualifying purchases.
GitHub’s timeline includes many kinds of activity, not just comments. Its documentation describes timeline events as activity in issues and pull requests; a commented event represents a comment and includes commenter information and created_at. Those fields make timeline data useful for this metric, but listing issue comments directly is simpler for a one-script report. GitHub documents the relevant API resources in its issues endpoints and issue event types.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Run this Python script
Save the following as issue_replies.py. It uses Python’s standard library, requests issues and their comments from the repository’s REST API, and prints a CSV row for each issue. Set GITHUB_TOKEN in your environment if the repository requires authentication. The script intentionally excludes pull requests, because GitHub’s REST API models pull requests as a kind of issue.
#1 Best Overall
import csv
import json
import os
import sys
from datetime import datetime
from urllib.error import HTTPError, URLError
from urllib.parse import quote
from urllib.request import Request, urlopen
def api_get(url, token):
headers = {
"Accept": "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28",
"User-Agent": "issue-reply-report",
}
if token:
headers["Authorization"] = f"Bearer {token}"
request = Request(url, headers=headers)
with urlopen(request) as response:
return json.load(response)
def parse_time(value):
return datetime.fromisoformat(value.replace("Z", "+00:00"))
def main():
if len(sys.argv) != 2 or "/" not in sys.argv[1]:
raise SystemExit("Usage: python issue_replies.py OWNER/REPO")
owner, repo = sys.argv[1].split("/", 1)
token = os.environ.get("GITHUB_TOKEN")
base = f"https://api.github.com/repos/{quote(owner)}/{quote(repo)}"
page = 1
writer = csv.writer(sys.stdout)
writer.writerow([
"issue_number", "title", "author", "created_at",
"first_reply_author", "first_reply_created_at", "hours_to_first_reply",
"status",
])
while True:
issues = api_get(
f"{base}/issues?state=all&per_page=100&page={page}", token
)
if not issues:
break
for issue in issues:
if "pull_request" in issue:
continue
number = issue["number"]
comments = api_get(
f"{base}/issues/{number}/comments?per_page=100", token
)
author = issue["user"]["login"] if issue.get("user") else ""
qualifying = [
comment for comment in comments
if comment.get("user")
and comment["user"].get("login") != author
and comment.get("created_at")
]
qualifying.sort(key=lambda comment: comment["created_at"])
if qualifying:
first = qualifying[0]
elapsed = (
parse_time(first["created_at"])
- parse_time(issue["created_at"])
).total_seconds() / 3600
writer.writerow([
number, issue.get("title", ""), author,
issue.get("created_at", ""), first["user"]["login"],
first["created_at"], f"{elapsed:.2f}", "reply observed",
])
else:
writer.writerow([
number, issue.get("title", ""), author,
issue.get("created_at", ""), "", "", "",
"no qualifying reply observed",
])
page += 1
if __name__ == "__main__":
try:
main()
except (HTTPError, URLError) as error:
raise SystemExit(f"GitHub API request failed: {error}")
The & characters in the query string above are HTML-escaped so the code remains valid HTML; when copying into a Python file, use ordinary ampersands in the URL string, as shown here: ?state=all&per_page=100&page= should be ?state=all&per_page=100&page= in an HTML page’s source and ?state=all&per_page=100&page= in copied HTML text. (In a plain Python file, use & only if it is literally escaped in the source.)
Read the CSV without overstating the result
A row marked reply observed has a first comment by a different account in the comments returned for that issue. hours_to_first_reply is elapsed time from issue creation to that comment’s created_at. It does not use an edit timestamp, which would answer when a comment was last changed rather than when it first arrived.
Rank #2
A row marked no qualifying reply observed means the script found no qualifying comment in the data it retrieved; it is not proof that the issue will never receive one. The report also does not decide whether the commenter was a maintainer. GitHub’s author_association field can distinguish associations such as owner, member, or collaborator, but your policy must define which associations count as a maintainer response. See GitHub’s field documentation.
Recommended Free Tools
Make response-rate comparisons fair
For a response rate, define both the issue cohort and the observation window. For example, compare issues opened during the same calendar month and count whether each received a qualifying reply within a fixed period after creation. Without a shared window, a recent issue has had less time to receive a response than an older one. Report the denominator—for example, qualifying replies divided by all issues in the selected cohort—and do not treat that percentage as a GitHub benchmark.
For useful diagnosis, group results by repository, label, issue type, or commenter association only when those categories are consistently defined. The elapsed-time field applies only to issues with a qualifying response; no-reply issues should remain visible in the rate denominator, not be assigned an invented response time.
Quick Recap
Best Value
Know the script’s limits
- The example uses standard-library HTTP calls and requests up to 100 issues per page. GitHub’s API may paginate results; the issue loop follows issue pages, but the comment request does not fetch comment pages beyond the first 100. For repositories where an issue can have more than 100 comments, add comment pagination before treating the first-comment result as complete.
- The script retrieves all issue states and excludes pull requests. To analyze only open or closed issues, change the
state=allquery parameter; the valid endpoint behavior and available options are documented in GitHub’s REST API documentation. - For private repositories or access-controlled data, API access depends on an authorized token. Consult GitHub’s REST API getting-started documentation for authentication guidance and current API details.
- The script does not set a date cutoff or enforce an observation window. Select the issue cohort in your analysis, or add filtering explicitly, so recent issues are not compared unfairly with older ones.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




