# GitHub Repository Stats Scraper (`sfoln/github-repo-stats`)

GitHub repository stats as clean JSON: stars, forks, watchers, open issues and pull requests, licence, topics, language breakdown, latest release, contributors count and 52 weeks of commit activity, for repositories or every public repo of a user or organization. $1 per 1,000 repos.

- Family: Data utilities
- Categories: Developer tools, AI, Automation
- Availability: on request (private on Apify). Email contact@sfoln.com with subject "Access request: GitHub Repository Stats Scraper (sfoln/github-repo-stats)" before calling; calls fail until it is public.
- JSON: https://www.sfoln.com/actors/github-repo-stats.json
- MCP: https://mcp.apify.com?tools=sfoln/github-repo-stats
- REST (sync): POST https://api.apify.com/v2/actors/sfoln~github-repo-stats/run-sync-get-dataset-items
- REST (async): POST https://api.apify.com/v2/actors/sfoln~github-repo-stats/runs

GitHub Repository Stats Scraper turns GitHub repositories into one clean JSON record each: stars, forks, watchers, open issues and open pull requests (counted separately), licence, topics, default branch, language breakdown, created / updated / last-push dates, the latest release, the number of contributors and 52 weeks of commit activity. Give it repositories (owner/name or URLs) or users and organizations (their public repositories, best first). Built for developer-tool market research, open-source due diligence, dependency health checks and AI agents; $0.001 per repository.

## Price per delivered record

| Event | Price | Per 1,000 | Charged for |
| --- | --- | --- | --- |
| GitHub repository (`repo`) | $0.001 | $1 / 1,000 | Charged once per repository record delivered: a repository you listed, or each repository listed for a user or organization. |

Pay-per-event, USD, billed by Apify; no platform usage charge. Only records with status `ok` are charged. Cap a run with `maxTotalChargeUsd`. Apify free plan: up to 10 per run.

## Run

```bash
curl -X POST "https://api.apify.com/v2/actors/sfoln~github-repo-stats/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"repositories":["apify/crawlee"]}'
```

MCP client configuration:

```json
{
  "mcpServers": {
    "apify": {
      "type": "http",
      "url": "https://mcp.apify.com?tools=sfoln/github-repo-stats"
    }
  }
}
```

Example prompt: Compare the GitHub repositories apify/crawlee and microsoft/playwright: stars, forks, open issues and pull requests, latest release and commits in the last 12 weeks.

## Input

List repositories, or users and organizations whose public repositories you want. Each repository becomes one dataset record with a status field; each account also gets one free summary record.

