# GitHub Discussions Scraper (`maximedupre/github-discussions`) Actor

Collect public GitHub organization, repository, and individual discussions. Save one row per discussion with text, authors, categories, activity times, comments, replies, reactions, and source links.

- **URL**: https://apify.com/maximedupre/github-discussions.md
- **Developed by:** [Maxime Dupré](https://apify.com/maximedupre) (community)
- **Categories:** Developer tools, Social media, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.05 / 1,000 discussions

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

### 💬 Turn GitHub Discussions into usable data

Support teams, developer advocates, and product researchers can collect public GitHub Discussions in a structured dataset. Each saved row includes the discussion text, repository context, author, activity times, comments, and source links. It also includes categories, labels, reactions, and replies when GitHub exposes them. Use the data to review community questions, track product feedback, and build a searchable support or research workflow.

**Use cases**

- Build a structured feed with [**GitHub Discussions Data**](https://apify.com/maximedupre/github-discussions/examples/github-discussions-data) for support or product research.
- Use [**Scrape GitHub Discussions**](https://apify.com/maximedupre/github-discussions/examples/scrape-github-discussions) to collect public discussion pages from a repository or organization.
- Run a [**GitHub Discussions Scraper**](https://apify.com/maximedupre/github-discussions/examples/github-discussions-scraper) to save discussion text, authors, categories, and comments.
- Use [**GitHub Discussion Scraper**](https://apify.com/maximedupre/github-discussions/examples/github-discussion-scraper) when you need one public discussion URL in a dataset.
- Collect recurring community questions with [**GitHub Discussions**](https://apify.com/maximedupre/github-discussions/examples/github-discussions) and review their activity and replies.

#### 📦 One row for each public discussion

**Returned data**

The Actor saves one normalized dataset row for each eligible public GitHub discussion. Every row keeps a stable `discussionId`, the canonical `discussionUrl`, and the submitted `sourceUrl`. Text is available as `body`, with rendered HTML in `bodyHtml`. Public author, repository, date, answer, category, label, reaction, comment, and reply data follow the output schema when GitHub exposes them.

#### 🔎 Find public GitHub discussions

**How it works**

Choose one target for each run: organization discussions, repository discussions, or individual discussion URLs. Add one or more public URLs in that target's field. The Actor reads public GitHub discussion pages and saves one row for each eligible discussion. Category, latest activity, and order settings apply to organization and repository discovery. A direct discussion URL is useful when you need one known page.

Start with one URL and a small `maxItems` value to check the source. Use `category` or `latestActivityAfter` to narrow an index run. Leave `maxItems` empty to return all available results until the source is exhausted. Use `discussionId` and `discussionUrl` to join data across runs, and keep `sourceUrl` to trace each row to its submitted URL.

#### ⚙️ Input

Choose one target for each run. Add URLs only in its matching list. URLs in other target sections are ignored. `category`, `latestActivityAfter`, and `sortOrder` apply only to organization and repository discovery. `maxItems` limits the discussions saved. Leave it empty to return all available results until the source is exhausted.

**Input fields**

| Field | Type | What it does |
| --- | --- | --- |
| `target` | Select | Chooses Organization discussions, Repository discussions, or Individual discussion URLs for this run. |
| `organizationUrls` | URL list | Adds public GitHub organization discussion index URLs when `target` is `organization`. |
| `organizationUrls[].url` | URL | A public HTTPS URL for an organization's GitHub Discussions index. |
| `repositoryUrls` | URL list | Adds public GitHub repository discussion index URLs when `target` is `repository`. |
| `repositoryUrls[].url` | URL | A public HTTPS URL for a repository's GitHub Discussions index. |
| `discussionUrls` | URL list | Adds public GitHub discussion URLs when `target` is `discussion`. |
| `discussionUrls[].url` | URL | A public HTTPS URL for one GitHub discussion. |
| `category` | String | Keeps one GitHub Discussions category during organization or repository discovery. Leave it empty to include all categories. |
| `latestActivityAfter` | UTC date string | Keeps discussions whose latest activity is on or after this date during organization or repository discovery. Leave it empty to include all dates. |
| `sortOrder` | Select | Orders organization and repository lists by latest activity, top, newest, or oldest. |
| `maxItems` | Integer | Stops after this many discussions. Leave it empty to return all available results until the source is exhausted. |

**Example input**

This input came from a successful run:

```json
{
  "target": "discussion",
  "discussionUrls": [
    {
      "url": "https://github.com/orgs/community/discussions/184710"
    }
  ],
  "sortOrder": "latest",
  "maxItems": 20
}
```

#### 🧾 Output

**Dataset output**

The `dataset` output links to the Apify dataset overview. Each dataset row uses the same discussion shape for organization, repository, and direct discussion URLs. `isAnswered` and `category` appear when GitHub exposes them. Arrays such as `labels`, `reactions`, and `comments` can be empty.

**Run output**

| Field | Type | What it does |
| --- | --- | --- |
| `dataset` | URL | Links to the dataset with one row for each public GitHub discussion. |

**Discussion row fields**

| Field | Type | What it does |
| --- | --- | --- |
| `discussionId` | String | Stable ID for the discussion. |
| `discussionUrl` | URL | Canonical public URL for the discussion. |
| `sourceUrl` | URL | Submitted URL that led to this discussion row. |
| `title` | String | Discussion title. |
| `body` | String | Plain text body of the discussion. |
| `bodyHtml` | HTML string | Rendered HTML body of the discussion. |
| `owner` | String | GitHub user or organization that owns the repository. |
| `repository` | Object | Repository that contains the discussion. |
| `repository.name` | String | Short repository name. |
| `repository.fullName` | String | Repository name with its owner. |
| `repository.url` | URL | Public URL for the repository. |
| `number` | Integer | Discussion number in its repository. |
| `author` | Object | Public author of the discussion. |
| `author.login` | String | GitHub login of the discussion author. |
| `author.profileUrl` | URL | Public profile URL for the discussion author, when available. |
| `createdAt` | Date-time string | Time when the discussion was created. |
| `lastActivityAt` | Date-time string | Time of the latest public activity. |
| `isAnswered` | Boolean | Whether GitHub marks the discussion answered, when publicly exposed. |
| `category` | String | Discussion category, when publicly exposed. |
| `labels` | String array | Labels assigned to the discussion. |
| `reactions` | Object array | Reaction counts shown on the discussion. |
| `reactions[].type` | String | Reaction type name. |
| `reactions[].count` | Integer | Number of reactions of that type. |
| `commentCount` | Integer | Number of publicly rendered comments. |
| `comments` | Object array | Public comments and their nested replies. |
| `comments[].url` | URL | Public URL for the comment. |
| `comments[].author` | Object | Public author of the comment. |
| `comments[].author.login` | String | GitHub login of the comment author. |
| `comments[].author.profileUrl` | URL | Public profile URL for the comment author, when available. |
| `comments[].body` | String | Plain text body of the comment, when available. |
| `comments[].bodyHtml` | HTML string | Rendered HTML body of the comment, when available. |
| `comments[].createdAt` | Date-time string | Time when the comment was created. |
| `comments[].replies` | Object array | Replies nested under the comment. |
| `comments[].replies[].url` | URL | Public URL for a reply. |
| `comments[].replies[].author` | Object | Public author of the reply. |
| `comments[].replies[].author.login` | String | GitHub login of the reply author. |
| `comments[].replies[].author.profileUrl` | URL | Public profile URL for the reply author, when available. |
| `comments[].replies[].body` | String | Plain text body of the reply, when available. |
| `comments[].replies[].bodyHtml` | HTML string | Rendered HTML body of the reply, when available. |
| `comments[].replies[].createdAt` | Date-time string | Time when the reply was created. |
| `comments[].replies[].replies` | Object array | Further nested replies with the same comment fields. |

**Example discussion row**

This is a complete row from a successful current-beta repository run.

```json
{
  "discussionId": "nodejs/nodejs.org#7145",
  "discussionUrl": "https://github.com/nodejs/nodejs.org/discussions/7145",
  "sourceUrl": "https://github.com/nodejs/nodejs.org/discussions",
  "title": "change name of next.something and next-data",
  "body": "I don't think these names are 100% right. Because 95% of them are server side code, but not specific to nextjs. For example, it could be integrated with remix or fatsify. So I think we could review the appointment of the rosters and the structure they are in.",
  "bodyHtml": "<p dir=\"auto\">I don&apos;t think these names are 100% right.</p> <p dir=\"auto\">Because 95% of them are server side code, but not specific to nextjs. For example, it could be integrated with remix or fatsify.</p> <p dir=\"auto\">So I think we could review the appointment of the rosters and the structure they are in.</p>",
  "owner": "nodejs",
  "repository": {
    "name": "nodejs.org",
    "fullName": "nodejs/nodejs.org",
    "url": "https://github.com/nodejs/nodejs.org"
  },
  "number": 7145,
  "author": {
    "login": "AugustinMauroy",
    "profileUrl": "https://github.com/AugustinMauroy"
  },
  "createdAt": "2024-10-26T09:47:18Z",
  "lastActivityAt": "2025-08-22T00:00:59.000Z",
  "category": "Ideas",
  "labels": [],
  "reactions": [
    {
      "type": "heart",
      "count": 2
    }
  ],
  "commentCount": 2,
  "comments": [
    {
      "url": "https://github.com/nodejs/nodejs.org/discussions/7145#discussioncomment-11328103",
      "author": {
        "login": "ovflowd",
        "profileUrl": "https://github.com/ovflowd"
      },
      "body": "I'm +1 renaming these. We could call them engine.XXX (for next.XXX) and server-data for (next-data)",
      "bodyHtml": "<p dir=\"auto\">I&apos;m +1 renaming these.</p> <p dir=\"auto\">We could call them <code class=\"notranslate\">engine.XXX</code> (for <code class=\"notranslate\">next.XXX</code>) and <code class=\"notranslate\">server-data</code> for (<code class=\"notranslate\">next-data</code>)</p>",
      "createdAt": "2024-11-20T19:50:48Z",
      "replies": [
        {
          "url": "https://github.com/nodejs/nodejs.org/discussions/7145#discussioncomment-11328666",
          "author": {
            "login": "AugustinMauroy",
            "profileUrl": "https://github.com/AugustinMauroy"
          },
          "body": "What's done quite a bit too, but that's up to the devs, is to put all that in a lib directory, for example, which is what next.js offers for setting up prisma.",
          "bodyHtml": "<p dir=\"auto\">What&apos;s done quite a bit too, but that&apos;s up to the devs, is to put all that in a <code class=\"notranslate\">lib</code> directory, for example, which is what next.js offers for setting up prisma.</p>",
          "createdAt": "2024-11-20T21:03:24Z",
          "replies": []
        }
      ]
    }
  ]
}
```

#### 💳 Pricing

**Pay per saved discussion**

This Actor uses pay-per-event pricing. The primary event is charged once for each public discussion saved to the dataset. The active per-discussion price is shown in Apify Console. Use `maxItems` and the discovery filters to control how many discussions you ask for.

#### 🔌 Integrations

**Use the dataset in your workflow**

https://www.youtube.com/watch?v=bNACk1\_S\_6w\&list=PLObrtcm1Kw6MUrlLNDbK9QRg8VDJg0gOW\&index=4

Open the `dataset` output after a run, or use the Apify API to read the structured discussion rows in your workflow.

#### ❓ FAQ

##### Can I use an organization, repository, or direct discussion URL?

Yes. Choose the matching target and add one or more public GitHub URLs. Organization and repository targets use discussion index URLs. The discussion target uses individual discussion URLs.

##### Does this collect GitHub issues or GitLab discussions?

No. This Actor collects public GitHub Discussions. It does not collect GitHub issues or GitLab discussions.

##### Can I mix target types in one run?

No. Choose one target for each run. URLs in the other target sections are ignored.

##### Do I need a GitHub login or token?

No. The Actor is for public GitHub discussion pages that can be viewed without a customer login.

##### Which filters work with index URLs?

`category`, `latestActivityAfter`, and `sortOrder` apply to organization and repository discovery. A category keeps one category, a date keeps discussions with activity on or after that date, and order chooses latest activity, top, newest, or oldest.

##### What does leaving maxItems empty do?

It returns all available results until the source is exhausted. Use a number when you want to stop after a set number of discussions.

##### Are comments and replies included?

The output includes comments and nested reply fields. Comments, replies, and their public author data appear when GitHub renders them on the discussion page.

##### What if a discussion has no comments or reactions?

The row still includes the discussion fields, and the related arrays can be empty. Optional public fields such as `category` or `isAnswered` appear when GitHub exposes them.

##### How do I connect rows from different runs?

Use the stable `discussionId` or canonical `discussionUrl` as the discussion key. Keep `sourceUrl` when you also need to know which submitted URL led to the row.

### 📝 Changelog

**0.0: Initial release**

### 🆘 Support

For issues, questions, or feature requests, [file a ticket](https://console.apify.com/actors/maximedupre~github-discussions/issues) and I'll fix or implement it in less than 24h 🫡

### 🔗 Related Actors

- [GitHub Release](https://apify.com/maximedupre/github-releases). Review release notes, tags, assets, and change signals for the same repositories.
- [GitHub Security Advisories Scraper](https://apify.com/maximedupre/github-security-advisories-scraper). Export advisory records and affected packages alongside community feedback.
- [Reddit Comments Search Scraper](https://apify.com/maximedupre/reddit-comments-search-scraper). Search public Reddit comments for related questions and product feedback.
- [Claude Code Help Channel Aggregator](https://apify.com/ianymu/claude-code-help-channel-aggregator). Group GitHub Discussions and Reddit questions into recurring support themes.
- [Topic Radar](https://apify.com/mick-johnson/topic-radar). Track related topics across GitHub and other public developer sources.

**Made with ❤️ by Maxime Dupré**

# Actor input Schema

## `target` (type: `string`):

Choose the public GitHub discussion source for this run.

## `organizationUrls` (type: `array`):

Add one or more public GitHub organization discussion index URLs. Use this field only when Target is Organization discussions. URLs in other Target sections are ignored.

## `repositoryUrls` (type: `array`):

Add one or more public GitHub repository discussion index URLs. Use this field only when Target is Repository discussions. URLs in other Target sections are ignored.

## `discussionUrls` (type: `array`):

Add one or more public GitHub discussion URLs. Use this field only when Target is Individual discussion URLs. URLs in other Target sections are ignored.

## `category` (type: `string`):

Enter the GitHub Discussions category to keep. It applies to Organization discussions and Repository discussions. Leave it blank to include all categories.

## `latestActivityAfter` (type: `string`):

Keep discussions whose latest activity is on or after this UTC date. It applies to Organization discussions and Repository discussions. Leave it blank to include all dates.

## `sortOrder` (type: `string`):

Choose the order for Organization discussions and Repository discussions.

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

Stop after this many discussions. Leave it blank to return all available results until the source is exhausted.

## Actor input object example

```json
{
  "target": "discussion",
  "discussionUrls": [
    {
      "url": "https://github.com/orgs/community/discussions/184710"
    }
  ],
  "sortOrder": "latest",
  "maxItems": 20
}
```

# Actor output Schema

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

Dataset with one row for each public GitHub discussion.

# 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 = {
    "target": "discussion",
    "discussionUrls": [
        {
            "url": "https://github.com/orgs/community/discussions/184710"
        }
    ],
    "sortOrder": "latest",
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("maximedupre/github-discussions").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 = {
    "target": "discussion",
    "discussionUrls": [{ "url": "https://github.com/orgs/community/discussions/184710" }],
    "sortOrder": "latest",
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("maximedupre/github-discussions").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 '{
  "target": "discussion",
  "discussionUrls": [
    {
      "url": "https://github.com/orgs/community/discussions/184710"
    }
  ],
  "sortOrder": "latest",
  "maxItems": 20
}' |
apify call maximedupre/github-discussions --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,maximedupre/github-discussions"
        }
    }
}

```

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/kL0MBXbx3ag0URiaT/builds/5O2hXzrTezxlli7Kp/openapi.json
