All posts
Workflow

Reddit removal_reasons API: pre-check posts before you submit

By Bazzly Team3 min read

Use Reddit's removal_reasons endpoint and saved responses to pre-check your post against a subreddit's real moderator rejection templates before submit.

Reddit removal_reasons API: pre-check posts before you submit

Every subreddit has two rulebooks. There is the one on the sidebar, which reads like a constitution, and there is the one the mods actually use when they hit remove: a set of pre-written rejection templates called removal reasons. If you have ever had a post disappear with a message that starts "Your post has been removed because...", you have met one.

Those templates are exposed via Reddit's API. You can fetch them, diff your draft against them, and route the ones that do slip through into a clean modmail follow-up. This post walks through the workflow end to end, using PRAW.

What removal_reasons actually is

Removal reasons are per-subreddit, mod-authored strings that get attached to a takedown. They power the "Removed by moderators" comment and, since late 2024, the saved-responses picker in the new mod tools. A community discussion in r/redditdev confirms that saved responses and removal reasons share the same underlying object type, which is why the same list shows up in both surfaces.

The endpoint is /api/v1/{subreddit}/removal_reasons and it returns JSON like this:

{
  "data": {
    "abc123": {
      "id": "abc123",
      "title": "Rule 3: No self-promotion",
      "message": "Posts about your own product require prior mod approval..."
    }
  },
  "order": ["abc123", "def456"]
}

The title is short and searchable. The message is the full text the OP receives. Both are gold when you are trying to figure out what actually gets removed in a sub, because sidebar rules are aspirational and removal reasons are operational.

Pulling removal reasons with PRAW

PRAW 8 exposes this cleanly via SubredditRemovalReasons, documented in the PRAW reference. Auth is standard OAuth with a script app.

import praw

reddit = praw.Reddit(
    client_id="...",
    client_secret="...",
    user_agent="removal-checker by u/yourname",
    username="yourname",
    password="...",
)

def fetch_reasons(sub_name):
    sub = reddit.subreddit(sub_name)
    return [
        {"id": r.id, "title": r.title, "message": r.message}
        for r in sub.mod.removal_reasons
    ]

for r in fetch_reasons("SaaS"):
    print(r["title"])

One catch: you need mod permissions on the subreddit to read its removal reasons via the API. If you are not a mod, you get a 403. This is where a lot of "just scrape it" workflows die, and it is the reason the workflow below has two tracks: mod-track (full templates) and non-mod-track (heuristic match against sidebar rules plus the public "removed by mods" comments you can pull off /new).

For non-mod subs, scrape recent removed-post replies from AutoModerator and the mod team's account. Those messages are literally the same message field, quoted publicly.

The pre-check workflow

Here is the full loop. It runs before submit, not after.

Rendering diagram…

The matching in step D does not need to be clever. A simple TF-IDF or embedding similarity between your draft and each message catches the obvious cases. The interesting ones are the pattern rules: "posts under 200 words", "no link in the body", "account age < 30 days". Those you encode as explicit checks, seeded by reading the actual removal_reasons text once by hand.

A good starter check list, in code:

  • Draft length vs the sub's typical removal-reason threshold
  • Presence of links in body or first comment
  • Account age and karma (see our post on shadowbans and how to tell for the diagnostics)
  • Self-promotion ratio over the last 30 days
  • Post-flair requirement (some subs auto-remove flairless posts)

Wiring saved responses into modmail

This is where the workflow earns its keep. If your post does get removed, you now have the exact reason_id the mods used, either from the modmail notification or by matching the public removal comment. That gives you a much better opener than "why was my post removed?".

A tailored modmail looks like:

Hi mods, my post at [link] was removed under "Rule 3: No self-promotion". I read the rule again and I think the issue was the link in the body rather than the topic itself. Would a rewrite that keeps the topic but strips the link be acceptable, or is the topic itself off-limits here? Happy to follow whatever process you prefer.

The response rate on messages like this is dramatically higher than generic appeals because you are quoting the mod's own template back at them. Send it via PRAW's Modmail interface, one message per removed post, not a batch.

sub.modmail.create(
    subject=f"Question about removed post {submission.id}",
    body=message_text,
    recipient=None,  # goes to the mod team
)

Keep the volume low. One modmail per removal, per subreddit, per week is a ceiling not a floor. Mods talk to each other, and being the person who mass-messages every sub is a fast way to end up on a shared blocklist.

Feeding it back into your ops

Every removal, matched to a reason_id, is a labeled training example for your next draft in that sub. After a month you have a per-sub cheat sheet of what actually gets pulled versus what the sidebar merely warns about. That is more useful than any "best practices" post.

If running this scan across a dozen target subs by hand is turning into its own job, Bazzly does the continuous monitoring, matching, and follow-up drafting so you can focus on the reply itself. For the alerting layer that surfaces the threads worth submitting into in the first place, see the companion writeup on Reddit and Slack alerts for buyer intent and the PRAW 8 production setup.

The underlying idea is boring and it works: read the actual rejection templates a subreddit uses, check your draft against them before submit, and when something does get removed, quote the template back at the mods in a real message. Most posts that die on Reddit die from things the mods have already written down.

Related reading