# Reddit User Profile Bulk Scraper (`automation-lab/reddit-user-profile-bulk-scraper`) Actor

Bulk-enrich public Reddit usernames into one profile row each with karma, account age, bio, follower count, assets, account flags, and explicit outcome statuses.

- **URL**: https://apify.com/automation-lab/reddit-user-profile-bulk-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Reddit User Profile Bulk Scraper

Turn Reddit usernames and profile URLs into one clean account record per user.

This Actor extracts public Reddit profile metadata: account ID, creation date and age, karma breakdown, follower count, bio, profile assets, account badges, moderation flags, NSFW status, visibility, and canonical URL. It deliberately excludes posts and comments, so the output stays compact and predictable for enrichment workflows.

### What this Actor does

Provide a list of Reddit usernames, profile URLs, or both. The Actor:

1. validates and deduplicates targets case-insensitively;
2. opens an anonymous public Reddit session through an Apify residential proxy;
3. completes Reddit's automatic JavaScript verification when presented;
4. reads the public account profile payload;
5. emits exactly one typed row per unique requested username;
6. distinguishes missing, suspended, private, blocked, and failed targets.

A Reddit login, Reddit API key, user cookies, and manual CAPTCHA solving are not required.

### Who is it for?

- **Audience research teams** enriching creator or community-member lists.
- **Moderation teams** reviewing account age, karma, and public account flags.
- **Trust and safety teams** refreshing public account watchlists.
- **OSINT researchers** normalizing public account metadata into datasets.
- **Creator and lead-enrichment teams** attaching public Reddit signals to records.
- **Data engineers** scheduling profile snapshots for downstream comparison.

### Why use a profile-only scraper

General Reddit scrapers are designed around posts, comments, communities, and search results. This Actor is optimized for a different job: converting a known username list into one account-level row per target.

That means:

- no activity-content explosion;
- simple joins on `username` or `redditUserId`;
- predictable one-target-to-one-row output;
- explicit outcome rows instead of silent missing records;
- charges only for successfully resolved public profiles, not status rows.

### Data extracted

| Field | Meaning |
| --- | --- |
| `username` | Canonical Reddit username |
| `redditUserId` | Reddit account ID without `t2_` |
| `status` | `success`, `not_found`, `suspended`, `private`, `blocked`, or `failed` |
| `statusMessage` | Explanation for non-success outcomes |
| `createdAt` | ISO 8601 account creation time |
| `accountAgeDays` | Whole account age in days at scrape time |
| `totalKarma` | Total Reddit karma |
| `linkKarma` | Link/post karma |
| `commentKarma` | Comment karma |
| `awardeeKarma` | Karma received from awards |
| `awarderKarma` | Karma earned from giving awards |
| `followersCount` | Public profile follower/subscriber count when exposed |
| `bio` | Public profile bio |
| `profileTitle` | Public profile title |
| `profileDescription` | Long public profile description |
| `avatarUrl` | Public icon or Snoovatar URL |
| `bannerUrl` | Public profile banner URL |
| `canonicalUrl` | Canonical Reddit profile URL |
| `verified` | Reddit verification flag |
| `hasVerifiedEmail` | Public verified-email flag when exposed |
| `isEmployee` | Reddit employee/admin flag |
| `isGold` | Reddit Premium/Gold flag |
| `isMod` | Moderator flag |
| `isNsfw` | NSFW profile flag |
| `isSuspended` | Suspended-account flag |
| `profileVisibility` | Public profile visibility/type value |
| `scrapedAt` | ISO 8601 scrape timestamp |

Source fields can be absent. Nullable output fields remain `null` rather than being guessed.

### Pricing

The Actor uses pay-per-event pricing:

- **$0.005** for one `start` event per run;
- one `profile` event per successfully resolved public profile.

| Apify plan tier | Price per successful profile |
| --- | ---: |
| Free | $0.0031794 |
| Bronze | $0.0027647 |
| Silver | $0.0021565 |
| Gold | $0.0016588 |
| Platinum | $0.0011059 |
| Diamond | $0.00077412 |

