# GitHub Users Scraper (`w3crawler/github-users-scraper`) Actor

Search public GitHub users and optionally enrich each result with its public profile fields.

- **URL**: https://apify.com/w3crawler/github-users-scraper.md
- **Developed by:** [w3crawler](https://apify.com/w3crawler) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.99 / 1,000 users

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does GitHub Users Scraper do?

**GitHub Users Scraper** searches the [public GitHub user directory](https://github.com/search?q=octocat\&type=users) and returns one source-backed row per matching account. It can enrich each result with fields from GitHub’s [public user API](https://docs.github.com/en/rest/users/users#get-a-user), while preserving search position, query, source URLs, stable identity, and timestamps. It does not access private profiles, private repositories, or authenticated account areas.

### Why use GitHub Users Scraper?

Use it for public developer research, open-source community mapping, recruiting research, public profile analytics, or scheduled change monitoring you are authorized to perform. GitHub search qualifiers can narrow a run by login, location, language, follower range, and other public expressions. Search results are deduplicated before the global limit, and optional profile enrichment retains public fields without inventing missing values. Apify adds run history, API access, scheduling, monitoring, and integrations. **No proxy rotation or access bypass is used.** A local fixture option exists only for deterministic development tests.

### What data can GitHub Users Scraper extract?

| Field                                                            | Type                       | Description                                                                    |
| ---------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------ |
| `recordType`, `recordId`                                         | string                     | `user` discriminator and stable case-insensitive login identity.               |
| `login`, `userId`, `type`                                        | string, integer            | Public account identity and GitHub account type, including bots when returned. |
| `name`, `bio`, `company`, `location`, `blog`                     | string                     | Public profile text when exposed.                                              |
| `followers`, `following`, `publicRepos`, `publicGists`           | integer                    | Public activity counts from the profile endpoint.                              |
| `profileUrl`, `apiUrl`, `searchUrl`, `sourceUrl`                 | URL                        | Public profile, search, and API provenance.                                    |
| `searchQuery`, `searchPosition`, `searchScore`                   | string, integer, number    | Search context and original one-based ranking.                                 |
| `dataAvailable`, `accessStatus`, `extractionMethod`, `scrapedAt` | boolean, string, date-time | Contract, access, transport, and timing metadata.                              |
| Diagnostic fields                                                | mixed                      | `url`, bounded `error`, and `errorCode` for unavailable public sources.        |

### How to scrape GitHub users

1. Open the Actor in Apify Console and enter a public GitHub search expression in the Input tab.
2. Set the maximum number of distinct users and choose whether to fetch public profile enrichment.
3. Start the run, inspect the dataset and `OUTPUT_SUMMARY`, then connect or download the results through the API, an integration, or a schedule.

### How much will it cost to scrape GitHub users?

Apify billing depends on the selected Actor pricing and compute used by each run; there is no fixed price promise here. Each run makes one public search request and, when enrichment is enabled, up to one profile request per selected result. More users, retries, long timeouts, and pacing increase runtime or request volume. Use a small `maxItems` for smoke tests and respect GitHub’s unauthenticated limits.

### Input

See the input tab for the complete configuration. `query` defaults to `octocat`, is trimmed, and must be 1–256 characters. `maxItems` is a global distinct-user limit from 1–100 (default 20). `includeProfiles` defaults to `true`; when false, rows retain search fields only. `requestDelayMs` is 0–2000 milliseconds (default 100) between profile requests, `maxRetries` is 1–5 attempts (default 3) for each public API request, and the optional `fixtureFile` is a repository-relative JSON path for local tests. Unknown keys, null numeric controls, empty queries, absolute fixture paths, and parent-directory traversal are rejected.

#### Minimal/default run

```json
{}
```

#### Search qualifiers with profile enrichment

```json
{
    "query": "location:Berlin followers:>100",
    "maxItems": 25,
    "includeProfiles": true,
    "requestDelayMs": 100,
    "maxRetries": 3
}
```

#### Fast discovery run

```json
{
    "query": "octocat",
    "maxItems": 10,
    "includeProfiles": false,
    "requestDelayMs": 0,
    "maxRetries": 1
}
```

### Output

Normal user rows use `recordType: "user"` and `dataAvailable: true`. The search response order is preserved through `searchPosition`; deduplication uses a case-insensitive login, then public ID or API URL fallback. If profile enrichment fails, the search-backed row is retained and the summary increments `profileRequestsFailed`. If no usable row can be produced, a diagnostic row uses `recordType: "diagnostic"`, `dataAvailable: false`, `accessStatus: "unavailable"`, and a stable diagnostic ID.

#### Normal user row

```json
{
    "recordType": "user",
    "recordId": "github-users:user:octocat",
    "dataAvailable": true,
    "accessStatus": "public",
    "extractionMethod": "github_rest_api",
    "login": "octocat",
    "userId": 583231,
    "profileUrl": "https://github.com/octocat",
    "searchQuery": "octocat",
    "searchPosition": 1,
    "searchUrl": "https://api.github.com/search/users?q=octocat&per_page=5",
    "sourceUrl": "https://api.github.com/users/octocat",
    "scrapedAt": "2026-09-08T00:00:00.000Z"
}
```

#### Diagnostic row and summary

```json
{
    "recordType": "diagnostic",
    "recordId": "github-users:diagnostic:no_results:https%3A%2F%2Fapi.github.com%2Fsearch%2Fusers%3Fq%3Doctocat%26per_page%3D20",
    "dataAvailable": false,
    "accessStatus": "unavailable",
    "extractionMethod": "github_rest_api",
    "url": "https://api.github.com/search/users?q=octocat&per_page=20",
    "error": "The public GitHub user search returned no usable user records.",
    "errorCode": "NO_RESULTS",
    "scrapedAt": "2026-09-08T00:00:00.000Z"
}
```

`OUTPUT_SUMMARY` contains status, query, search and deduplication counts, profile-request counts, normal/diagnostic counts, requested limit, completion time, and the public search URL. You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

### Tips and advanced options

Use search qualifiers to reduce the candidate set before increasing `maxItems`. Disable enrichment for a fast discovery pass, then rerun a narrower query with it enabled. `maxItems` is global after deduplication, while `searchPosition` always records the original response position. GitHub’s search endpoint is paginated by its API response, but this Actor requests only the bounded page sized to `maxItems`; it is not an unbounded crawler. Increase pacing or wait for the reset window when rate-limited. Never put credentials in a fixture or README; the Actor has no credential input.

### FAQ, support, and responsible use

If a run has diagnostics, inspect `OUTPUT_SUMMARY`, `errorCode`, and `url`. Search results and public fields can change between runs, and GitHub may return rate limits or unavailable profiles. Report reproducible issues in the Actor’s Issues tab with the run ID, input, summary, and affected public URL. Use only data account owners made public, follow GitHub’s terms and rate limits, respect privacy and applicable law, and obtain legal advice for personal-data processing. This Actor is not affiliated with or endorsed by GitHub.

#### Local verification

```bash
npm ci
npm test
npm run check
apify validate-schema
apify run --purge --input-file test/inputs/live-smoke.json
npm run validate
```

# Actor input Schema

## `query` (type: `string`):

Public GitHub user search expression, such as octocat, location:Berlin, or followers:>1000.

## `maxItems` (type: `integer`):

Maximum distinct public users returned after preserving the source search order.

## `includeProfiles` (type: `boolean`):

Fetch public profile fields such as name, location, followers, repositories, and bio.

## `requestDelayMs` (type: `integer`):

Polite delay between public profile requests.

## `maxRetries` (type: `integer`):

Attempts for each public GitHub API request.

## `fixtureFile` (type: `string`):

Optional local JSON fixture with search and profile payloads; leave blank for GitHub API requests.

## Actor input object example

```json
{
  "query": "octocat",
  "maxItems": 20,
  "includeProfiles": true,
  "requestDelayMs": 100,
  "maxRetries": 3,
  "fixtureFile": ""
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("w3crawler/github-users-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("w3crawler/github-users-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call w3crawler/github-users-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,w3crawler/github-users-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/m2acmb1MO2df8BonO/builds/nILLaBwvM5IgcS2Yc/openapi.json