| Field | Type | Default | Meaning |
| --- | --- | --- | --- |
| `repositories` | array | — | Repositories: Repositories as owner/name or GitHub URLs (https://github.com/owner/name, .git and /tree/… URLs work too). Accounts on the Apify free plan can process up to 10 inputs per run. |
| `owners` | array | — | Users or organizations: GitHub users or organizations (login or profile URL): their public repositories are listed (see Max repositories per account) and each one becomes a charged record. |
| `maxReposPerOwner` | integer | `20` | Max repositories per account: Repositories returned (and charged) per user or organization, best first. Accounts on the Apify free plan get up to 20 per account. |
| `ownerReposSort` | string | `"stars"` | Account repositories order: Which repositories of an account come first: most stars, most forks, or most recently updated. One of `"stars"`, `"forks"`, `"updated"`. |
| `includeForks` | boolean | `false` | Include forks: Account listings: also list repositories that are forks. |
| `includeArchived` | boolean | `false` | Include archived repositories: Account listings: also list archived (read-only) repositories. |
| `includeLanguages` | boolean | `true` | Languages breakdown: Bytes and percent per language (1 request per repository). |
| `includeLatestRelease` | boolean | `true` | Latest release: Tag, name and date of the latest published release (1 request per repository). |
| `includeContributors` | boolean | `true` | Contributors count: Contributors including anonymous commit authors (1 request per repository; GitHub does not count them for the very largest repositories). |
| `includePullRequests` | boolean | `true` | Open pull requests: Open pull requests, which also splits GitHub's open issue count into issues and pull requests (1 request per repository). |
| `includeCommitActivity` | boolean | `true` | Commit activity (52 weeks): Commits per week over the last 52 weeks, plus 4-, 12- and 52-week totals (1 request per repository, best effort: GitHub computes them on demand). |
| `githubToken` | string | — | GitHub token (optional): Your own GitHub personal access token (no scopes needed for public data) for your own quota of 5,000 requests per hour. Without it the Actor uses its shared token, or GitHub's 60 requests per hour when none is configured. Only ever sent to api.github.com. |
| `maxItems` | integer | `500` | Max inputs: Safety cap on repositories plus accounts processed in this run; further inputs are ignored and counted in the OUTPUT record. |
| `concurrency` | integer | `4` | Concurrency: Inputs processed in parallel. |
| `itemTimeoutSecs` | integer | `600` | Timeout per input (seconds): An input still running after this long is stopped (repositories of an account already delivered are kept). |
| `includeRaw` | boolean | `false` | Include raw GitHub data: Attach GitHub's repository, languages and release objects to each record (larger output). |

Example input:

```json
{
  "repositories": [
    "apify/crawlee"
  ]
}
```

## Output

One record per input item with `status` (`ok` is charged; `not_found`, `error`, `skipped_*` are free) and `charged`. The run stores an `OUTPUT` summary record.

| Field | Type | Meaning |
| --- | --- | --- |
| `input` | string | object | Input: The input item this record corresponds to. |
| `status` | string | Status: ok \| not_found \| error \| skipped_invalid \| skipped_budget \| skipped_free_plan \| skipped_unmetered |
| `charged` | boolean | Charged: Whether this record incurred a pay-per-event charge. |
| `chargedEvent` | string | Charged event: Pay-per-event event charged for this record (present only when charged). |
| `chargedCount` | integer | Events charged: Events actually charged when the charge came back short of the requested count (present only then; a warning explains it). |
| `source` | string | Source: Upstream data source (github = GitHub REST API). |
| `fetchedAt` | string | Fetched at: ISO timestamp. |
| `error` | object | Error: { code, message, provider?, status? } when status is not ok: not_found (no such public repository or account), rate_limit (GitHub quota spent; the message has the reset time), invalid_input, http_error, timeout, network. Runtime codes: budget_exhausted, free_plan_limit, unmetered, aborted, charge_failed, record_too_large, invalid_record, dataset_push_failed. |
| `warnings` | array | Warnings: Notes, e.g. a section GitHub could not answer (its fields are null) or commit statistics still being computed. |
| `recordType` | string | Row type: repo (one per repository, charged) \| summary (one per account input, free) |
| `position` | integer | Position: Repositories of an account: rank in the chosen order. |
| `found` | boolean | Found: false when the repository or account does not exist (or is not public). |
| `repoId` | integer | null | Repository id: GitHub repository id. |
| `fullName` | string | null | Repository: owner/name (canonical, after renames). |
| `owner` | string | null | Owner: Owner login (repositories and account summaries). |
| `ownerType` | string | null | Owner type: User or Organization. |
| `name` | string | null | Name: Repository name. |
| `url` | string | null | URL: github.com page of the repository. |
| `description` | string | null | Description: Repository description. |
| `homepage` | string | null | Homepage: Website set on the repository. |
| `topics` | array | Topics: Repository topics. |
| `stars` | integer | null | Stars: Stargazers. |
| `forks` | integer | null | Forks: Forks. |
| `watchers` | integer | null | Watchers: Accounts watching the repository (subscribers). |
| `openIssues` | integer | null | Open issues: Open issues without pull requests (null when pull requests were not counted). |
| `openPullRequests` | integer | null | Open pull requests: Open pull requests. |
| `openIssuesAndPullRequests` | integer | null | Open issues + PRs: GitHub's open_issues_count (issues and pull requests). |
| `license` | string | null | Licence: SPDX id (NOASSERTION when GitHub cannot classify it); null when there is none. |
| `licenseName` | string | null | Licence name: Licence name. |
| `defaultBranch` | string | null | Default branch: Default branch. |
| `primaryLanguage` | string | null | Primary language: GitHub's main language. |
| `languages` | array | null | Languages: [{ language, bytes, percent }], largest first. |
| `createdAt` | string | null | Created: ISO timestamp. |
| `updatedAt` | string | null | Updated: ISO timestamp (any change, incl. stars). |
| `pushedAt` | string | null | Last push: ISO timestamp of the last push. |
| `daysSinceLastPush` | integer | null | Days since last push: Whole days between the last push and the fetch. |
| `latestReleaseTag` | string | null | Latest release: Tag of the latest published release (not a draft or prerelease). |
| `latestReleaseName` | string | null | Release name: Name of the latest release. |
| `latestReleaseAt` | string | null | Released at: ISO publish time of the latest release. |
| `latestReleaseUrl` | string | null | Release URL: github.com page of the latest release. |
| `contributorsCount` | integer | null | Contributors: Contributors including anonymous commit authors (null for repositories GitHub will not count). |
| `commitActivityStatus` | string | Commit activity: ok \| pending (GitHub still computing; run again) \| empty (no commits) \| skipped \| unavailable |
| `commitsLast52Weeks` | integer | null | Commits (52 weeks): Commits in the last 52 weeks (default branch). |
| `commitsLast12Weeks` | integer | null | Commits (12 weeks): Commits in the last 12 weeks. |
| `commitsLast4Weeks` | integer | null | Commits (4 weeks): Commits in the last 4 weeks. |
| `weeklyCommits` | array | null | Weekly commits: [{ weekStart (YYYY-MM-DD, Sunday), commits }], oldest first, 52 weeks. |
| `isArchived` | boolean | null | Archived: Read-only archived repository. |
| `isFork` | boolean | null | Fork: The repository is a fork. |
| `forkedFrom` | string | null | Forked from: Parent repository of a fork. |
| `isTemplate` | boolean | null | Template: Template repository. |
| `isDisabled` | boolean | null | Disabled: Disabled by GitHub. |
| `visibility` | string | null | Visibility: public. |
| `sizeKb` | integer | null | Size (KB): Repository size in KB. |
| `hasIssues` | boolean | null | Issues enabled: Issues enabled. |
| `hasWiki` | boolean | null | Wiki enabled: Wiki enabled. |
| `hasPages` | boolean | null | Pages enabled: Pages enabled. |
| `hasDiscussions` | boolean | null | Discussions enabled: Discussions enabled. |
| `ownerName` | string | null | Account name: Summary records: display name of the account. |
| `ownerUrl` | string | null | Account URL: Summary records. |
| `publicRepos` | integer | null | Public repositories: Summary records: public repositories of the account. |
| `followers` | integer | null | Followers: Summary records. |
| `blog` | string | null | Website: Summary records: website of the account. |
| `location` | string | null | Location: Summary records. |
| `twitterUsername` | string | null | X handle: Summary records. |
| `reposFound` | integer | null | Repositories found: Summary records: repositories matching the account listing (forks and archived as configured). |
| `resultsDelivered` | integer | Repositories delivered: Summary records: repository records delivered (and charged) for the account. |
| `stopReason` | string | Stop reason: Summary records: limit \| free_plan \| end \| budget \| aborted \| deadline. |
| `rateLimited` | boolean | Stopped by rate limit: Summary records: the GitHub quota ran out before every repository was fetched. |
| `raw` | object | Raw: GitHub's repository, languages and release objects (includeRaw). |

Example record:

```json
{
  "input": {
    "repository": "octo-org/rocket"
  },
  "recordType": "repo",
  "repoId": 812345678,
  "fullName": "octo-org/rocket",
  "owner": "octo-org",
  "ownerType": "Organization",
  "name": "rocket",
  "url": "https://github.com/octo-org/rocket",
  "description": "A fast, typed web crawling and scraping toolkit.",
  "homepage": "https://rocket.example.dev",
  "topics": [
    "crawler",
    "scraping",
    "typescript",
    "web-scraping"
  ],
  "stars": 18234,
  "forks": 1003,
  "watchers": 121,
  "openIssues": 117,
  "openPullRequests": 40,
  "openIssuesAndPullRequests": 157,
  "license": "Apache-2.0",
  "licenseName": "Apache License 2.0",
  "defaultBranch": "master",
  "primaryLanguage": "TypeScript",
  "languages": [
    {
      "language": "TypeScript",
      "bytes": 6123456,
      "percent": 92.24
    },
    {
      "language": "JavaScript",
      "bytes": 512345,
      "percent": 7.72
    }
  ],
  "createdAt": "2019-03-04T10:12:31.000Z",
  "updatedAt": "2026-10-14T08:01:22.000Z",
  "pushedAt": "2026-10-13T17:44:09.000Z",
  "daysSinceLastPush": 1,
  "latestReleaseTag": "v3.15.1",
  "latestReleaseName": "v3.15.1",
  "latestReleaseAt": "2026-10-01T12:30:05.000Z",
  "latestReleaseUrl": "https://github.com/octo-org/rocket/releases/tag/v3.15.1",
  "contributorsCount": 315,
  "commitActivityStatus": "ok",
  "commitsLast52Weeks": 1092,
  "commitsLast12Weeks": 252,
  "commitsLast4Weeks": 84,
  "weeklyCommits": [
    {
      "weekStart": "2025-10-19",
      "commits": 21
    },
    {
      "weekStart": "2025-10-26",
      "commits": 21
    }
  ],
  "isArchived": false,
  "isFork": false,
  "forkedFrom": null,
  "isTemplate": false,
  "isDisabled": false,
  "visibility": "public",
  "sizeKb": 48213,
  "hasIssues": true,
  "hasWiki": false,
  "hasPages": true,
  "hasDiscussions": true,
  "status": "ok",
  "charged": true,
  "chargedEvent": "repo",
  "source": "github",
  "fetchedAt": "2026-10-14T22:00:00.000Z"
}
```

## FAQ

**Do I need a GitHub token?**

No. The Actor uses its own token when one is configured (5,000 requests per hour, shared by all runs); without any token GitHub allows only 60 requests per hour, about 10 repositories. For large or frequent runs, add your own personal access token (no scopes needed) in githubToken: it is stored as a secret input and only sent to api.github.com.

**What happens when the GitHub rate limit is reached?**

The Actor reserves the requests a repository needs before it starts it, so it stops between repositories: the remaining inputs get an unbilled error record with code rate_limit and the time the limit resets. Repositories already delivered are kept.

**Why is commit activity sometimes missing?**

GitHub computes commit statistics on demand. When they are not ready, the Actor polls twice, then delivers the record with commitActivityStatus pending and empty commit counts; running it again a minute later returns them.


## Related

- [DefiLlama Scraper – DeFi TVL, Fees & Yields](https://www.sfoln.com/actors/defillama-scraper.md) (`sfoln/defillama-scraper`)
- [URL Metadata & Open Graph Extractor](https://www.sfoln.com/actors/url-metadata.md) (`sfoln/url-metadata`)
- [Domain WHOIS & DNS Lookup](https://www.sfoln.com/actors/domain-intelligence.md) (`sfoln/domain-intelligence`)

Publisher: SFOLN LLC, contact@sfoln.com. Catalogue: https://www.sfoln.com/catalog.json. Agent guide: https://www.sfoln.com/agents.md.
