Finding great developers is hard. But there's a talent pool hiding in plain sight: GitHub profiles.
Thousands of developers actively signal they're open to new opportunities — right in their GitHub bio. And with the GitHub Search API, you can find them programmatically.
In this guide, I'll show you exactly how to do it.
Why GitHub Is Underutilized for Talent Sourcing
Most recruiters live on LinkedIn. Some check Stack Overflow. Almost nobody systematically searches GitHub.
That's a missed opportunity. A quick search reveals that over 4,800 developers currently have "open to work" in their GitHub bio. These are people who:
- Actively maintain code you can review before reaching out
- Have public contribution histories showing consistency
- Often list their tech stack, location, and contact info
- Are signaling availability without the noise of LinkedIn's "open to work" badge
Unlike a resume, a GitHub profile shows you what someone actually builds. You can see their code quality, the languages they use, how they collaborate, and whether they ship.
The GitHub Search API
GitHub's User Search API lets you query profiles by bio content, location, language, and more.
The basic endpoint:
GET https://api.github.com/search/users?q=open+to+work+in:bio&per_page=100
This searches for users who have "open to work" somewhere in their bio. The in:bio qualifier restricts the search to the biography field.
A typical response looks like:
{
"total_count": 4835,
"items": [
{
"login": "devuser123",
"id": 12345678,
"avatar_url": "https://avatars.githubusercontent.com/u/12345678",
"html_url": "https://github.com/devuser123",
"type": "User"
}
]
}
The search results give you basic profile info. To get the full picture, you'll need a second API call (more on that below).
Filtering by Location
Looking for developers in a specific city or country? Add location: to your query:
GET https://api.github.com/search/users?q=open+to+work+in:bio+location:Berlin&per_page=100
This returns developers who mention "open to work" in their bio AND have "Berlin" in their location field. You can use any city, country, or region:
location:"New York"location:Germanylocation:"San Francisco"-
location:Remote(yes, some people list this)
Filtering by Programming Language
Want only Python developers? Or JavaScript specialists? Add language: to narrow results:
GET https://api.github.com/search/users?q=open+to+work+in:bio+language:python&per_page=100
This filters by the primary language in the user's repositories. You can combine filters:
GET https://api.github.com/search/users?q=open+to+work+in:bio+language:typescript+location:London&per_page=100
Now you're finding TypeScript developers in London who are open to work. That's a very targeted list.
Getting Full Profile Details
The search endpoint returns minimal data. To get the full profile — name, bio, company, blog, email, number of repos, and the hireable flag — hit the Users endpoint:
GET https://api.github.com/users/{login}
Response:
{
"login": "devuser123",
"name": "Jane Developer",
"bio": "Full-stack engineer | Open to work | React, Node, Python",
"location": "Berlin, Germany",
"email": "jane@example.com",
"hireable": true,
"public_repos": 42,
"followers": 156,
"blog": "https://janedev.com",
"created_at": "2019-03-15T00:00:00Z"
}
The hireable field is a boolean that users can set in their GitHub settings. When combined with "open to work" in the bio, you have a strong signal that this person is actively looking.
Putting It Together: A Python Script
Here's a working script that searches for candidates and fetches their details:
import requests
import time
GITHUB_TOKEN = "ghp_your_token_here" # Optional but recommended
HEADERS = {"Authorization": f"token {GITHUB_TOKEN}"} if GITHUB_TOKEN else {}
def search_candidates(query="open to work in:bio", max_pages=3):
candidates = []
for page in range(1, max_pages + 1):
url = "https://api.github.com/search/users"
params = {"q": query, "per_page": 100, "page": page}
resp = requests.get(url, headers=HEADERS, params=params)
resp.raise_for_status()
data = resp.json()
print(f"Page {page}: {len(data['items'])} users "
f"(total: {data['total_count']})")
for user in data["items"]:
# Fetch full profile
profile = requests.get(
f"https://api.github.com/users/{user['login']}",
headers=HEADERS
).json()
candidates.append({
"username": profile.get("login"),
"name": profile.get("name"),
"bio": profile.get("bio"),
"location": profile.get("location"),
"email": profile.get("email"),
"hireable": profile.get("hireable"),
"repos": profile.get("public_repos"),
"url": profile.get("html_url"),
})
time.sleep(2) # Respect rate limits
time.sleep(6) # Pause between search pages
return candidates
# Search for Python developers in Germany
results = search_candidates(
query="open to work in:bio language:python location:Germany"
)
for dev in results:
print(f"{dev['name']} — {dev['location']}")
print(f" Bio: {dev['bio']}")
print(f" Repos: {dev['repos']} | Email: {dev['email']}")
print(f" {dev['url']}")
print()
Rate Limits: What You Need to Know
GitHub's API has strict rate limits:
| Auth Level | Search Requests | User Requests |
|---|---|---|
| No token | 10/minute | 60/hour |
| Personal Access Token | 30/minute | 5,000/hour |
For any serious use, you'll want a Personal Access Token. Even a fine-grained token with zero permissions will give you the higher limits.
The script above includes time.sleep() calls to stay under limits, but if you're processing hundreds of profiles, expect it to take a while.
Practical Tips
Vary your search terms. Not everyone writes "open to work." Try:
looking for opportunities in:bioseeking new role in:bioavailable for hire in:bio-
hireable:true(the GitHub setting, no bio text needed)
Check contribution activity. A profile with recent commits is a better signal than one that's been dormant for a year. The Users API gives you updated_at — use it.
Respect people's privacy. Just because someone's profile is public doesn't mean they want cold emails. If they list an email, a thoughtful message referencing their actual work goes a long way. Generic recruiter spam does not.
Export to CSV. Add a few lines to the script above to dump results into a spreadsheet for your team:
import csv
with open("candidates.csv", "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=results[0].keys())
writer.writeheader()
writer.writerows(results)
If You Don't Want to Code It
The API approach works great if you're comfortable with Python and don't mind handling pagination, rate limits, and data cleanup.
If you'd rather skip the scripting, there are tools that wrap this into a point-and-click workflow. For example, the GitHub Candidates Scraper on Apify does exactly what the code above does — searches GitHub for developers matching your criteria and returns structured data with skills, repos, and contact info. Useful if you need results fast without maintaining a script.
Wrapping Up
GitHub is one of the most underused sourcing channels for technical talent. The data is public, the API is free, and thousands of developers are actively signaling availability.
Whether you write your own script or use an existing tool, the key insight is the same: the best candidates are already showing you their work. You just need to look.
Have questions or want to share your approach? Drop a comment below.
Top comments (0)