# Reddit User Scraper - Profiles, Karma, Posts & Comments (`studioxl/reddit-user-scraper`) Actor

Reddit profiles for 1 to 1,000 usernames per run: post and comment karma, account age, followers, verified badge, premium and bio, plus each account's newest posts and comments if you want them. Suspended, deleted and missing accounts are listed and never charged.

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

## Pricing

from $0.99 / 1,000 row saveds

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

## Reddit User Scraper - Profiles, Posts & Comments

Paste as many as 1,000 Reddit usernames or profile links and get one row per account: karma split into post and comment karma, account age, followers, verified badge, premium status, bio and avatar. Add each account's newest posts and comments as extra rows if you need them. Built for audience research, creator and partner vetting, and community moderation. No Reddit account or login needed.

### What it is for

- **Audience research.** You have the usernames from a thread or a community and want to know who they are as a group: how old the accounts are, how much they post, how many are new.
- **Creator and partner vetting.** Before you sponsor, hire or partner with a Reddit creator, check account age, karma, verified badge and what they have posted lately.
- **Moderation.** Check the accounts in your mod queue or your mod applicants: account age, karma split, whether the profile is marked 18+, and which subreddits they already moderate.

It reads only what any visitor sees on a public profile. It is built for looking at accounts in bulk for these purposes, not for building a file on one private person.

### Measured

Measured on 2026-10-20 on this Actor, with comment authors taken from recent Reddit threads:

| Run | Accounts in | Rows saved | Time | Rows per minute |
|---|---:|---:|---:|---:|
| Profile only | 1,000 | 944 | 38.8 min | 24 |
| Profile only | 100 | 95 | 4.0 min | 24 |
| Profile + posts + comments, 25 of each | 20 | 576 (20 profiles, 228 posts, 328 comments) | 4.1 min | 140 |
| Three profile-only runs started together | 3 x 30 | 87 | 3.4 to 3.8 min each | 23 combined |

Of the 1,000 usernames, 55 were suspended and 1 did not exist. Those 56 were listed for free, so the run was charged for 944 rows. Runs in the same account share one pace: three at once finished in about the time one 90-account run takes, so splitting a list into parallel runs does not make it faster.

### What you get

One row per account (`recordType: profile`):

| Field | Example | Notes |
|---|---|---|
| `username`, `id`, `profileUrl` | GallowBoob, t2_iqsg6 | Original capitalisation |
| `karmaTotal`, `karmaFromPosts`, `karmaFromComments` | 36838255, 35727417, 1110838 | Filled on all 944 measured rows |
| `createdAt`, `accountAgeDays` | 2014-10-07T09:38:40.859Z, 4396 | Account creation, UTC, ISO 8601 |
| `postCount`, `commentCount` | 12730, 14642 | What the profile reports in total, not what this run saved |
| `followers` | 33919 | Most accounts have none: 38 of 944 (4%) had more than zero |
| `verified` | false | The verified badge. 2 of 944 measured accounts had it |
| `premium`, `isEmployee` | true, false | |
| `displayName`, `title`, `bio` | Rob, The internet was a mistake | A bio is set on 18% of accounts |
| `avatarUrl`, `bannerUrl`, `socialLinks` | | |
| `isNsfw` | false | The profile itself is marked 18+. 209 of 944 measured accounts (22%) |
| `historyCuratedByUser` | false | The account hides part of its history from its public profile. 310 of 944 (33%) |
| `hasProfilePage` | true | 1 of 944 measured accounts had karma but no profile page; such rows have no bio, followers or banner |
| `trophyCount` | 44 | Filled on 942 of 944 measured rows |
| `trophies` | \[{"name": "Verified Email", "grantedAt": "2023-01-01T00:00:00.000Z"}] | Only when "Trophy list" is on |
| `isMod`, `moderatedSubreddits` | true, \[{"name": "StoppedWorking", "subscribers": 626052}] | Only when "Moderated subreddits" is on |

`trophies`, `isMod` and `moderatedSubreddits` are empty, not `false` or `[]`, when you did not ask for them. An empty value that means "not requested" must never read as "moderates nothing".

