# 🔥Github Profile Scraper (`aimscrape/github-profile-scraper`) Actor

Extract public GitHub user, organization, and bot profiles from usernames or URLs. Collect account types, bios, avatars, repository counts, followers, timestamps, and organization verification in structured results.

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

## Pricing

from $0.75 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Profile Scraper do?

**GitHub Profile Scraper** collects public profile metadata for GitHub users,
organizations, and bots from usernames or profile URLs. It returns account
identity, profile type, biography, avatar, public repository and gist counts,
followers, timestamps, and organization verification in a structured Dataset
you can download or access through the Apify API.

The Actor collects publicly available GitHub profile information without
requiring sign-in or accessing private data.

### How to scrape GitHub profiles

1. Open the **Input** tab and add GitHub usernames or profile URLs.
2. Start the Actor. Use a few targets for the first run to inspect the available
   public fields.
3. Follow progress in the run log, then open **Profiles** in the **Output** tab.
4. Download the Dataset as JSON, CSV, Excel, or another format supported by
   Apify, or retrieve it through the API.

Use Apify schedules for recurring collection. Each run captures the public
values returned by GitHub at collection time, so separate runs can be compared
to monitor profile changes.

### Why use GitHub Profile Scraper?

- **Developer and organization research:** collect consistent identity,
  biography, location, website, and account-type data.
- **Public profile directories:** normalize usernames and profile URLs into one
  stable record format.
- **Account monitoring:** track public repository, gist, follower, and following
  counts over time.
- **Organization verification:** identify organization profiles and collect
  GitHub's public verification and archive state when available.
- **Automation:** run through Apify Console, schedules, API calls, integrations,
  and monitoring without maintaining custom scraping infrastructure.

### Input

```json
{
  "usernames": [
    "octocat",
    "https://github.com/github"
  ],
  "skipInvalidInputs": true
}
```

`usernames` is required and accepts between 1 and 100,000 entries. You can mix
these formats in one run:

| Format | Example |
| --- | --- |
| Username | `octocat` |
| Username with an `@` prefix | `@octocat` |
| HTTPS profile URL | `https://github.com/octocat` |

The input form first checks only that each entry has the basic shape of a bare
username, an `@username`, or a supported profile URL. This broad check permits
letters, digits, periods, underscores, and hyphens without imposing a username
length or first/last character rule, so one malformed entry does not prevent
valid entries in the same list from running. Before queueing, the Actor applies
GitHub's exact rule: 1–39 characters, with an alphanumeric first and last
character. Profile URLs must use `github.com` or `www.github.com` and contain
one profile path segment.

By default, `skipInvalidInputs` is `true`, so values rejected by the strict
runtime check are omitted from the Dataset without making a network request.
Set it to `false` to store one `invalid_input` row per distinct invalid entry;
valid entries continue normally. Recognizable credentials in invalid strings
are redacted before output. Repository URLs, query parameters, fragments,
embedded credentials, and non-GitHub hosts remain invalid.

Inputs are normalized to lowercase and equivalent targets are collected once
per run. For example, `GitHub`, `@github`, and
`https://github.com/GitHub/` identify the same requested profile.

### What data can GitHub Profile Scraper extract?

All output properties use lower camelCase.

| Field | Type | Meaning |
| --- | --- | --- |
| `status` | string | `ok`, `not_found`, or `invalid_input`. |
| `id` | string or null | GitHub numeric account ID serialized as text. |
| `username` | string | Normalized requested username used for queue and recovery identity; for `invalid_input`, the redacted submitted string. |
| `canonicalUsername` | string or null | Canonical login returned by GitHub. |
| `profileType` | string or null | GitHub account type, such as `User`, `Organization`, or `Bot`. |
| `isVerified` | boolean or null | GitHub organization verification when available. |
| `archivedAt` | string or null | Organization archive timestamp when available. |
| `url`, `apiUrl` | string / string or null | Public profile URL and final public API URL. |
| `avatarUrl`, `name`, `bio` | string or null | Public avatar, display name, and biography or organization description. |
| `company`, `blog`, `location`, `email` | string or null | Public profile values returned by GitHub. Location is not inferred. |
| `hireable`, `siteAdmin` | boolean or null | Public account flags when returned. |
| `twitterUsername` | string or null | Public Twitter/X username when returned. |
| `publicRepoCount`, `publicGistCount` | integer or null | Public repository and gist counts. |
| `followerCount`, `followingCount` | integer or null | Public follower and following counts. |
| `createdAt`, `updatedAt` | string or null | GitHub account timestamps. |
| `crawledAt` | string | UTC collection timestamp in ISO 8601 format. |

Every row contains the complete field set. Missing optional values are explicit
`null`; real zero counts and `false` flags remain unchanged.

An `invalid_input` row contains the redacted submitted value in `username`, its
collection time in `crawledAt`, and explicit `null` for profile metadata,
including `url`.

### Output example

The following is **synthetic example data**, not a captured live account:

