# API: Getting all posts in a topic

**URL:** https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018
**Category:** Development
**Created:** [March 14, 2016, 2:30pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018 "2016-03-14T14:30:32Z")
**Posts on this page:** 20
**Page:** 1

<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 14, 2016, 2:30pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/1 "2016-03-14T14:30:32Z")

</div>

I’m working on a script that will evaluate participation in a discussion and produce a number based on how many messages they wrote, likes, and replies and such that will become students’ grade for “participating” in a discussion.

`/t/blah/TOPIC_ID.json` returns only 20 posts. Is there a way to get all of them, or will I need to do a request for all of them?

I looked a little at what gets passed to poll, but it wasn’t immediately apparent that I could somehow pass it something like a range or number of posts that I wanted.

---

<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 14, 2016, 2:47pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/2 "2016-03-14T14:47:36Z")

</div>

Maybe the easiest way is to get the data I want from the [data explorer](https://meta.discourse.org/t/32566?silent=true) plugin.

Now I’m thinking that it would be cool to write a plugin that showed people’s scores next to their profile pic in their posts in that topic.

---

<div class="post-metadata">

### Author: ![blake](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/blake/32/157322_2.png) [@blake](https://meta.discourse.org/u/blake)
#### Post date: [March 14, 2016, 3:32pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/3 "2016-03-14T15:32:59Z")

</div>

When you GET `/t/blah/TOPIC_ID.json` the output will also contain a `stream` array that has all the id’s for the topic.

You then can call: `/t/blah/TOPIC_ID/posts.json?post_ids[]` and pass in all the ids from the stream array.

---

<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 14, 2016, 3:34pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/4 "2016-03-14T15:34:22Z")

</div>

Thanks! And the problem with [data explorer](https://meta.discourse.org/t/32566?silent=true) is that there is no way (that I can see quickly) to pass in the topic\_id that I want.

---

<div class="post-metadata">

### Author: ![blake](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/blake/32/157322_2.png) [@blake](https://meta.discourse.org/u/blake)
#### Post date: [March 14, 2016, 3:43pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/5 "2016-03-14T15:43:30Z")

</div>

Also its probably a good idea to still break up fetching all the posts into multiple requests rather than 1 big one. So if you have a topic with 100 posts. You should break it up into 5 smaller requests fetching 20 posts at a time.

---

<div class="post-metadata">

### Author: ![jandres](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jandres/32/130933_2.png) [@jandres](https://meta.discourse.org/u/jandres)
#### Post date: [September 19, 2018, 4:34pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/6 "2018-09-19T16:34:56Z")

</div>

Hi @blake @pfaffman

I don’t know why i’m getting a response from `/t/blah/TOPIC_ID.json` with only the last 10 posts.  
I see the `chunk_size` parameter (in response) set to 10, but i don’t know why is like that or where can i change this value.

Thank you very much

---

<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: [September 19, 2018, 4:41pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/7 "2018-09-19T16:41:32Z")

</div>

I once [wrote code](https://github.com/pfaffman/discourse-downloader) that downloaded all of the posts in a topic.

I don’t know if the code still works, but it looks like how many posts you get is harder to predict than you might think. You pass the first post-id to control what posts you get.

See [https://github.com/pfaffman/discourse-downloader/blob/master/discourse-downloader#L69](https://github.com/pfaffman/discourse-downloader/blob/master/discourse-downloader#L69)

---

<div class="post-metadata">

### Author: ![blake](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/blake/32/157322_2.png) [@blake](https://meta.discourse.org/u/blake)
#### Post date: [September 19, 2018, 5:28pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/8 "2018-09-19T17:28:12Z")

</div>

The best way to download all the posts to a topic via the api is to mimic what Discourse is doing in the web browser so please checkout [Reverse engineer the Discourse API](https://meta.discourse.org/t/how-to-reverse-engineer-the-discourse-api/20576) for details. Basically go the the topic in the browser open up your dev tools and look at the xhr requests as you scroll through the topic.

Here are the steps to download all the posts in the topic via the api:

1. Hit `/t/-/{id}.json`. This will contain a ‘posts\_stream’ hash that contains a ‘posts’ array and a ‘stream’ array. The ‘posts’ array will give you the first 20 posts.

2. Now you need to loop through the ‘stream’ array which gives you all of the post ids in the topic. Remove the first 20 post ids from the stream (otherwise you are re-downloading them for no reason).

3. In chunks of 20 pass in all the post\_ids to `/t/{id}/posts.json` like this:  
`http://localhost:3000/t/8/posts.json?post_ids[]=46&post_ids[]=47&post_ids[]=48&post_ids[]=49&post_ids[]=50&post_ids[]=51&post_ids[]=52&post_ids[]=53&post_ids[]=54&post_ids[]=55&post_ids[]=56&post_ids[]=57&post_ids[]=58&post_ids[]=59&post_ids[]=60&post_ids[]=61&post_ids[]=62&post_ids[]=63&post_ids[]=64&post_ids[]=65`

---

<div class="post-metadata">

### Author: ![jandres](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jandres/32/130933_2.png) [@jandres](https://meta.discourse.org/u/jandres)
#### Post date: [September 19, 2018, 5:45pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/9 "2018-09-19T17:45:48Z")

</div>

Thanks @blake and @pfaffman for your soon response.

I agree with @blake steps for get all posts in a topic.

According with step 1  
I just wanted to know if there are any parameter (maybe in the header of request) to set the `chunk_size` in `/t/blah/TOPIC_ID.json` request, because if i made a request from POSTMAN i get the first 20 posts as described previosly, but if i made the request using my web app using angular, i just get the first 10.

So i think there are something in the request that change the response from discourse server.

I use this request because from her i can get the post stream and the first 20 posts in one request. So i take her like my first request base to get all post in a topic.

I know this question is not critical, i can figure out to get my solution using multiple request. I am just curious to know why

---

<div class="post-metadata">

### Author: ![blake](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/blake/32/157322_2.png) [@blake](https://meta.discourse.org/u/blake)
#### Post date: [September 19, 2018, 6:52pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/10 "2018-09-19T18:52:05Z")

</div>

> [@jandres](#):
>
> but if i made the request using my web app using angular, i just get the first 10.

For some reason your angular app is triggering `slow_chunk_size`.

> <https://github.com/discourse/discourse/blob/main/lib/topic_view.rb#L12-L14>

from

> <https://github.com/discourse/discourse/blob/main/app/controllers/application_controller.rb#L104-L106>

So that might be something to look into.

> [@jandres](#):
>
> I just wanted to know if there are any parameter (maybe in the header of request) to set the `chunk_size` in `/t/blah/TOPIC_ID.json` request

There is not a `chunk_size` parameter you can set, but if you pass in `print=true` like `/t/-/{id}.json?print=true` it will set the chunk size to 1000.

---

<div class="post-metadata">

### Author: ![jandres](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jandres/32/130933_2.png) [@jandres](https://meta.discourse.org/u/jandres)
#### Post date: [September 19, 2018, 6:54pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/11 "2018-09-19T18:54:48Z")

</div>

Thank you so much 👌

That is the trick. I am running my app (actually is an ionic v3 app) from chrome dev tools on android device and i alwasy get the first 10. When i swtich to browser mode, i get the 20.

---

<div class="post-metadata">

### Author: ![benraay](https://avatars.discourse-cdn.com/v4/letter/b/4491bb/32.png) [@benraay](https://meta.discourse.org/u/benraay)
#### Post date: [May 31, 2019, 3:20pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/12 "2019-05-31T15:20:41Z")

</div>

> [@blake](#):
>
> There is not a `chunk_size` parameter you can set, but if you pass in `print=true` like `/t/-/{id}.json?print=true` it will set the chunk size to 1000.

this saved my life !

---

<div class="post-metadata">

### Author: ![lisbethw1130](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/lisbethw1130/32/129613_2.png) [@lisbethw1130](https://meta.discourse.org/u/lisbethw1130)
#### Post date: [August 2, 2019, 3:59am UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/13 "2019-08-02T03:59:03Z")

</div>

print parameter just saved me 🤩

---

<div class="post-metadata">

### Author: ![bjornekstrom](https://avatars.discourse-cdn.com/v4/letter/b/13edae/32.png) [@bjornekstrom](https://meta.discourse.org/u/bjornekstrom)
#### Post date: [July 20, 2020, 3:57pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/14 "2020-07-20T15:57:59Z")

</div>

The `?print=true` command is great, indeed! It seems however that there is a rate limit for `?print=true` commands of five calls per hour. Is there a way to make more API calls per hour?

---

<div class="post-metadata">

### Author: ![fifi\_joon](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/fifi_joon/32/257139_2.png) [@fifi\_joon](https://meta.discourse.org/u/fifi_joon)
#### Post date: [April 16, 2022, 12:36pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/15 "2022-04-16T12:36:58Z")

</div>

This solution does not work on “mega topics” Do you have any solution for those?

---

<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: [April 16, 2022, 7:54pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/16 "2022-04-16T19:54:35Z")

</div>

If not, you’ll need to make multiple requests to retrieve the rest. How many does it return?

---

<div class="post-metadata">

### Author: ![polv](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/polv/32/257689_2.png) [@polv](https://meta.discourse.org/u/polv)
#### Post date: [April 21, 2022, 7:27pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/17 "2022-04-21T19:27:32Z")

</div>

While `?print=true` works (as well as `&page=2`), there appears to be more Rate limit than without `print=true`. I wonder how many requests I can do, and considered safe, not to hit status 422.

I am trying to read around 9000 posts, so for 20 posts at once, it will either be very slow, or get rate-limited…

---

<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: [April 21, 2022, 9:08pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/18 "2022-04-21T21:08:32Z")

</div>

I recommend that you write the code expecting to get rate limited.

---

<div class="post-metadata">

### Author: ![polv](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/polv/32/257689_2.png) [@polv](https://meta.discourse.org/u/polv)
#### Post date: [April 22, 2022, 1:02am UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/19 "2022-04-22T01:02:01Z")

</div>

It’s in my UserScript. Language highlighting for `typescript` doesn’t work; and `js` works strangely. Have to be `javascript`. Both `ts` and `typescript` work in StackOverflow, however.

```javascript
interface IPost {
  id: number
  username: string
  post_number: number
  cooked: string
}

interface ITopicResponse {
  actions_summary: {}[]
  archetype: string
  fancy_title: string
  title: string
  post_stream: {
    posts: IPost[]
    stream: number[]
  }
  posts_count: number
  reply_count: number
}

export async function jsonFetch<T>(url: string): Promise<T | null> {
  const r = await fetch(url)
  if (r.ok) {
    const json = await r.json()
    if (!json.errors) {
      return json
    }
  }

  logger('error', r)
  return null
}

export async function fetchAll(urlBase: string) {
  const r0 = await jsonFetch<ITopicResponse>(urlBase + '.json?print=true')
  if (!r0) return []

  const posts: IPost[] = r0.post_stream.posts
  let page = 2
  while (posts.length < r0.posts_count) {
    const r = await jsonFetch<ITopicResponse>(
      urlBase + '.json?print=true&page=' + page++
    )
    if (!r || !r.post_stream.posts.length) {
      break
    }
    posts.push(...r.post_stream.posts)
    await new Promise((resolve) => setTimeout(resolve, 1000))
  }

  return posts
}

fetchAll('https://community.wanikani.com/t/16404').then(console.log)

```

In a `ts-node` script using Axios,

```plaintext
(node:1102374) UnhandledPromiseRejectionWarning: Error: Request failed with status code 422

```

If I wait long enough, like 10 minutes, it will fail at page 2; but if I just repeat now, I can’t load any URL.

And without **print** works OK.

* * *

Actually, I got it to work by avoiding `print=true`.

```javascript
export async function fetchAll(urlBase: string) {
  const r0 = await jsonFetch<ITopicResponse>(urlBase + '.json');
  if (!r0) return [];

  const stream = r0.post_stream.stream || [];
  const chunks: number[][] = [];
  while (stream.length) {
    chunks.push(stream.splice(0, 300));
  }

  const posts: IPost[] = [];
  let isContinue = true;
  while (chunks.length && isContinue) {
    const rs = await Promise.all(
      chunks
        .splice(0, 10)
        .map((ids) =>
          jsonFetch<ITopicPostResponse>(
            urlBase +
              '/posts.json?' +
              ids.map((id) => `post_ids[]=${id}`).join('&'),
          ),
        ),
    ).then((rs) =>
      rs.map((r) => {
        if (!r) {
          isContinue = false;
          return [];
        }
        return r.post_stream.posts;
      }),
    );

    rs.map((r) => {
      posts.push(...r);
    });

    if (chunks.length) {
      await new Promise((r) => setTimeout(r, 1000));
    }
  }
  posts.push(...r0.post_stream.posts);

  if (!isContinue) {
    logger(
      'error',
      `Total posts: ${r0.posts_count} != real count: ${posts.length}, due to Rate Limit?`,
    );
  }

  return posts;
}

```

---

<div class="post-metadata">

### Author: ![Daniil\_Bazhenov](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/daniil_bazhenov/32/201247_2.png) [@Daniil\_Bazhenov](https://meta.discourse.org/u/Daniil_Bazhenov)
#### Post date: [January 11, 2023, 12:36pm UTC](https://meta.discourse.org/t/api-getting-all-posts-in-a-topic/41018/20 "2023-01-11T12:36:39Z")

</div>

I encountered a problem that `'print' => true` does not work, but `'print' => 'true'` does.  
PHP Guzzle.  
Maybe you should add the `print = 1` handler too
