Move topics to subcategories automatically based on their tags

Hi guys

I was wondering if it’s possible to automatically move topics to new subcategories that will be created, based on whether they are tagged with a specific tag or any of a defined list of tags?

I didn’t find another thread dealing with this.

Thanks :slight_smile:

There is nothing built into Discourse that would allow topics to be recategorized when they are tagged. It might be possible to use a Tag Event webhook and the Discourse API to accomplish this. You would need to setup a webhook on your Admin / API / Webhooks page to fire when a a topic is tagged with one of the tags that you would like to trigger the action. You could then recategorize the topic (or create a new category for the topic if needed) via the Discourse API.

Thanks, @simon . We will look into this to see if it can work for us.
Using this method, would that automatically categorize the topic into the relevant subcategory based on what tag the topic had been tagged with?

One small correction to my previous post is that the Tag Event webhook is not the correct webhook to use for this. To get details about a topic’s tags, you need to use the Topic Event webhook. That webhook is fired any time a topic is created, updated, or deleted. The relevant part of that webhook’s payload will look something like this:

  "topic": {
    "tags": [
    "id": 10365,
    "title": "Holiday calendar category test",
    "fancy_title": "Holiday calendar category test",
    "posts_count": 18,
    "created_at": "2021-03-11T20:11:12.227Z",
    "views": 10,
    "reply_count": 3,
    "like_count": 0,
    "last_posted_at": "2021-04-06T19:52:02.478Z",
    "visible": true,
    "closed": false,
    "archived": false,
    "archetype": "regular",
    "slug": "holiday-calendar-category-test",
    "category_id": 5,
    "word_count": 187,
    "deleted_at": null,
    "user_id": 1,
    "featured_link": null,
    "pinned_globally": true,
    "pinned_at": "2021-03-15T17:24:44.551Z",
    "pinned_until": "3021-03-15T15:00:00.000Z",
    "unpinned": null,
    "pinned": true,
    "highest_post_number": 18,
    "deleted_by": null,
    "has_deleted": false,
    "bookmarked": false,
    "participant_count": 1,
    "queued_posts_count": 0,
    "thumbnails": null,
    "tags_disable_ads": false,
    "event_starts_at": "2021-03-30 19:10:00",
    "event_ends_at": "2021-03-30 20:10:00",
    "can_vote": false,
    "vote_count": 0,
    "user_voted": false,
    "discourse_zendesk_plugin_zendesk_id": null,
    "discourse_zendesk_plugin_zendesk_url": "",
    "created_by": {
      "id": 1,
      "username": "Simon_Cossar",
      "name": "Simon Cossar ",
      "avatar_template": "/letter_avatar_proxy/v4/letter/s/ed655f/{size}.png"
    "last_poster": {
      "id": 1,
      "username": "Simon_Cossar",
      "name": "Simon Cossar ",
      "avatar_template": "/letter_avatar_proxy/v4/letter/s/ed655f/{size}.png"
    "pending_posts": []

You could then recategorize the topic based on the value of its tags property. To recategorize the topic, you would make a PUT request via the Discourse API to set the topic’s category_id to the ID of the category that you want to move it to. If you wanted to move the topic to a category that does not yet exist on your site, you would need to make two API calls. The first API call would be to create the new category. The second API call would be to move the topic to the new category.

The above method would allow you to automatically recategorize topics based on their tags.

A good approach for figuring out the API calls that are required for this is outlined here: How to reverse engineer the Discourse API. Let us know if you have any trouble figuring out how to structure the API calls.

You will need to figure out a way of saving your Discourse site’s category structure to your main application’s database so that you know which category IDs are available to move the topics to. For example, in the payload that I posted above, I might want to move a topic that’s been tagged with docs to my site’s “documentation” category. To do that, I’d need to be able to find the ID of my “documentation” category on my main application. There are a few ways that this could be accomplished. Our WordPress plugin does this by making periodic requests to the Discourse /site.json route, parses the categories that are returned from that route, and then caches the results for a period of 10 minutes.