# Endchan Scraper — Posts, Replies & Quote Links (`thescrapelab/endchan-public-discussion-scraper`) Actor

Scrape public Endchan posts and replies with timestamps, quotes and source URLs. Export JSON, CSV or Excel without an Endchan login or source API.

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

## Pricing

from $1.00 / 1,000 saved public post or replies

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

<p align="center"><img src="https://api.apify.com/v2/key-value-stores/RCp47kYO5ACDiLlhK/records/endchan-logo.png" width="144" alt="Endchan Scraper conversation and quote network emblem"></p>

Collect public **Endchan posts and replies** from board or thread URLs, with timestamps, source links and quote references. Export JSON, CSV or Excel for conversation research and repeated community snapshots. No Endchan login, source API key or proxy purchase is required.

Each run collects a bounded snapshot of the public boards or threads you supply. You control the maximum number of saved posts and can set an Apify spending limit.

### Use cases: Endchan conversation research

Save one structured result for each original post or reply. Study discussions, follow supplied threads or compare board samples between runs. Stable post IDs connect records; anonymous names are not persistent identities.

Board pages discover threads; text comes from full public thread pages. It collects text and metadata without downloading media. Source policy and collection limits apply.

### How to scrape Endchan posts and replies

1. Paste one or more public `https://endchan.net/` board or thread URLs.
2. Choose **Maximum posts**, then start the run. The default is 20.
3. Open **Posts and replies** to inspect or export results. Check **Collection summary** to understand coverage and why the run stopped.

Replies are included automatically. Expand **Optional settings** to turn them off or apply filters.

### Inputs and useful output

| Input | How to use it |
|---|---|
| Board or thread URLs | Supply 1–10 public Endchan board, board-page or full-thread URLs. |
| Maximum posts | Choose 1–1,000. Originals and replies each count as one result. |
| Include replies | Enabled by default under Optional settings. |
| Post text keywords | Optional, case-insensitive OR matches over fetched posts. An original can also match its subject. |
| Published on or after / before | Optional inclusive UTC dates, written as `YYYY-MM-DD`. Posts without dates are excluded when date bounds apply. |

The maximum is a ceiling. Filters apply to fetched posts, without global search or automatic ancestor retrieval. Direct thread URLs take priority over board discovery.

```json
{"startUrls": ["https://endchan.net/tech/"], "maxItems": 20}
```

These abbreviated, sanitized records were observed in a public technology thread on 22 October 2026:

```json
[
  {
    "recordId": "endchan.net:tech:15907",
    "recordType": "original",
    "text": "can someone help me by using handbrake to split an mkv into multiple mp4s and upload? is this the right place to ask?",
    "publishedAt": "2026-10-04T14:55:00.000Z",
    "quotedPostIds": [],
    "postUrl": "https://endchan.net/tech/res/15907.html#15907"
  },
  {
    "recordId": "endchan.net:tech:15939",
    "recordType": "reply",
    "text": ">>15907\nUse losslesscut",
    "publishedAt": "2026-10-20T02:24:00.000Z",
    "quotedPostIds": [
      "tech:15907"
    ],
    "postUrl": "https://endchan.net/tech/res/15907.html#15939"
  }
]
```

The default table highlights board, post type, thread title, text, publication time, quotes and source link. Full JSON adds author, collection/edit times, outbound links and structured quote targets. Unavailable values remain `null`; thread titles can be absent.

Use `recordId` to join snapshots. Quote IDs include the board, because numeric IDs can repeat. Quotes do not establish parents. Choose **Snapshot comparison** to compare `contentHash` for the same record ID. Hashes describe normalized, redacted output; they do not prove edit history. Older saved rows may lack a hash.

### How much does Endchan scraping cost?

**$1 per 1,000 saved posts/replies ($0.001 each), plus $0.02 per started run.** Run compute and source fetching are included; there is no subscription.

| Saved posts/replies in one run | Total charge |
| --- | ---: |
| 0 | $0.02 |
| 20 | $0.04 |
| 100 | $0.12 |
| 1,000 | $1.02 |

These totals assume enough accessible content fits within the collection limits. The Pricing tab is authoritative.