**Posts** (`recordType: post`) have the same columns as our [Reddit Search Scraper](https://apify.com/studioxl/reddit-post-search-scraper): title, text, link, subreddit, score, upvote ratio, comment count, flair and flat media columns. `profileUsername` says which account they came from. Posts on the account's own profile show the subreddit as `u_<name>`.

**Comments** (`recordType: comment`) have the same columns as our [Reddit Comments Scraper](https://apify.com/studioxl/reddit-comments-replies-scraper): text, score, date, link, post ID, post title and subreddit. Comments longer than 300 characters are saved in full, with their parent ID, edit date and flair. Shorter comments come with their complete text, but parent ID, edit date and flair are empty. In the 20-account run, 26 of 328 comments (8%) were long enough to need the full fetch. `subreddit` was empty on 43 of 328 comments (13%): 23 of those were on posts deleted since.

Suspended, deleted and nonexistent accounts are not rows. They are listed for free in the **Skipped accounts** record and in the run message, so you can see exactly which names did not resolve and why.

### How to use it

1. Paste usernames, one per line. `spez`, `u/spez` and `https://www.reddit.com/user/spez/` all work. The same account listed twice is collected once.
2. Pick what to collect: profile only, or profile plus posts, comments or both.
3. Click **Start** and download CSV, Excel or JSON from the **Output** tab. Switch between the Profiles, Posts and Comments views.

```json
{
  "usernames": ["spez", "u/GallowBoob"],
  "mode": "all",
  "maxPostsPerUser": 25,
  "maxCommentsPerUser": 25
}
```

### Input

| Field | What it does |
|---|---|
| Usernames or profile links | 1,000 per run at most. Lines that are not usernames are skipped and listed in the run summary. |
| What to collect | Profile only (`profile`), `profile_posts`, `profile_comments` or `all`. |
| Max posts / comments per account | Newest first, 0 to 1,000 each. |
| Full text of long comments | On by default. Off saves one step per long comment, but those comments stop at 300 characters (`bodyTruncated: true`). |
| Trophy list | Adds the list of trophies. Slower: one extra step per account. |
| Moderated subreddits | Adds `isMod` and the list. Slower: one extra step per account. |
| Include 18+ posts | Off by default. Accounts are never skipped for being 18+; only 18+ posts are left out. |

Calling it from code or an AI agent? `users`, `profiles`, `profileUrls`, `urls` and `startUrls` work for the usernames. `maxPosts` and `maxComments` work for the limits, and `includePosts` and `includeComments` (true or false) work instead of `mode`. Fields the scraper doesn't know are ignored and listed in the run message.

### Output example

```json
{
  "recordType": "profile",
  "username": "GallowBoob",
  "profileUrl": "https://www.reddit.com/user/GallowBoob/",
  "displayName": "Rob",
  "createdAt": "2014-10-07T09:38:40.859Z",
  "accountAgeDays": 4396,
  "karmaTotal": 36838255,
  "karmaFromPosts": 35727417,
  "karmaFromComments": 1110838,
  "postCount": 12730,
  "commentCount": 14642,
  "followers": 33919,
  "verified": false,
  "premium": true,
  "isNsfw": false,
  "trophyCount": 44,
  "isMod": null
}
```

### Pricing

You pay per saved row, whether it is a profile, a post or a comment. There is no start fee.

| Apify plan | Discount tier | Per 1,000 rows | Per row |
|---|---|---:|---:|
| Free | No discount | $1.29 | $0.00129 |
| Starter | Bronze | $1.19 | $0.00119 |
| Scale | Silver | $1.09 | $0.00109 |
| Business | Gold | $0.99 | $0.00099 |

- 1,000 profiles cost $1.29 on the Free plan. 20 accounts with 25 posts and 25 comments each are at most 1,020 rows, so about $1.32.
- Suspended, deleted and nonexistent accounts are free. The same account or post twice in one run is charged once.
- Set "Maximum cost per run" in Run options for a hard cap. If that cap is too low to save even one row, the run says so and collects nothing.

### FAQ

**Why did I get fewer posts than `postCount`?** `postCount` is the total the profile reports, and your per-account limit usually stops first. When it does not, the account may hide part of its history (`historyCuratedByUser: true`), or the posts were removed. The run summary shows, per account, whether collection ended at your limit or because nothing more was visible.

**Why are some accounts missing from the dataset?** They are suspended, deleted or do not exist. Each is listed in the Skipped accounts record with its reason, and none is charged.

**How long does a run take?** Profile only runs at about 24 accounts a minute, so 1,000 accounts took 38.8 minutes. With 25 posts and 25 comments per account, 20 accounts took 4.1 minutes. Set the run timeout in Run options above that. A run that hits its timeout keeps what it saved. To finish the list in the same dataset, open the run and choose **Actions > Resurrect** with a longer timeout: rows already saved are not charged again.

**Can I run it on a schedule?** Yes. Save the input as a task and add a schedule. Results can go to Google Sheets, Slack, Make, Zapier or n8n through Apify integrations.

### Limits

- At most 1,000 accounts per run, and at most 1,000 posts and 1,000 comments per account, newest first.
- Public data only: no email, location, private messages or voting history.
- Comments carry no 18+ marker, so "Include 18+ posts" cannot filter them.
- Scores, karma and follower counts are a snapshot from the moment of collection.

### Changelog

**0.1 (2026-10-20).** First release. The first 100-account test skipped 23 accounts because their profiles are marked 18+. That rule dropped almost a quarter of the list, so accounts are never skipped for it now: `isNsfw` reports it and "Include 18+ posts" filters posts only.

Questions or a missing field? Open an issue in the **Issues** tab with your run ID.

# Actor input Schema

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

One per line, 1,000 at most. Accepts spez, u/spez or https://www.reddit.com/user/spez/. The same account listed twice is collected and charged once.

## `mode` (type: `string`):

Profile only takes one step per account: one row per account with karma, account age, followers and bio. The other options add one row per post or comment.

## `maxPostsPerUser` (type: `integer`):

Newest posts first. Used only when posts are collected. You pay only for posts that are saved.

## `maxCommentsPerUser` (type: `integer`):

Newest comments first. Used only when comments are collected. You pay only for comments that are saved.

## `fullCommentText` (type: `boolean`):

On: comments longer than 300 characters are saved in full, with their parent ID, edit date and flair. Off: those comments stop at 300 characters (bodyTruncated is true), which saves one step per long comment. The price per row is the same either way.

## `includeTrophies` (type: `boolean`):

Adds each account's trophies (name, date, icon) to its profile row. The trophy count is included either way. Adds one step per account.

## `includeModeratedSubreddits` (type: `boolean`):

Adds isMod and the list of subreddits the account moderates. When off, these fields are empty rather than false, so an empty value never reads as 'moderates nothing'. Adds one step per account.

## `includeNsfw` (type: `boolean`):

Off by default: posts marked 18+ are left out. Every account still gets its profile row; isNsfw shows whether the profile itself is marked 18+, as 22% of 944 measured accounts were. Comments carry no 18+ marker and are kept.

## Actor input object example

```json
{
  "usernames": [
    "spez",
    "u/GallowBoob"
  ],
  "mode": "profile",
  "maxPostsPerUser": 25,
  "maxCommentsPerUser": 25,
  "fullCommentText": true,
  "includeTrophies": false,
  "includeModeratedSubreddits": false,
  "includeNsfw": false
}
```

# Actor output Schema

## `profiles` (type: `string`):

One row per account. Switch views for posts, comments or every field.

## `json` (type: `string`):

Every row and field.

## `csv` (type: `string`):

Every row and field for spreadsheets.

## `skipped` (type: `string`):

Suspended, deleted and missing accounts that were skipped.

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

Rows saved per account, why each account stopped, and why the run stopped.

# 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",
        "u/GallowBoob"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("studioxl/reddit-user-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",
        "u/GallowBoob",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("studioxl/reddit-user-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": [
    "spez",
    "u/GallowBoob"
  ]
}' |
apify call studioxl/reddit-user-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,studioxl/reddit-user-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/mxhPXrutxxcenhLyB/builds/v9h7bftDjWQahDo2x/openapi.json
