# Reddit Profile Scraper (`w3crawler/reddit-profile-scraper`) Actor

Scrape public Reddit user profiles by username or profile URL, including karma, account metadata, trophies, and optional recent activity.

- **URL**: https://apify.com/w3crawler/reddit-profile-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 profiles

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

### Reddit Profile Scraper

Extract bounded public profile metadata from [Reddit](https://www.reddit.com/) by username or public profile URL. The Actor can include a small, caller-selected window of recent public posts and comments, with explicit activity status when a requested section is empty or unavailable.

Actor page: [Reddit Profile Scraper on Apify](https://apify.com/w3crawler/reddit-profile-scraper)

#### Why use this Actor

Use it to build a current, public-only profile inventory for research, moderation support, community analysis, or other lawful workflows that need profile-level context. Each normal record is tied to a canonical public profile URL and includes the representation used for extraction.

The Actor does not log in, access private account data, solve CAPTCHAs, hide automation, alter browser fingerprints, bypass Reddit access controls, or claim that a blocked page is a profile. A failed profile request becomes a four-field diagnostic.

#### What the dataset contains

| Field                                                              | Description                                                                           |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------- |
| `recordType`                                                       | `profile` for a normal public profile row.                                            |
| `recordId`                                                         | Stable identity derived from the normalized public username.                          |
| `sourceUrl`, `profileUrl`                                          | Canonical public Reddit profile provenance.                                           |
| `username`, `requestedUsername`                                    | Username returned by Reddit and the caller's normalized request.                      |
| `commentKarma`, `linkKarma`, `totalKarma`                          | Public karma values when exposed.                                                     |
| `createdAt`, `accountAgeDays`                                      | Public account creation time and derived age when available.                          |
| `isGold`, `isMod`, `isEmployee`, `hasVerifiedEmail`, `isSuspended` | Public markers only when observable from the page.                                    |
| `bio`                                                              | Public profile description when exposed.                                              |
| `trophies`                                                         | Public trophy names, descriptions, and icons when exposed.                            |
| `recentPosts`, `recentComments`                                    | Optional bounded public activity selected by the caller.                              |
| `includeRecentPosts`, `includeRecentComments`, `maxRecentItems`    | Caller settings retained in each normal row.                                          |
| `activityStatus`                                                   | Per-section `not_requested`, `available`, `empty`, or `unavailable` status and count. |
| `extractionMethod`, `scrapedAt`                                    | Public-page representation and UTC extraction time.                                   |

Diagnostic rows contain only `url`, `error`, `errorCode`, and `scrapedAt`. They describe a blocked, login-redirected, unavailable, or incomplete public profile and never contain placeholder profile data.

#### Input

`usernames` is required. All other fields are optional. Unknown fields, loose type coercion, invalid usernames, and unsupported profile URL shapes are rejected.

| Field                   | Type and limits                                                                                                             | Default  | Behavior                                                                                                    |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------- |
| `usernames`             | Array of 1–20 strings; each value is a bare Reddit username, `u/name`, or HTTPS profile URL with a 1–30 character username. | required | Duplicate normalized usernames are removed; one public profile request is scheduled per remaining username. |
| `includeRecentPosts`    | Boolean.                                                                                                                    | `false`  | Request a bounded public `/submitted/` section.                                                             |
| `includeRecentComments` | Boolean.                                                                                                                    | `false`  | Request a bounded public `/comments/` section.                                                              |
| `maxRecentItems`        | Integer from 1–50.                                                                                                          | `10`     | Maximum posts and maximum comments per profile when those sections are requested.                           |
| `proxyConfiguration`    | Optional Apify Proxy or custom proxy object.                                                                                | unset    | A proxy is created only when `useApifyProxy` is true or `proxyUrls` contains at least one HTTP(S) URL.      |

Accepted profile URL forms include `https://reddit.com/user/name/`, `https://www.reddit.com/user/name/`, and the equivalent `old.reddit.com/u/name/` form. The runtime normalizes these to the public `www.reddit.com/user/name/` page. The input has no precedence rules: all normalized usernames are processed once, and activity options apply to every profile in the run.

#### Input examples

##### Profile metadata only

```json
{
  "usernames": [
    "public_user",
    "u/another_user",
    "https://www.reddit.com/user/third_user/"
  ]
}
```

##### Profile plus recent public posts

```json
{
  "usernames": ["public_user"],
  "includeRecentPosts": true,
  "includeRecentComments": false,
  "maxRecentItems": 5
}
```

##### Profile plus both activity sections and Apify Proxy

```json
{
  "usernames": ["public_user", "another_user"],
  "includeRecentPosts": true,
  "includeRecentComments": true,
  "maxRecentItems": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

##### Direct custom proxy configuration

```json
{
  "usernames": ["public_user"],
  "proxyConfiguration": {
    "proxyUrls": ["http://proxy.example.test:8080"]
  }
}
```

#### Run it in Apify Console

1. Open the [Actor page](https://apify.com/w3crawler/reddit-profile-scraper) and choose **Try for free** or **Start**.
2. Enter one or more public usernames or profile URLs in `usernames`.
3. Enable recent posts or comments only when the activity window is needed, then choose `maxRecentItems`.
4. Add permitted Proxy settings if the run requires them. Proxy does not bypass a challenge or make private data public.
5. Start the run and inspect normal rows separately from diagnostics. Open the `OUTPUT` key-value record for counts and activity status totals.

#### Cost and run sizing

Browser execution, response size, dataset storage, and optional Proxy usage affect Apify cost. The Actor's configured pay-per-event metadata charges per profile dataset event; check the Actor page for current account pricing. Start with one username, metadata only, and a small activity limit. Increase the list or activity window after confirming that Reddit is returning public pages. A Proxy cannot turn an access challenge into a successful profile record.

#### Normal output example

```json
{
  "recordType": "profile",
  "recordId": "reddit-profile:87a2c41e3db2194ce9aa",
  "sourceUrl": "https://www.reddit.com/user/public_user/",
  "username": "public_user",
  "profileUrl": "https://www.reddit.com/user/public_user/",
  "commentKarma": 1234,
  "linkKarma": 5678,
  "totalKarma": 6912,
  "createdAt": "2020-01-02T03:04:05.000Z",
  "accountAgeDays": 2430,
  "isGold": false,
  "isMod": false,
  "isEmployee": false,
  "hasVerifiedEmail": true,
  "isSuspended": false,
  "bio": "Public profile description.",
  "trophies": [
    {
      "name": "Verified Email",
      "description": "Public trophy marker",
      "icon": "https://www.reddit.com/icon.png"
    }
  ],
  "recentPosts": [
    {
      "id": "abc123",
      "title": "A public post",
      "subreddit": "smallbusiness",
      "score": 12,
      "numComments": 3,
      "createdAt": "2026-09-07T12:00:00.000Z",
      "permalink": "https://www.reddit.com/r/smallbusiness/comments/abc123/a_public_post/",
      "url": "https://www.reddit.com/r/smallbusiness/comments/abc123/a_public_post/",
      "selfText": "Public post text."
    }
  ],
  "requestedUsername": "public_user",
  "includeRecentPosts": true,
  "includeRecentComments": false,
  "maxRecentItems": 5,
  "activityStatus": {
    "posts": {
      "requested": true,
      "status": "available",
      "count": 1
    },
    "comments": {
      "requested": false,
      "status": "not_requested",
      "count": 0
    }
  },
  "extractionMethod": "reddit-profile-rendered-dom",
  "scrapedAt": "2026-09-08T06:30:00.000Z"
}
```

#### Fallback and diagnostic output

If a requested activity section is public but empty, the profile is retained and that section is marked `empty`. If a requested section cannot be fetched, the profile is retained with `activityStatus.<section>.status` set to `unavailable` and a bounded error. The Actor does not invent activity items.

When the profile itself is blocked or unavailable, the dataset contains a diagnostic such as:

```json
{
  "url": "https://www.reddit.com/user/public_user/",
  "error": "ACCESS_BOUNDARY: Reddit presented an anti-bot challenge or blocked the public profile request",
  "errorCode": "REDDIT_ACCESS_BLOCKED",
  "scrapedAt": "2026-09-08T06:30:00.000Z"
}
```

Common diagnostic codes are `REDDIT_ACCESS_BLOCKED`, `PROFILE_UNAVAILABLE`, and `REDIRECT_OUT_OF_SCOPE`. A run can contain normal profile rows and diagnostics for other usernames at the same time.

#### Run summary output

The `OUTPUT` key-value record describes the run; it is not a replacement for dataset rows:

```json
{
  "recordType": "runSummary",
  "sourceWebsite": "https://www.reddit.com/",
  "usernames": ["public_user", "another_user"],
  "includeRecentPosts": true,
  "includeRecentComments": true,
  "maxRecentItems": 3,
  "proxyConfigured": false,
  "profilesStored": 1,
  "diagnosticsStored": 1,
  "failedRequests": 1,
  "blockedRequests": 1,
  "activitySummary": {
    "postsRequested": 1,
    "commentsRequested": 1,
    "postsReturned": 3,
    "commentsReturned": 3,
    "unavailableSections": []
  },
  "found": true,
  "dataAvailable": true,
  "diagnosticReasons": [
    "ACCESS_BOUNDARY: Reddit presented an anti-bot challenge or blocked the public profile request"
  ],
  "scrapedAt": "2026-09-08T06:30:00.000Z"
}
```

`recordType` is `runSummary` when at least one normal profile is stored and `runDiagnostic` when none are stored. `found` and `dataAvailable` are true only when a normal profile row was written.

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

#### Advanced usage and boundaries

- Use bare usernames for simple batch work and canonical profile URLs when the input itself is part of your provenance record.
- Set both activity flags independently. `maxRecentItems` is applied separately to posts and comments for every profile.
- Public profile pages may expose different fields over time. Missing karma, trophies, markers, or timestamps remain absent rather than being inferred.
- Activity URLs are accepted only when they resolve to HTTPS Reddit URLs. External links in post content are not treated as Reddit activity provenance.
- Proxy settings are transport configuration only. They do not bypass login walls, CAPTCHAs, rate limits, or access controls.
- Treat public profile information as personal data where applicable. Minimize retention, restrict access, honor deletion or opt-out requests, and use a lawful purpose.

#### Troubleshooting

##### The run contains `REDDIT_ACCESS_BLOCKED`

Reddit returned a challenge, login wall, WAF response, or other access boundary. Try one public username, reduce the activity scope, wait before retrying, and review Reddit and Proxy terms. Do not attempt to bypass the challenge.

##### The run contains `PROFILE_UNAVAILABLE`

The public page loaded without a usable profile representation. Check the username spelling and canonical public URL. Suspended, deleted, or age-gated accounts may not expose the fields this Actor requires.

##### The run contains `REDIRECT_OUT_OF_SCOPE`

The final browser URL left HTTPS Reddit. Use the canonical Reddit profile URL and remove external redirect wrappers.

##### Activity is `unavailable`

The profile itself was available, but the requested `/submitted/` or `/comments/` page could not be fetched. The profile row remains usable; inspect the bounded status error and rerun later if the activity is important.

#### API and issues

The Actor can be started and monitored through the [Apify API documentation](https://docs.apify.com/api/v2) using the Actor ID or the [Actor page](https://apify.com/w3crawler/reddit-profile-scraper). For a reproducible problem, include the run ID, sanitized input shape, diagnostic code, and `OUTPUT` summary in the Actor's Issues or support channel. Do not include private account data, proxy credentials, or session tokens in a report.

#### Privacy, legal, and non-affiliation

This Actor is intended only for publicly visible Reddit profile and activity pages and does not provide legal advice. You are responsible for complying with Reddit's terms, subreddit rules, applicable privacy and data-protection laws, copyright requirements, and any consent, retention, or opt-out obligations. Do not use results to infer protected characteristics, make high-impact decisions, or target people in sensitive contexts.

This is an independent third-party Actor. It is not sponsored, endorsed, administered, or affiliated with Reddit, Inc., Apify, or any Reddit community. Reddit and related names and marks belong to their respective owners.

#### Local development

```bash
npm install
npm test
npm run check
apify validate-schema
apify run --purge --input-file .actor/input.json
npm run validate-datasets
```

# Changelog

This Actor's version history is a separate document: https://apify.com/w3crawler/reddit-profile-scraper/changelog.md

# Actor input Schema

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

One to 20 public Reddit usernames, u/name values, or complete reddit.com profile URLs.

## `includeRecentPosts` (type: `boolean`):

Include a bounded selection of recent public submissions.

## `includeRecentComments` (type: `boolean`):

Include a bounded selection of recent public comments.

## `maxRecentItems` (type: `integer`):

Maximum recent posts or comments per profile.

## `proxyConfiguration` (type: `object`):

Optional Apify or custom proxy configuration.

## Actor input object example

```json
{
  "usernames": [
    "unconventionalbook"
  ],
  "includeRecentPosts": false,
  "includeRecentComments": false,
  "maxRecentItems": 10
}
```

# Actor output Schema

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

URL of the default dataset items endpoint.

## `runSummary` (type: `string`):

Profile inputs, activity settings, saved records, failures, and public-data availability.

# 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": [
        "unconventionalbook"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("w3crawler/reddit-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": ["unconventionalbook"] }

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

```

## MCP server setup

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