Export public GitHub commit-author emails, contributor identity fields, timestamps, and commit evidence from repositories or organizations.
GitHub Contributor Email Scraper uses GitHub's official APIs and saves clean dataset rows for CSV, Excel, JSON, API, automation, and authorized research workflows. It supports tokenless REST for small public jobs and authenticated GraphQL for efficient, quota-aware commit-history queries.
What data does it export?
- Public commit-author email and name
- GitHub login and profile URL when GitHub links the commit to an account
- Repository owner and name
- Commit SHA and evidence URL
- Commit timestamp and a short message snippet
- Noreply-email status
- Explicit-repository or organization-discovery provenance
- REST or GraphQL route provenance
The Actor does not infer private emails, access private repositories, use login cookies, or bypass GitHub privacy settings.
Example input
{
"repositories": [
"apify/crawlee",
"apify/apify-sdk-js"
],
"maxCommitsPerRepo": 100,
"since": "2026-01-01",
"includeNoreplyEmails": false,
"dedupeByEmail": true,
"apiMode": "auto"
}
Use repositoryUrls when you have full GitHub URLs, repositories for owner/repo values, or organization to discover public repositories belonging to an organization.
Example output
{
"repository": "apify/crawlee",
"owner": "apify",
"repo": "crawlee",
"commitSha": "abc123",
"commitUrl": "https://github.com/apify/crawlee/commit/abc123",
"authorName": "Example Developer",
"authorEmail": "dev@example.com",
"isNoreplyEmail": false,
"githubLogin": "exampledev",
"profileUrl": "https://github.com/exampledev",
"committedAt": "2026-01-01T12:00:00Z",
"messageSnippet": "Improve retry handling",
"sourceType": "repository",
"scrapedAt": "2026-07-20T12:00:00Z",
"apiMode": "graphql"
}
Every dataset row keeps a commit URL and SHA so you can review the public source evidence.
Input settings
| Setting | API key | Description |
|---|---|---|
| Repository URLs | repositoryUrls |
Up to 100 public GitHub repository URLs. |
| Repository names | repositories |
Up to 100 owner/repo values or full repository URLs. |
| Organization login | organization |
Optional GitHub organization login or profile URL. |
| Maximum organization repositories | maxRepositories |
Public organization repositories to discover, from 1 to 100. Default: 20. |
| Maximum commits per repository | maxCommitsPerRepo |
Recent commits inspected per repository, from 1 to 1,000. Default: 20. |
| Since date | since |
Optional ISO date or timestamp lower bound. |
| Until date | until |
Optional ISO date or timestamp upper bound. |
| Branch | branch |
Optional branch name. Blank uses each repository's default branch. |
| Include noreply emails | includeNoreplyEmails |
Keep GitHub noreply addresses. Default: false. |
| Deduplicate by email | dedupeByEmail |
Save the first row for each email across the run. Default: true. |
| GitHub API mode | apiMode |
auto, rest, or graphql. Default: auto. |
| Maximum active run seconds | maxRunSeconds |
Optional active-work cutoff from 1 to 270 seconds. Pending work is checkpointed. |
| GitHub token | githubToken |
Optional secret token for GraphQL and higher GitHub limits. Public-repository read access is sufficient. |
At least one repository input or an organization is required. Invalid GitHub hosts, malformed repository names, invalid dates, and unsafe branch names are rejected before paid or network work.
REST and GraphQL modes
apiMode: "auto" is recommended:
- With a
githubToken, the Actor uses GitHub GraphQL. - Without a token, the Actor uses GitHub REST.
Choose rest to force REST even when a token is present. Choose graphql to force GraphQL; this mode requires githubToken.
GraphQL queries the default branch through defaultBranchRef or the selected branch, requests only the fields used in the dataset, and follows forward cursors. REST remains available for backward-compatible tokenless tasks.
Neither route is an unlimited-rate workaround. The Actor honors GitHub retry/reset guidance, bounds retries, detects GraphQL errors returned with HTTP 200, and stops admitting work before the Apify timeout.
Repository and organization behavior
Explicit repositories retain sourceType: "repository".
Repositories discovered from organization use sourceType: "organization". If the same repository appears in both places, the explicit source wins and the row is not duplicated for discovery provenance.
maxRepositories limits only organization discovery. Explicit repository inputs remain separate, and all sources are deduplicated by canonical owner/repo.
Date and branch filters
since and until accept ISO dates or timestamps:
{
"repositories": ["apify/crawlee"],
"since": "2026-01-01T00:00:00Z",
"until": "2026-06-30T23:59:59Z"
}
Use branch for a non-default branch:
{
"repositories": ["owner/repository"],
"branch": "release/v1",
"maxCommitsPerRepo": 100
}
If a valid date range or empty repository has no matching commits, the run succeeds with zero rows and records the reason in RUN_SUMMARY. If every repository is unavailable or fails, the run fails instead of presenting a misleading empty success.
Noreply filtering and email deduplication
GitHub users can author commits with privacy-protecting addresses ending in users.noreply.github.com.
- Keep
includeNoreplyEmails: falseto exclude these addresses. - Set it to
truefor complete public commit evidence.
With dedupeByEmail: true, only the first row for each case-insensitive email is saved across all repositories. Disable it when you need a row for every inspected commit that contains an included email.
Run summary and pending work
The default key-value store contains:
RUN_SUMMARY— route, requested/completed/failed repository counts, processed commits, saved rows, skip counts, empty reason, warnings, and classified repository errors.PENDING_WORK— the repository and page/cursor checkpoint used when work remains.
Rows are saved progressively. Saving a paid row and charging the item event are one operation. If a later repository fails or the active-work deadline is reached, completed rows remain available.
On a successful complete run, PENDING_WORK is cleared. On a forced cutoff, the run fails honestly with partial output and a resumable checkpoint.
Who is this for?
This Actor is designed for teams that have authorization to work with public Git commit metadata, including:
- developer relations and open-source program teams;
- recruiting and talent research teams;
- repository maintainers and engineering analytics teams;
- security, compliance, and software-supply-chain analysts;
- data teams building approved contributor directories or audits.
It is not a private-email discovery service. It exports only author identity fields already attached to public commits returned by GitHub's official APIs.
Common workflows
Authorized contributor research: Export recent public commit evidence for repositories you are permitted to analyze.
Developer relations: Identify contributors across owned or authorized open-source projects and retain a source commit for review.
Repository auditing: Include noreply addresses and disable deduplication to examine commit-level author metadata.
Organization reporting: Discover a bounded set of public organization repositories and export a unified dataset.
Recurring monitoring: Use since with Apify schedules to collect recent commit-author records at a controlled cadence.
Schedule recurring exports
Save a task with a bounded repository list and date filter, then attach it to an Apify schedule.
For recurring jobs:
- Keep repository and commit limits conservative.
- Use a GitHub token for GraphQL or larger workloads.
- Advance
sincein your automation when you need incremental windows. - Check
RUN_SUMMARYbefore treating a partial multi-repository result as complete. - Use the dataset's stable repository/SHA/email combination when merging runs.
API usage
Node.js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('fetch_cat/github-contributor-email-scraper').call({
repositories: ['apify/crawlee'],
maxCommitsPerRepo: 100,
includeNoreplyEmails: false,
dedupeByEmail: true,
apiMode: 'auto',
githubToken: process.env.GITHUB_TOKEN
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
Python
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("fetch_cat/github-contributor-email-scraper").call(run_input={
"repositories": ["apify/crawlee"],
"maxCommitsPerRepo": 100,
"includeNoreplyEmails": False,
"dedupeByEmail": True,
"apiMode": "rest",
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
cURL
curl -X POST \
"https://api.apify.com/v2/acts/fetch_cat~github-contributor-email-scraper/runs" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"repositories": ["apify/crawlee"],
"maxCommitsPerRepo": 100,
"apiMode": "rest"
}'
Pass Apify authentication in the header so it does not enter URL history or request logs. Put githubToken in the secret input field rather than source code.
Use with MCP and AI agents
This Actor works through the official Apify MCP server. The focused endpoint exposes only this Actor:
https://mcp.apify.com?tools=fetch_cat/github-contributor-email-scraper
Claude Code:
claude mcp add apify-github-contributor-email \
--url "https://mcp.apify.com?tools=fetch_cat/github-contributor-email-scraper"
Claude Desktop:
{
"mcpServers": {
"apify-github-contributor-email": {
"url": "https://mcp.apify.com?tools=fetch_cat/github-contributor-email-scraper"
}
}
}
Example prompts:
- "Run the GitHub Contributor Email Scraper for apify/crawlee with 50 commits and exclude noreply addresses."
- "Export commit-level author evidence from these authorized repositories without email deduplication."
- "Scan the default branches of these repositories since 2026-01-01 and summarize RUN_SUMMARY before using the rows."
Tips for better results
- Start with one repository and 20-100 commits.
- Use
apiMode: "auto"with a GitHub token for GraphQL. - Use
branchonly when you know the requested branch exists across the repositories. - Keep
dedupeByEmailenabled for one row per address. - Disable deduplication for commit-level evidence and expect more rows.
- Review
RUN_SUMMARYfor partial repository failures and rate-limit diagnostics. - If GitHub returns a reset time, wait rather than immediately launching repeated large runs.
Limits and practical notes
- Public repositories only.
- The selected branch history is linear and follows GitHub's API semantics.
- A commit email may not belong to a deliverable mailbox.
- GitHub may return no linked login even when the commit has an author name and email.
- Noreply addresses intentionally protect a contributor's contact address.
- Rewritten Git history can change or remove earlier commit evidence.
- REST and GraphQL have separate primary limits but share secondary protections.
- The Actor retries transient failures only within a bounded run deadline.
- It does not use residential proxies, browser automation, cookies, or private-repository permissions.
Legality and responsible use
Use this Actor only within the GitHub authorization and legal basis that applies to your workflow. Follow applicable privacy, employment, communications, anti-spam, security, and data-retention requirements.
Do not assume a public commit email is consent for unsolicited messaging. Maintain appropriate suppression, removal, and do-not-contact handling for downstream systems.
Support
If a run fails or the output looks wrong, open an issue or report a bug from the Actor page.
Please include:
- Apify run ID or run URL
- Input JSON with secret tokens removed
- Expected output
- Actual output
- One reproducible public repository URL
This lets support distinguish GitHub availability, rate limits, branch/date filters, schema changes, and Actor behavior without exposing credentials.
For one reproducible public URL, use https://github.com/apify/crawlee and compare against the Crawlee contributor-email example.