`not_found`, `suspended`, `private`, `blocked`, and `failed` status rows are not charged as resolved profiles. The live Apify pricing tab remains the source of truth.

For a run with **N** successful public profiles, use:

```text
estimated charge = $0.005 + (N × profile event price for your plan tier)
```

Examples:

| Successful profiles | Free plan | Bronze plan |
| ---: | ---: | ---: |
| 1 | $0.00818 | $0.00776 |
| 5 | $0.02090 | $0.01882 |
| 25 | $0.08449 | $0.07412 |
| 100 | $0.32294 | $0.28147 |

Residential proxy transfer and browser runtime are handled inside the Actor. Large lists are usually more economical than many one-profile runs because the start event is paid once and healthy sessions are reused.

### Getting started

1. Open the Actor in Apify Console.
2. Add Reddit usernames under **Reddit usernames**.
3. Optionally add existing Reddit profile links under **Reddit profile URLs**.
4. Keep **Use residential proxy** enabled for reliable Reddit access.
5. Start with concurrency `1` or `2`.
6. Click **Start**.
7. Open the **Profiles** dataset output.
8. Export the rows as JSON, CSV, Excel, XML, or RSS.

Example input:

```json
{
  "usernames": ["spez", "reddit", "AutoModerator"],
  "maxItems": 3,
  "maxConcurrency": 2,
  "maxRetries": 2,
  "useResidentialProxy": true,
  "proxyCountryCode": "US"
}
```

### Input parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `usernames` | string array | `[]` | Reddit usernames without `u/` |
| `startUrls` | request list | `[]` | `reddit.com/user/...` or `reddit.com/u/...` profile URLs |
| `maxItems` | integer | `20` | Maximum unique profiles after deduplication |
| `maxConcurrency` | integer | `2` | Parallel profile workers; allowed range 1–5 |
| `maxRetries` | integer | `2` | Session-rotating retries for transient failures; allowed range 0–4 |
| `useResidentialProxy` | boolean | `true` | Use Apify residential proxy sessions |
| `proxyCountryCode` | string | `US` | Two-letter ISO proxy country code |

At least one valid username or profile URL is required. Malformed usernames, unsupported URLs, invalid country codes, and out-of-range limits fail the run before scraping.

### Output example

A current public profile produces a row shaped like this:

```json
{
  "username": "exampleuser",
  "redditUserId": "abc123",
  "status": "success",
  "statusMessage": null,
  "createdAt": "2020-01-15T12:00:00.000Z",
  "accountAgeDays": 1825,
  "totalKarma": 15420,
  "linkKarma": 4210,
  "commentKarma": 10980,
  "awardeeKarma": 180,
  "awarderKarma": 50,
  "followersCount": 230,
  "bio": "Example public profile bio.",
  "profileTitle": "Example Profile",
  "profileDescription": null,
  "avatarUrl": "https://styles.redditmedia.com/example-avatar.png",
  "bannerUrl": null,
  "canonicalUrl": "https://www.reddit.com/user/exampleuser/",
  "verified": false,
  "hasVerifiedEmail": true,
  "isEmployee": false,
  "isGold": false,
  "isMod": true,
  "isNsfw": false,
  "isSuspended": false,
  "profileVisibility": "user",
  "scrapedAt": "2025-01-15T12:00:00.000Z"
}
```

The example is anonymized. Actual values come from the requested public Reddit account.

### Status and failure behavior

The Actor never turns a Reddit block into a false missing account.

- `success`: a recognizable public account payload was resolved.
- `not_found`: Reddit explicitly returned HTTP 404 or a 404 JSON response.
- `suspended`: Reddit identified the account as suspended.
- `private`: the returned profile visibility is private.
- `blocked`: Reddit returned a challenge/interstitial or exhausted 403/418/429 responses.
- `failed`: another upstream, browser, network, or payload-shape error exhausted retries.

