Build a GitHub Issues Dashboard with Python and Flask
Want to track issues across your GitHub repositories in one place? In this tutorial, we’ll walk through how to build a simple but effective dashboard using Python, Flask, and the GitHub API. We’ll use the requests library to retrieve issues and render them in a clean, readable format on your local server.
1. Setting Up the Project Environment
Before diving into the code, let’s start by setting up a clean Python environment. It’s a good idea to use a virtual environment to keep dependencies isolated:
python -m venv venv
source venv/bin/activate # On Windows, use venv\Scripts\activate
pip install flask requests
This installs the Flask micro-framework and Python’s requests library, which we’ll use to interact with GitHub’s REST API.
2. Accessing GitHub Issues with the API
The GitHub Issues API lets you query any public (and authenticated private) repository for open, closed, or all issues. Here’s a simple Python function to fetch issues using requests:
import requests
def fetch_issues(owner, repo):
url = f"https://api.github.com/repos/{owner}/{repo}/issues"
headers = {'Accept': 'application/vnd.github.v3+json'}
response = requests.get(url, headers=headers)
if response.status_code == 200:
return response.json()
else:
print(f"Error: {response.status_code} - {response.text}")
return []
This function fetches all issues, including pull requests (which are technically also issues). You can filter them later or use labels, state, or since parameters to fine-tune your query.
3. Creating a Flask Web Server to Display Issues
Now, it’s time to create the web dashboard. Here’s a basic Flask app that shows issues from a hard-coded repo:
from flask import Flask, render_template_string
app = Flask(__name__)
@app.route('/')
def home():
issues = fetch_issues('psf', 'requests') # Example repo: Python Software Foundation's requests
return render_template_string(template, issues=issues)
template = '''
GitHub Issues Dashboard
GitHub Issues
{% for issue in issues %}
#{{ issue.number }} - {{ issue.title }}
State: {{ issue.state }} | Created by: {{ issue.user.login }}
{% else %}
No issues found.
{% endfor %}
'''
if __name__ == '__main__':
app.run(debug=True)
This creates a local web server at http://127.0.0.1:5000 and fetches real-time issues every time you visit the homepage.
4. Enhancing the Dashboard with Filters and Multiple Repos
Let’s make the tool more flexible by allowing users to specify a repo in the URL query string. This way, the dashboard can support multiple repositories:
from flask import request
@app.route('/')
def home():
owner = request.args.get('owner', 'psf')
repo = request.args.get('repo', 'requests')
issues = fetch_issues(owner, repo)
return render_template_string(template, issues=issues, owner=owner, repo=repo)
Update your template title for clarity and improved UX:
<h1>Issues in {{ owner }}/{{ repo }}</h1>
Now you can navigate to URLs like http://127.0.0.1:5000/?owner=flask&repo=flask to check another project’s issues.
5. Authentication for Higher Rate Limits and Private Repositories
GitHub’s public API has a rate limit of 60 requests/hour for unauthenticated users. Authenticated requests enjoy much larger limits. Here’s how to add a token header:
import os
GITHUB_TOKEN = os.environ.get('GITHUB_TOKEN')
headers = {
'Accept': 'application/vnd.github.v3+json',
'Authorization': f'token {GITHUB_TOKEN}'
}
Be sure to set your token in the environment before running the app:
export GITHUB_TOKEN="your_personal_access_token"
This allows you to access private repos and avoid dropped requests due to rate limiting.
6. Bonus: Caching and Performance Tips
To avoid excessive GitHub API calls and speed things up, consider caching responses using Flask-Caching or an in-memory store like Redis. For small-scale use, even a simple in-script cache can help:
issue_cache = {}
def fetch_issues(owner, repo):
key = f"{owner}/{repo}"
if key in issue_cache:
return issue_cache[key]
url = f"https://api.github.com/repos/{owner}/{repo}/issues"
response = requests.get(url, headers=headers)
if response.status_code == 200:
issue_cache[key] = response.json()
return issue_cache[key]
return []
Be mindful of stale data and add expiration timers if needed for production scenarios.
Conclusion
You now have a basic GitHub Issues Dashboard built entirely in Python using Flask and the GitHub API. It can be extended with more advanced filters, pagination, login/auth flows, and issue triaging features. This is a great tool for open-source maintainers and dev teams to get instant visibility into their repo activity. Happy coding!
Useful links:

