# Interact with discourse from Python?

**URL:** https://meta.discourse.org/t/interact-with-discourse-from-python/87543
**Category:** Development
**Created:** [May 15, 2018, 4:34pm UTC](https://meta.discourse.org/t/interact-with-discourse-from-python/87543 "2018-05-15T16:34:39Z")
**Posts on this page:** 13
**Page:** 2

<div class="post-metadata">

### Author: ![remidm](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/remidm/32/546042_2.png) [@remidm](https://meta.discourse.org/u/remidm)
#### Post date: [March 4, 2026, 10:02pm UTC](https://meta.discourse.org/t/interact-with-discourse-from-python/87543/21 "2026-03-04T22:02:43Z")

</div>

Thank you so much! Yes I’ll do this! I’m specifically looking for pageviews (logged in users, anonymous users, crawlers) but I can’t find it in the API documentation. Any pointers?

---

<div class="post-metadata">

### Author: ![supermathie](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/supermathie/32/507518_2.png) [@supermathie](https://meta.discourse.org/u/supermathie)
#### Post date: [March 4, 2026, 10:24pm UTC](https://meta.discourse.org/t/interact-with-discourse-from-python/87543/22 "2026-03-04T22:24:04Z")

</div>

Some of the admin-specific calls aren’t in the API docs

I would open the network tab, go to the admin page, view the report with the data you want to retrieve, and then check the network tab to see what the browser loaded.

Which is really a summary of [Reverse engineer the Discourse API](https://meta.discourse.org/t/reverse-engineer-the-discourse-api/20576)

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [March 5, 2026, 1:04am UTC](https://meta.discourse.org/t/interact-with-discourse-from-python/87543/23 "2026-03-05T01:04:27Z")

</div>

What I would do is use the [data explorer](https://meta.discourse.org/t/32566?silent=true) plugin to get whatever you want and then you can pull that down with the API. [Run Data Explorer queries with the Discourse API](https://meta.discourse.org/t/run-data-explorer-queries-with-the-discourse-api/120063)

---

<div class="post-metadata">

### Author: ![supermathie](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/supermathie/32/507518_2.png) [@supermathie](https://meta.discourse.org/u/supermathie)
#### Post date: [March 5, 2026, 1:20am UTC](https://meta.discourse.org/t/interact-with-discourse-from-python/87543/24 "2026-03-05T01:20:05Z")

</div>

Absolutely; if you want data differing from what’s already on offer in the admin panel, DE is the way to go.

It also gives the guarantee those queries won’t return different data after an update, BUT also the underlying structures may change and you may need to maintain the query.

Tradeoffs either way.

---

<div class="post-metadata">

### Author: ![remidm](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/remidm/32/546042_2.png) [@remidm](https://meta.discourse.org/u/remidm)
#### Post date: [March 5, 2026, 1:35pm UTC](https://meta.discourse.org/t/interact-with-discourse-from-python/87543/25 "2026-03-05T13:35:14Z")

</div>

Thank you both! I got away with the “reverse engineer" method + API key! Thank you so much!

---

<div class="post-metadata">

### Author: ![MaukWM](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/maukwm/32/485619_2.png) [@MaukWM](https://meta.discourse.org/u/MaukWM)
#### Post date: [April 19, 2026, 11:38am UTC](https://meta.discourse.org/t/interact-with-discourse-from-python/87543/26 "2026-04-19T11:38:18Z")

</div>

A bit late to this conversation (well, the extension of it :p), but I also wanted to pull data from a discourse forum and didn’t want the hassle of setting up an API key, if you (or anyone) wants a simple wrapper to pull posts from any discourse forum you can check it our [here](https://github.com/elninotech/discourse-reader)

Released on PyPi so easy to install with pip/uv, handles rate limiting for you and is typed with Pydantic (makes for a better DX imo). Usage:

```plaintext
from discourse_reader import DiscourseClient

client = DiscourseClient("https://meta.discourse.org")

# Browse categories
for cat in client.categories():
    print(f"{cat.name}: {cat.topic_count} topics")

# Get a topic with all its posts
topic = client.topics.get(12345)
print(topic.title)
print(topic.opening_post.cooked) # the original post (HTML)
print(topic.accepted_answer) # accepted answer or None
for reply in topic.posts.replies():
    print(reply.username, reply.cooked)

```

Not as extensive as `pydiscourse`but that’s intentional since it works without an API key, it also definitely won’t offer better or faster data than the [data explorer](https://meta.discourse.org/t/32566?silent=true) plugin but I think it’s nice if you just wanna quickly pull a batch of threads of simple site statistics 🙂

---

<div class="post-metadata">

### Author: ![Moin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/moin/32/554653_2.png) [@Moin](https://meta.discourse.org/u/Moin)
#### Post date: [April 19, 2026, 12:04pm UTC](https://meta.discourse.org/t/interact-with-discourse-from-python/87543/27 "2026-04-19T12:04:50Z")

</div>

I get the impression that this approach might violate the [terms of service](https://meta.discourse.org/tos#heading--acceptable-use) for this forum and the default terms of service for Discourse forums.

> You may not automate access to the forum, or monitor the forum, such as with a web crawler, browser plug-in or add-on, or other computer program that is not a web browser. You may crawl the forum to index it for a publicly available search engine, if you run one.

---

<div class="post-metadata">

### Author: ![MaukWM](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/maukwm/32/485619_2.png) [@MaukWM](https://meta.discourse.org/u/MaukWM)
#### Post date: [April 20, 2026, 8:53am UTC](https://meta.discourse.org/t/interact-with-discourse-from-python/87543/28 "2026-04-20T08:53:53Z")

</div>

Hmmm. I don’t think I’m doing anything special beyond simply wrapping what would otherwise be a simple `curl` request to any of the publicly documented API endpoints. However, if the @Discourse team takes any offense to what I created please let me know.

Personally, I don’t _think_ the package itself violates any ToS since the responsibility of respecting a forums’ terms will always be with the dev using the tool. This package only hits public and documented API endpoints, if a developer has malicious intent to scrape or monitor a forum, this would honestly already be a trivial task.

On that note, [pydiscourse](https://github.com/pydiscourse/pydiscourse) offers the same functionality, the only difference being the need for an API key (I don’t know how easy this is to do as a regular user), after which it can similarly be used to violate the ToS of any forum. So if the default rule is to not automate access to the forum, wouldn’t `pydiscourse` and [discourse2](https://github.com/gadicc/discourse2) not also violate ToS? `discourse2` even advertises access to publicly accessible data in their list of features if no API key is provided:

> Works in both server and browser\* environments (\*useful for querying public data without API keys and on relevant origin, e.g. latest topics, etc)

There are probably a lot more packages out there in other languages that already support this type of access.

Some more context: I built this so I can easily pull data from a forum that one of our customers host (but we don’t have direct DB access). It just makes my workflow cleaner and my hope is to assist others that are in the same situation.

---

<div class="post-metadata">

### Author: ![NateDhaliwal](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/natedhaliwal/32/313494_2.png) [@NateDhaliwal](https://meta.discourse.org/u/NateDhaliwal)
#### Post date: [April 20, 2026, 10:22am UTC](https://meta.discourse.org/t/interact-with-discourse-from-python/87543/29 "2026-04-20T10:22:17Z")

</div>

> [@MaukWM](#):
>
> being the need for an API key (I don’t know how easy this is to do as a regular user), after which it can similarly be used to violate the ToS of any forum

The thing is that generating an API key first needs access to the Admin interface (Admin \> Advanced \> API keys), so giving one an API key would be something the Admins _want_ to do; not any regular user can get one.

---

<div class="post-metadata">

### Author: ![MaukWM](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/maukwm/32/485619_2.png) [@MaukWM](https://meta.discourse.org/u/MaukWM)
#### Post date: [April 20, 2026, 10:58am UTC](https://meta.discourse.org/t/interact-with-discourse-from-python/87543/30 "2026-04-20T10:58:30Z")

</div>

Yeah if the only way to get an API key is from the admin interface, then this package could simplify violating a specific forums’ ToS.

Though I still want to discuss some of the other points I made, and hear other peoples’ thoughts on those, namely: Anyone could already trivially scrape/monitor with `curl` or `requests`. Shouldn’t the responsibility lie with that developer to not violate the ToS? Or should it lie within the tools they used itself?

For `discourse2` and similar packages, they are more broadly purposed, but `discourse2` does still advertise the ability work on public endpoints if no API key is provided. Does that enable ToS violation to the same degree?

Also, since discourse is GPLv2, does the creation of a tool like `discourse-reader` inherently violate any terms directly?

Curious to hear other people’s thoughts on these.

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [April 20, 2026, 12:27pm UTC](https://meta.discourse.org/t/interact-with-discourse-from-python/87543/31 "2026-04-20T12:27:34Z")

</div>

The official [discourse\_api](https://github.com/discourse/discourse_api) ruby gem also supports accessing public data without an API key. So I think it’s fine for the tooling to exist. It’s up to users to ensure they’re complying with any forum-specific ToS.

(that’s my personal opinion - not an official legal statement from CDCK 😅)

It’s also worth noting - unauthenticted ‘bot’ requests are subject to much stricter rate limits, and potentially other ‘bot protection’ security layers (e.g. Cloudflare). So if you can, it’s always best to use an API key.

---

<div class="post-metadata">

### Author: ![MaukWM](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/maukwm/32/485619_2.png) [@MaukWM](https://meta.discourse.org/u/MaukWM)
#### Post date: [April 20, 2026, 1:00pm UTC](https://meta.discourse.org/t/interact-with-discourse-from-python/87543/32 "2026-04-20T13:00:14Z")

</div>

Thanks for the response! For the time being, I updated the [README](https://github.com/elninotech/discourse-reader/commit/7b6ff7a4822bd19071a532556a2f567e1c1a1463) in my package with a disclaimer to respect the ToS of whatever site a dev might want to use it against.

I was not aware of this default ToS rule at all when I made this, hopefully anyone who looks to use this package also learns about it in the future as well 🙂

---

<div class="post-metadata">

### Author: ![supermathie](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/supermathie/32/507518_2.png) [@supermathie](https://meta.discourse.org/u/supermathie)
#### Post date: [April 20, 2026, 3:11pm UTC](https://meta.discourse.org/t/interact-with-discourse-from-python/87543/33 "2026-04-20T15:11:15Z")

</div>

> [@david](#):
>
> So I think it’s fine for the tooling to exist. It’s up to users to ensure they’re complying with any forum-specific ToS.

Yeah, this straight up echoes the arguments for VCRs… a while ago. Similarly, lockpicks. There exist legitimate and illegitimate uses of tools and it’s upon the operator to be response.

> [@Moin](#):
>
> You may not automate access to the forum, or monitor the forum, such as with a web crawler, browser plug-in or add-on, or other computer program that is not a web browser.

Again, IANAL and this is not an official statement, but I feel this accurately represents our perspective on this:

There’s a big difference between well-intended exploring with a tool ([e.g.](https://meta.discourse.org/t/interact-with-discourse-from-python/87543/20)) and setting up _automation_.

We’re not going to get grumpy with people using meta with tools like this _especially_ if they’re developing functionality or learning how to interact with the Discourse API. We’ll encourage it, as long as you’re not bulk-scraping data, incurring undue load, or degrading others’ experience.

[Previous page](https://meta.discourse.org/t/interact-with-discourse-from-python/87543.md?page=1)