Every accepted unique target receives one row, even when the profile cannot be resolved. This makes bulk joins and watchlist audits deterministic.

### Tips for reliable runs

- Leave residential proxy enabled; Reddit commonly blocks datacenter traffic.
- Start with concurrency `1` for small, high-value lists.
- Use concurrency `2` for normal bulk refreshes.
- Increase concurrency only when the observed block rate remains low.
- Keep retries at `2` unless a workflow has strict latency requirements.
- Split very large watchlists into scheduled batches.
- Use the `status` field to route retryable and terminal outcomes separately.
- Deduplicate upstream when you want stable billing estimates; the Actor also deduplicates input.

### Limits

- Only anonymous public profile metadata is extracted.
- Posts, comments, messages, and private account data are excluded.
- Reddit can change fields, verification behavior, and rate limits.
- Some flags or profile assets are not exposed for every account and remain `null`.
- Follower counts depend on what Reddit exposes in the public profile payload.
- Account age is computed at scrape time and changes between runs.
- Deleted and suspended account response shapes can vary.
- Residential proxy access must be available in the Apify account running the Actor.

### Integration workflows

#### Moderation intake

Send usernames from a moderation queue, then use account age, karma, and status fields as inputs to a human-reviewed risk workflow. Do not use a single field as an automatic enforcement decision.

#### Audience list enrichment

Join exported rows back to a CRM, spreadsheet, or warehouse on lowercase `username`. Preserve `redditUserId` for stable account-level tracking.

#### Scheduled watchlist refresh

Create an Apify schedule that runs daily or weekly. Store each run's `scrapedAt`, karma, follower, and flag fields for downstream comparisons.

#### Trust-and-safety routing

Route `blocked` and `failed` rows to a later retry. Treat `not_found` separately because it requires an explicit Reddit 404.

### Run with the Apify API using cURL

Replace `YOUR_TOKEN` with an Apify API token:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~reddit-user-profile-bulk-scraper/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "usernames": ["spez", "reddit"],
    "maxItems": 2,
    "maxConcurrency": 1,
    "useResidentialProxy": true
  }'
```

To wait for results synchronously:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~reddit-user-profile-bulk-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"usernames":["spez"],"maxItems":1}'
```

