GitHub Repository Scraper: Stars, Releases & Contributors
Pricing
from $1.50 / 1,000 repository scrapeds
GitHub Repository Scraper: Stars, Releases & Contributors
Scrape public GitHub repositories: stars, forks, issues, licence, topics, languages, latest releases and top contributors. Works unauthenticated; supply a token to raise limits.
Pricing
from $1.50 / 1,000 repository scrapeds
Rating
0.0
(0)
Developer
Arman Hossain
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
5 hours ago
Last modified
Categories
Share

GitHub Repository Scraper turns a list of public GitHub repositories into structured rows, stars, forks, watchers, open issues, licence, topics, the full language breakdown, recent releases and the top contributors by commit count.
It reads the public GitHub REST API directly: no browser, no proxies, no scraping of HTML, no login required. A personal access token is optional and does one thing, raises the request budget from 60/hour to 5000/hour.
What you get
| Output field | Meaning |
|---|---|
requestedAs, fullName | What you passed in, and the canonical owner/repo GitHub resolved it to |
owner, url, homepage | Owner login, repo URL, and the project's own site if it declares one |
description | Repo tagline |
stars, forks, watchers, openIssues | Current counts, see the note on watchers below |
license | SPDX identifier where GitHub has one (MIT, Apache-2.0), otherwise the licence name |
topics | The repo's topic tags |
primaryLanguage, languages | Dominant language, and the full { language: bytes } map when includeLanguages is on |
defaultBranch, isArchived, isFork, sizeKb | Branch name, archive/fork status, checkout size in KB |
createdAt, pushedAt | Creation time and the last push, pushedAt is the real activity signal |
latestRelease, releases | Newest stable release, plus the last 10, when includeReleases is on |
contributors | Top 10 by commit count, when includeContributors is on |
scrapedAt | Run timestamp |
A RUN_SUMMARY record in the key-value store holds per-run counts, remaining rate-limit budget, which repos failed and which were skipped.
On watchers. GitHub's API has a long-standing quirk: watchers_count is a legacy alias that returns the star count, while the number of people actually watching the repo lives in subscribers_count. This Actor maps watchers to the real subscriber count, so stars and watchers are different numbers here, unlike in a raw API response.
On requestedAs vs fullName. GitHub answers renamed and transferred repos with a 301 to the new location. The Actor follows it, so asking for facebook/react today saves a row with fullName: "react/react". Both are kept so you can join back to your input list.
Common use cases
Track OSS competitor traction. Sweep a watchlist on a schedule and diff stars and pushedAt week over week.
{"repositories": ["vercel/next.js", "remix-run/react-router", "nuxt/nuxt", "sveltejs/kit"],"includeReleases": true,"includeContributors": false,"includeLanguages": false,"githubToken": "ghp_your_token_here"}
Build a repo-ranking leaderboard. Metrics only, three requests saved per repo, so a long list fits inside the unauthenticated budget.
{"repositories": ["torvalds/linux", "facebook/react", "tensorflow/tensorflow", "kubernetes/kubernetes"],"includeReleases": false,"includeContributors": false,"includeLanguages": false}
Due diligence on an open-source dependency. Everything on, for a handful of repos, licence, bus factor, release cadence and whether it is still maintained.
{"repositories": ["expressjs/express", "lodash/lodash"],"includeReleases": true,"includeContributors": true,"includeLanguages": true}
Input
| Field | Type | Default | Notes |
|---|---|---|---|
repositories | array | - | Required. owner/repo, a github.com URL, or a git clone string. Mixed input is fine. |
includeReleases | boolean | true | Last 10 releases + newest stable as latestRelease. +1 request per repo. |
includeContributors | boolean | true | Top 10 contributors by commit count. +1 request per repo. |
includeLanguages | boolean | true | Full { language: bytes } map. +1 request per repo. |
githubToken | string | "" | Optional PAT. Raises 60 → 5000 requests/hour. Stored as a secret. |
Which combinations make sense. The three booleans are the whole cost model. With all of them off, a repo costs 1 request; with all on it costs 4. Unauthenticated that is the difference between roughly 60 repos an hour and roughly 15. Topics, stars, forks, licence, language name, dates and archive status all ride along on the base request and are always present. You never need to turn an extra on to get those. Turn extras on for depth on a short list; turn them off for breadth on a long one.
Output example
{"requestedAs": "facebook/react","fullName": "react/react","owner": "react","description": "The library for web and native user interfaces.","url": "https://github.com/react/react","homepage": "https://react.dev","stars": 247059,"forks": 51190,"watchers": 6600,"openIssues": 1248,"license": "MIT","topics": ["declarative", "frontend", "javascript", "library", "react", "ui"],"primaryLanguage": "JavaScript","languages": {"JavaScript": 5659949,"Rust": 2965252,"TypeScript": 2567778,"HTML": 116629,"CSS": 95930},"defaultBranch": "main","isArchived": false,"isFork": false,"sizeKb": 1045734,"createdAt": "2013-05-24T16:15:54Z","pushedAt": "2026-08-05T19:11:16Z","latestRelease": {"tagName": "v19.2.8","name": "19.2.8 (July 21st, 2026)","publishedAt": "2026-07-21T15:49:09Z","isPrerelease": false,"isDraft": false,"url": "https://github.com/react/react/releases/tag/v19.2.8","notes": "## React Server Components\n\n- Performance improvements when decoding …"},"releases": ["… the last 10, same shape as latestRelease …"],"contributors": [{ "login": "sebmarkbage", "contributions": 1939, "type": "User", "url": "https://github.com/sebmarkbage" },{ "login": "zpao", "contributions": 1778, "type": "User", "url": "https://github.com/zpao" },{ "login": "gaearon", "contributions": 1687, "type": "User", "url": "https://github.com/gaearon" }],"scrapedAt": "2026-08-06T12:00:00.000Z"}
RUN_SUMMARY in the key-value store:
{"reposRequested": 4,"reposSaved": 4,"reposFailed": 0,"reposSkipped": 0,"failures": [],"skipped": [],"requestsUsed": 16,"requestsPerRepo": 4,"rateLimited": false,"rateLimit": {"limit": 60,"remaining": 44,"resetsAt": "2026-08-06T13:12:11.000Z","authenticated": false},"filters": { "includeReleases": true, "includeContributors": true, "includeLanguages": true },"finishedAt": "2026-08-06T12:00:07.221Z"}
Limits and behaviour
- 60 requests per hour, per IP, unauthenticated. This is the constraint that decides what this Actor can do for you. With all extras on, one repo costs four requests, so an unauthenticated run tops out around 15 repos per hour. With all extras off it is about 60. A token raises the ceiling to 5000 requests/hour, roughly 1,250 repos an hour with everything on. If you plan to scrape more than a handful of repos, supply a token.
- The budget is read from every response. rate-limit headers and rate-limit headers are logged after every repo and written into
RUN_SUMMARY.rateLimit. - Exhaustion stops the run cleanly, before a partial row. The Actor checks the remaining budget before starting each repo and stops if it cannot afford to finish that repo, so you never get a row with the extras silently missing. Remaining repos are listed in
RUN_SUMMARY.skipped,rateLimitedis set totrue, and the reset time is logged. It does not hammer into a wall of 403s. - One bad repo never aborts the run. A typo or a private repo returns 404, lands in
RUN_SUMMARY.failures, and the run moves on. The Actor only throws if every repo failed, or if the budget was already gone before a single repo could be read. - Transient errors are retried. 429 and 5xx get three attempts with linear backoff. 404, 401 and 403-with-budget-remaining are fatal for that repo and are not retried.
- Empty repos are handled. A repo with no commits answers 204/409 on
/contributorsand/languages; those come back as empty rather than as an error. - Duplicates are removed before any request is made, so passing the same repo twice costs you nothing.
- Public data only. No authentication is required, no private repos are reachable, no access control is bypassed. Contributor logins are public profile data.
API example
curl -X POST "https://api.apify.com/v2/acts/arman-bd~github-repo-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"repositories": ["facebook/react", "vercel/next.js"],"includeReleases": true,"includeContributors": false,"includeLanguages": false}'
JavaScript example
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_TOKEN' });const run = await client.actor('arman-bd/github-repo-scraper').call({repositories: ['facebook/react', 'vercel/next.js', 'sveltejs/kit'],includeReleases: true,includeContributors: false,includeLanguages: false,});const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const r of items) {console.log(`${r.fullName}: ${r.stars} stars, latest ${r.latestRelease?.tagName ?? 'no releases'}`);}
FAQ
Do I need a proxy? No. Proxy configuration is not required to run this Actor.
Do I need a GitHub account? Not to run it. You need one only to create a token, which you want for anything beyond a dozen or so repos.
What scopes does the token need? None. A classic PAT with zero scopes ticked, or a fine-grained token with read access to public repositories, is enough, the token exists purely to identify you for rate-limiting.
Can it read private repos? Only if you supply a token that has access to them. With no token, or a public-only token, private repos return 404 and are reported as failures.
Why is stars different from watchers? Because they should be. GitHub's raw watchers_count field returns the star count for historical reasons; this Actor reports the real subscriber count instead.
Why did fullName come back different from what I typed? The repo was renamed or transferred and GitHub 301'd to its new home. requestedAs keeps your original string so you can join the two.
What happens if GitHub is unavailable? 5xx responses are retried three times, then that repo is recorded in RUN_SUMMARY.failures and the run continues.
Can I schedule it? Yes, it is built for it. Run a watchlist daily and diff on stars, forks and pushedAt.
Can I integrate it with something else? Yes, Apify API, client libraries, webhooks, scheduled runs, dataset exports (JSON/CSV/Excel) or MCP. Output is structured JSON.