```json
{
  "status": "ok",
  "id": "9919",
  "username": "example-org",
  "canonicalUsername": "example-org",
  "profileType": "Organization",
  "isVerified": true,
  "archivedAt": null,
  "url": "https://github.com/example-org",
  "apiUrl": "https://api.github.com/orgs/example-org",
  "avatarUrl": "https://avatars.githubusercontent.com/u/9919?v=4",
  "name": "Example Organization",
  "company": "Example, Inc.",
  "blog": "https://example.com",
  "location": "Singapore",
  "email": null,
  "hireable": null,
  "bio": "Building useful open-source software.",
  "twitterUsername": "example",
  "siteAdmin": false,
  "publicRepoCount": 42,
  "publicGistCount": 0,
  "followerCount": 12500,
  "followingCount": 0,
  "createdAt": "2011-01-25T18:44:36Z",
  "updatedAt": "2026-10-20T08:00:00Z",
  "crawledAt": "2026-10-29T09:00:00Z"
}
```

### How profile results are classified

The Actor validates each target and records a profile only when GitHub returns a
matching public account:

- `ok` means the public profile was collected successfully.
- `not_found` means GitHub did not expose a matching public user or organization
  during the run. It does not prove that the username is available to register.
- `invalid_input` means the submitted value was not a supported username or
  profile URL. These rows are stored only when `skipInvalidInputs` is `false`.
- Temporary access, network, and response errors are retried and are never
  recorded as `not_found`.
- If optional organization information is unavailable, the Actor keeps the
  valid base profile and returns `null` for the unavailable fields.

### How much does it cost to scrape GitHub profiles?

Check the Actor's **Pricing** tab for current rates and review the run's charge
limit before starting. On pay-per-event runs, each stored Dataset row is a
result, including `not_found` and any `invalid_input` rows not omitted with
`skipInvalidInputs`.

If the result or charge budget is reached, the Actor stops with partial results
and a status message. Increase the applicable budget and resurrect the same run
with the same normalized target set to continue its unfinished queue. When
`skipInvalidInputs` is `false`, keep the same invalid input strings as well.
Reordering the same targets or changing run memory does not change their saved
identities.

### Limitations

- The Actor returns public profile metadata only.
- It does not collect private emails, private organization settings, private
  repositories, repository content, commits, contribution graphs, members,
  follower lists, stars, or events.
- Public fields can be `null` when a profile does not publish them or GitHub
  does not make them publicly available.
- Counts and timestamps reflect GitHub's response at collection time and can
  change independently between requests.
- GitHub Enterprise Server and custom GitHub hosts are not supported.

### More Actors by AimScrape

Explore other public-data tools from
[AimScrape](https://apify.com/aimscrape):

| Actor | Best for |
| --- | --- |
| [Snapchat Profile Scraper](https://apify.com/aimscrape/snapchat-profile-scraper) | Collecting public Snapchat profile metadata, subscriber counts, verification, and Snapcodes. |
| [Fast TikTok Profile Scraper 🚀](https://apify.com/aimscrape/tiktok-profile-scraper) | Collecting public TikTok profile details, audience counts, likes, and verification. |
| [Fast YouTube Channel Scraper](https://apify.com/aimscrape/youtube-channel-scraper) | Collecting public YouTube channel metadata, counts, verification, and external links. |
| [Fast YouTube Channel Video Scraper 🚀](https://apify.com/aimscrape/youtube-channel-video-scraper) | Exporting public video metadata from a YouTube channel's Videos tab. |
| [YouTube Advanced Search Scraper](https://apify.com/aimscrape/youtube-search-video-scraper) | Finding YouTube videos by keyword with channel and engagement metadata. |

### Responsible use and support

Use collected public data lawfully and for a legitimate purpose. Profile fields
can contain personal data supplied by GitHub users; review the laws and policies
that apply to your use case. This Actor is an independent third-party tool and
is not affiliated with or endorsed by GitHub.

For run-specific troubleshooting, include the run ID and non-sensitive log
details when contacting the Actor's support channel. Never include proxy
credentials or access tokens in support messages.

# Actor input Schema

## `usernames` (type: `array`):

Add bare usernames, @usernames, or HTTPS profile URLs from github.com or www.github.com. The input form checks only the basic shape and allowed characters, without limiting username length or enforcing GitHub's exact first/last character rules, so valid entries in mixed lists can still run. Before queueing, the Actor applies GitHub's stricter username rules. Invalid entries make no network requests and are skipped by default.

## `skipInvalidInputs` (type: `boolean`):

Do not store invalid_input results in the Dataset. Invalid entries are still rejected locally without a network request, while valid entries continue normally. Disable this option to store invalid_input rows.

## Actor input object example

```json
{
  "usernames": [
    "https://github.com/github"
  ],
  "skipInvalidInputs": true
}
```

# Actor output Schema

## `overview` (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 = {
    "usernames": [
        "https://github.com/github"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("aimscrape/github-profile-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 = { "usernames": ["https://github.com/github"] }

# Run the Actor and wait for it to finish
run = client.actor("aimscrape/github-profile-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 '{
  "usernames": [
    "https://github.com/github"
  ]
}' |
apify call aimscrape/github-profile-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,aimscrape/github-profile-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/cmvg3wGHfCzAZB0dq/builds/As4hEWEPIiTodPhH9/openapi.json