### Run with JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client.actor(
  'automation-lab/reddit-user-profile-bulk-scraper'
).call({
  usernames: ['spez', 'reddit'],
  maxItems: 2,
  maxConcurrency: 1,
  useResidentialProxy: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

Install the client with:

```bash
npm install apify-client
```

### Run with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])

run = client.actor(
    "automation-lab/reddit-user-profile-bulk-scraper"
).call(run_input={
    "usernames": ["spez", "reddit"],
    "maxItems": 2,
    "maxConcurrency": 1,
    "useResidentialProxy": True,
})

items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

Install the client with:

```bash
pip install apify-client
```

### Use with MCP and AI agents

Add the Actor to Claude Code through Apify MCP:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/reddit-user-profile-bulk-scraper"
```

#### Claude Desktop

Add the following remote MCP server JSON to Claude Desktop's MCP configuration.

#### Cursor

Use **Settings → Tools & MCP → Add MCP server** and supply the same remote URL.

#### VS Code

Add the same remote server object to your workspace or user MCP configuration.

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/reddit-user-profile-bulk-scraper"
    }
  }
}
```

Example prompts:

- “Enrich these 50 Reddit usernames and return account age, karma, and moderator status.”
- “Check this Reddit profile watchlist and separate missing, suspended, blocked, and successful accounts.”
- “Create a CSV-ready table of public bios, follower counts, karma, and profile URLs.”

### Responsible use and legality

This Actor accesses anonymous public Reddit profile metadata. Use it only for lawful purposes and in accordance with applicable laws, Reddit's terms, Apify's terms, and your organization's policies.

Do not use the output to harass users, bypass access controls, infer private traits, or make high-impact automated decisions without appropriate review. Minimize stored personal data, set retention limits, secure exports, and honor valid deletion or access requests where applicable.

You are responsible for determining the lawful basis for your processing and for complying with privacy, employment, consumer-protection, and other relevant rules.

### Troubleshooting

#### Why did I receive `blocked` instead of `not_found`?

Reddit returned a challenge, rate limit, or blocked response rather than an explicit 404. The Actor reports that uncertainty honestly. Retry later with residential proxy enabled and conservative concurrency.

#### Why are some values `null`?

Reddit does not expose every field for every account. The Actor preserves missing values as `null` rather than fabricating defaults.

#### Why did the run fail before producing rows?

Check for malformed usernames, non-Reddit URLs, an invalid proxy country, or out-of-range numeric inputs. Input validation intentionally fails closed.

#### Can I scrape posts and comments too?

Not with this profile-only Actor. Use the related Reddit Scraper for activity, community, and search workflows.

#### Can I disable the proxy?

Yes, for diagnostics, but Reddit frequently blocks datacenter and direct traffic. The default residential route is recommended for real workloads.

### FAQ

#### Does the Actor require a Reddit account?

No. It uses anonymous public surfaces and does not accept Reddit credentials or cookies.

#### Does one input always produce one output row?

Each unique, valid username accepted after deduplication produces exactly one row. Duplicate username and URL forms collapse to one case-insensitive target.

#### Are unresolved rows charged as profiles?

No. Only `success` rows emit the per-profile charge event.

#### Can I schedule it?

Yes. Use Apify Schedules to refresh a watchlist daily, weekly, or at another interval.

#### What export formats are available?

Apify datasets support JSON, JSONL, CSV, Excel, XML, and RSS exports.

### Related automation-lab Actors

- [Reddit Scraper](https://apify.com/automation-lab/reddit-scraper) — scrape Reddit posts, comments, communities, and search results when you need activity content rather than one profile row per username.

### Support

If Reddit changes its public profile response or a valid input repeatedly returns an unexpected status, open an issue from the Actor's Apify Console page. Include a minimal reproducible input, run ID, and expected outcome. Do not include private credentials or personal data that is not already public.

# Actor input Schema

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

Reddit usernames without u/. Duplicates are removed case-insensitively.

## `startUrls` (type: `array`):

Public reddit.com/user/... or reddit.com/u/... profile URLs. You can combine URLs with usernames.

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

Maximum number of unique profiles to process after deduplication.

## `maxConcurrency` (type: `integer`):

Number of profiles processed in parallel. Keep this conservative to reduce Reddit blocks and proxy churn.

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

Session-rotating retries for transient blocks, rate limits, timeouts, and server errors.

## `useResidentialProxy` (type: `boolean`):

Use Apify residential proxy sessions. Recommended because Reddit commonly blocks datacenter traffic.

## `proxyCountryCode` (type: `string`):

Two-letter ISO country code used for residential proxy requests.

## Actor input object example

```json
{
  "usernames": [
    "spez",
    "reddit"
  ],
  "startUrls": [
    {
      "url": "https://www.reddit.com/user/spez/"
    }
  ],
  "maxItems": 20,
  "maxConcurrency": 2,
  "maxRetries": 2,
  "useResidentialProxy": true,
  "proxyCountryCode": "US"
}
```

# Actor output Schema

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

Public Reddit profile metadata and per-target status records.

# 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": [
        "spez",
        "reddit"
    ],
    "startUrls": [
        {
            "url": "https://www.reddit.com/user/spez/"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/reddit-user-profile-bulk-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": [
        "spez",
        "reddit",
    ],
    "startUrls": [{ "url": "https://www.reddit.com/user/spez/" }],
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/reddit-user-profile-bulk-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": [
    "spez",
    "reddit"
  ],
  "startUrls": [
    {
      "url": "https://www.reddit.com/user/spez/"
    }
  ]
}' |
apify call automation-lab/reddit-user-profile-bulk-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=automation-lab/reddit-user-profile-bulk-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/PJ0EkeKlmmhtbenuc/builds/CJltCfZbYlyqJA5z5/openapi.json