The start fee also applies to empty or unavailable-source runs. Previews, filtered posts, within-run duplicates, errors and summary records have no result fee. Repeated runs are new snapshots and can save the same posts again. Ordinary Apify storage and exports after the run can incur platform charges. A minimum spending limit of $0.021 covers the start plus at most one post; it does not guarantee a result. A $0.04 limit permits up to 20 saved posts. Multiple small runs each incur a start fee.

### Coverage and common questions

#### What does the collection status mean?

The summary starts with a short explanation: `finished` means the bounded scope was scanned; `limited` means a cap or pending work remains; `partial` means a source omission or page failure; `failed` means collection failed; `interrupted` means shutdown retained saved work. Zero matching results can be a valid finished scan.

#### Can it collect every reply or all history?

It collects accessible replies in fetched HTML within 10 content attempts by default (including retries; up to 20 with an explicit `maxRequests`), a two-minute source-request deadline, 2 MiB per response and 8 MiB total download reservations. Startup, parsing and storage can add time; use a 150-second host timeout. Missing, deleted, private and omitted historical content is not recovered.

#### What if access is denied or fewer posts appear?

Check the summary for filters, limits and failed URLs. The Actor respects source policy and stops for access refusals or rate limits. It does not bypass them. For support, provide the run ID and public URL through the Issues tab when available; never send credentials.

Public access does not grant commercial reuse rights. Confirm permissions for your intended use. Common contact patterns are redacted, but this is not a complete personal-data detector. This independent tool is not endorsed by Endchan.

### Use Endchan Scraper with Python

Uses `apify-client` 3.x and an Apify token, without Endchan credentials. The maximum-charge setting covers the run start and saved-result fees. This example permits up to 20 results for $0.04.

```python
import os
from datetime import timedelta
from decimal import Decimal
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("thescrapelab/endchan-public-discussion-scraper").call(
    run_input={"startUrls": ["https://endchan.net/tech/"], "maxItems": 20},
    memory_mbytes=256,
    run_timeout=timedelta(seconds=150),
    max_total_charge_usd=Decimal("0.04"),
    restart_on_error=False,
)
if run is None:
    raise RuntimeError("The Actor did not return a run")
for post in client.dataset(run.default_dataset_id).iterate_items():
    print(post["recordId"], post["text"], post["postUrl"])
```

# Changelog

This Actor's version history is a separate document: https://apify.com/thescrapelab/endchan-public-discussion-scraper/changelog.md

# Actor input Schema

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

1–10 public HTTPS endchan.net board or full-thread HTML URLs. Only this host; no search or arbitrary URLs.

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

Maximum saved originals and replies across all links. Fewer may be returned when no more matches are found or the request, time or spending limit is reached.

## `includeReplies` (type: `boolean`):

Fetch replies from full public thread HTML. Quoted posts are references, not inferred parents.

## `keywords` (type: `array`):

Case-insensitive OR filter over fetched post text; original posts also match their subject. Only matching rows saved. Thread URL/title and quote references retain context; ancestors need not be saved. This is not global search.

## `dateFrom` (type: `string`):

YYYY-MM-DD inclusive; filters individual posts inside the bounded crawl. Missing dates excluded when bounds used.

## `dateTo` (type: `string`):

YYYY-MM-DD inclusive. Not an incremental checkpoint or exhaustive archive query.

## `maxThreads` (type: `integer`):

Maximum distinct threads admitted across all starts; direct thread links take priority.

## `maxBoardPages` (type: `integer`):

Follow public HTML page links; bumped ordering is not chronological.

## `maxRequests` (type: `integer`):

Counts retries and failures. Robots policy requests are separate.

## Actor input object example

```json
{
  "startUrls": [
    "https://endchan.net/tech/"
  ],
  "maxItems": 20,
  "includeReplies": true,
  "keywords": [],
  "maxThreads": 20,
  "maxBoardPages": 3,
  "maxRequests": 10
}
```

# Actor output Schema

## `posts` (type: `string`):

No description

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

No description

## `networkAudit` (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("thescrapelab/endchan-public-discussion-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("thescrapelab/endchan-public-discussion-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 thescrapelab/endchan-public-discussion-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,thescrapelab/endchan-public-discussion-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/LgBbIne2yXpTNX6QC/builds/FkEyDky6XL6XgacSn/openapi.json
