Reddit Commands

Overview

The netapi reddit commands provide CLI access to Reddit’s API. All commands support -f json for jq piping. Authenticated requests use oauth.reddit.com; public endpoints append .json to standard Reddit URLs.

Prerequisites

Reddit API access requires an OAuth2 "script" application.

Create a Script App

  1. Go to www.reddit.com/prefs/apps

  2. Click Create another app…​

  3. Select script as the application type

  4. Set the redirect URI to localhost:8080 (unused for script apps, but required)

  5. Note the client ID (under the app name) and client secret

Environment Variables

# Load credentials from dsec
dsource d000 dev/app

# Credentials available as environment variables:
#   REDDIT_CLIENT_ID     - OAuth2 client ID
#   REDDIT_CLIENT_SECRET - OAuth2 client secret
#   REDDIT_USER_AGENT    - User-Agent string (required by Reddit)
#   REDDIT_USERNAME      - (optional) for user-context endpoints
#   REDDIT_PASSWORD      - (optional) for user-context endpoints

Add these to dsec edit d000 dev/app:

REDDIT_CLIENT_ID=your-client-id
REDDIT_CLIENT_SECRET=your-client-secret
REDDIT_USER_AGENT=netapi/0.2.0

Token Acquisition

netapi handles token refresh automatically. The underlying flow:

# Client credentials grant (app-only context)
curl -s -X POST https://www.reddit.com/api/v1/access_token \
  -u "${REDDIT_CLIENT_ID}:${REDDIT_CLIENT_SECRET}" \
  -d "grant_type=client_credentials" \
  -A "${REDDIT_USER_AGENT}"

# Password grant (user context — needed for saved, identity)
curl -s -X POST https://www.reddit.com/api/v1/access_token \
  -u "${REDDIT_CLIENT_ID}:${REDDIT_CLIENT_SECRET}" \
  -d "grant_type=password&username=${REDDIT_USERNAME}&password=${REDDIT_PASSWORD}" \
  -A "${REDDIT_USER_AGENT}"

Rate Limits

Context Limit

Authenticated (OAuth2)

100 requests/minute

Unauthenticated (.json suffix)

10 requests/minute

Free tier with no request caps beyond rate limiting. The User-Agent header is mandatory — Reddit blocks requests with generic or missing user agents.

Commands (15 total)

Command Description

hot

Hot posts from a subreddit

new

New posts from a subreddit

top

Top posts (with time filter)

rising

Rising posts from a subreddit

post

Full post details by ID

comments

Comment tree for a post

search

Search posts across subreddits

user

User profile information

user-posts

A user’s submissions

user-comments

A user’s comments

subreddit

Subreddit metadata and rules

multireddit

Multireddit listing

saved

Saved posts (requires user auth)

api

Raw API endpoint access

JSON Output

All commands support -f json for machine-readable output:

netapi reddit hot --subreddit programming -f json
netapi reddit top --subreddit networking --time week -f json
netapi reddit search "cisco ise" --subreddit netsec -f json
netapi reddit user spez -f json

jq Patterns

Exploring Structure

# See all keys in first post object
netapi reddit hot --subreddit programming -f json | jq '.[0] | keys'

# Keys with types
netapi reddit hot --subreddit programming -f json | jq '.[0] | to_entries | .[] | "\(.key): \(.value | type)"'

# Full first object
netapi reddit hot --subreddit programming -f json | jq '.[0]'

Feed Listings (hot, new, top, rising)

# Hot posts — title, score, author
netapi reddit hot --subreddit programming --limit 25 -f json | jq -r '.[] | "\(.score)\t\(.author)\t\(.title)"'

# New posts — compact summary
netapi reddit new --subreddit netsec --limit 20 -f json | jq '.[] | {title, score, author, num_comments, url}'

# Top posts this week
netapi reddit top --subreddit networking --time week --limit 20 -f json | jq -r '.[] | "[\(.score)] \(.title)"'

# Rising — with self-text preview (first 120 chars)
netapi reddit rising --subreddit python --limit 10 -f json | jq '.[] | {title, score, preview: (.selftext[:120])}'

# Filter to link posts only (not self-posts)
netapi reddit hot --subreddit programming -f json | jq '.[] | select(.is_self == false) | {title, url, score}'

# Filter out NSFW content
netapi reddit hot --subreddit all --limit 50 -f json | jq '.[] | select(.over_18 == false) | {title, subreddit, score}'

Post Details

# Full post details
netapi reddit post abc123 -f json | jq '{
  title,
  author,
  score,
  upvote_ratio,
  url,
  selftext,
  link_flair_text,
  total_awards_received,
  created_utc: (.created_utc | todate),
  num_comments
}'

# Link URL vs self-text
netapi reddit post abc123 -f json | jq 'if .is_self then .selftext else .url end'

# Cross-post detection — extract original source
netapi reddit post abc123 -f json | jq 'if .crosspost_parent_list then
  .crosspost_parent_list[0] | {original_sub: .subreddit, original_author: .author, original_title: .title, original_url: .url}
else "Not a cross-post" end'

Comments

# Top-level comments — author and body
netapi reddit comments abc123 -f json | jq '.[] | select(.depth == 0) | {author, score, body}'

# Flatten comment tree — all comments with depth
netapi reddit comments abc123 -f json | jq -r '.[] | "\("  " * .depth)\(.author) (\(.score)): \(.body | split("\n")[0])"'

# Top comments by score
netapi reddit comments abc123 -f json | jq 'sort_by(-.score) | .[0:10] | .[] | {author, score, body: (.body[:200])}'

# Comment count by author
netapi reddit comments abc123 -f json | jq '[.[].author] | group_by(.) | map({author: .[0], count: length}) | sort_by(-.count)'
# Search within a subreddit
netapi reddit search "query" --subreddit netsec --sort relevance -f json | jq '.[] | {title, score, num_comments, url}'

# Search with time filter
netapi reddit search "zero day" --subreddit netsec --time month -f json | jq -r '.[] | "[\(.score)] \(.title)"'

# Filter results by score threshold
netapi reddit search "ansible" --subreddit networking -f json | jq '.[] | select(.score > 50) | {title, score, url}'

# Filter by minimum comments (find discussions, not announcements)
netapi reddit search "cisco ise" --subreddit networking -f json | jq '.[] | select(.num_comments > 10) | {title, num_comments, url}'

# Cross-subreddit search
netapi reddit search "network automation" --subreddit all --sort top -f json | jq '.[] | {title, subreddit, score}'

User Profiles

# User profile summary
netapi reddit user spez -f json | jq '{
  name,
  link_karma,
  comment_karma,
  total_karma,
  created_utc: (.created_utc | todate),
  is_gold,
  verified
}'

# Account age in days
netapi reddit user spez -f json | jq '((now - .created_utc) / 86400 | floor) as $days | "\(.name): \($days) days old"'

# User submissions
netapi reddit user-posts spez -f json | jq '.[] | {title, subreddit, score, num_comments}'

# User comments with context
netapi reddit user-comments spez -f json | jq '.[] | {
  subreddit,
  score,
  body: (.body[:150]),
  link_title
}'

# Karma breakdown by subreddit (from posts)
netapi reddit user-posts someuser -f json | jq '[.[] | {subreddit, score}] | group_by(.subreddit) | map({sub: .[0].subreddit, total_score: (map(.score) | add)}) | sort_by(-.total_score)'

Subreddit Metadata

# Subreddit info
netapi reddit subreddit networking -f json | jq '{
  display_name,
  title,
  subscribers,
  active_user_count,
  description: (.public_description[:200]),
  created_utc: (.created_utc | todate),
  over18
}'

# Subscriber count
netapi reddit subreddit netsec -f json | jq '"\(.display_name): \(.subscribers) subscribers"'

URL and Media Extraction

# Extract all link URLs from a subreddit (no self-posts)
netapi reddit hot --subreddit programming --limit 100 -f json | jq -r '.[] | select(.is_self == false) | .url'

# Media URLs only (i.redd.it, v.redd.it, imgur)
netapi reddit hot --subreddit networking --limit 100 -f json | jq -r '.[] | select(.url | test("i\\.redd\\.it|v\\.redd\\.it|imgur\\.com")) | .url'

# Video posts (v.redd.it hosted video)
netapi reddit hot --subreddit all --limit 100 -f json | jq '.[] | select(.is_video == true) | {title, url: .media.reddit_video.fallback_url}'

Discussion-Heavy Posts

# Sort by comment-to-score ratio (high ratio = discussion-heavy)
netapi reddit hot --subreddit networking --limit 50 -f json | jq '
  [.[] | select(.score > 5)] |
  map(. + {ratio: (.num_comments / .score)}) |
  sort_by(-.ratio) |
  .[0:10] |
  .[] | {title, score, num_comments, ratio: (.ratio * 100 | floor / 100)}'

Raw API Access

# Any GET endpoint
netapi reddit api /r/networking/about | jq '.'

# Subreddit rules
netapi reddit api /r/netsec/about/rules | jq '.rules[] | {short_name, description}'

# Subreddit moderators
netapi reddit api /r/networking/about/moderators | jq '.data.children[] | .name'

# Trending subreddits
netapi reddit api /api/trending_subreddits | jq '.'

# Specific user trophies
netapi reddit api /api/v1/user/spez/trophies | jq '.data.trophies[] | .data.name'

Environment Variables

Variable Description

REDDIT_CLIENT_ID

OAuth2 client ID from reddit.com/prefs/apps (required)

REDDIT_CLIENT_SECRET

OAuth2 client secret (required)

REDDIT_USER_AGENT

Custom User-Agent string (required — Reddit blocks generic agents)

REDDIT_USERNAME

Reddit username (optional — needed for user-context endpoints)

REDDIT_PASSWORD

Reddit password (optional — needed for user-context endpoints)

Useful jq Recipes

Daily Security Digest

netapi reddit top --subreddit netsec --time day --limit 25 -f json | jq -r '
  "# netsec digest — \(now | todate | split("T")[0])\n",
  (.[] | "- [\(.title)](\(.url)) (\(.score) pts, \(.num_comments) comments)")
'

Find Discussions About a Topic

netapi reddit search "cisco ise" --subreddit networking -f json | jq '.[] | {title, score, num_comments, url}'

Export Subreddit Digest to Markdown

netapi reddit top --subreddit networking --time week --limit 20 -f json | jq -r '
  "# r/networking — Top This Week\n",
  (.[] | "## \(.title)\n- Score: \(.score) | Comments: \(.num_comments)\n- Author: u/\(.author)\n- Link: \(.url)\n")
'
netapi reddit hot --subreddit programming --limit 100 -f json | jq -r '.[] | select(.is_self == false) | .url' | sort -u

Export to CSV

netapi reddit top --subreddit netsec --time month --limit 50 -f json | jq -r '.[] | [.title, .author, .score, .num_comments, .url] | @csv'

Count Posts by Author

netapi reddit hot --subreddit networking --limit 100 -f json | jq '[.[].author] | group_by(.) | map({author: .[0], count: length}) | sort_by(-.count) | .[0:10]'

Filter and Transform

# High-engagement posts: score > 100 and comments > 50
netapi reddit top --subreddit all --time day --limit 100 -f json | jq '.[] | select(.score > 100 and .num_comments > 50) | {
  title,
  subreddit,
  score,
  num_comments,
  url
}'

Multireddit Security Feed

# Combine multiple subreddits into one digest
for sub in netsec networking sysadmin; do
  netapi reddit top --subreddit "$sub" --time day --limit 5 -f json | jq --arg s "$sub" '.[] | . + {source: $s}'
done | jq -s 'sort_by(-.score) | .[] | "[\(.source)] [\(.score)] \(.title)"' -r

curl Equivalents (Works Now)

These raw curl + jq patterns work today without the netapi CLI.

Setup (dsec)

The public JSON API needs no auth. For OAuth2 (100 req/min), add credentials to dsec:

  1. Create a "script" app at www.reddit.com/prefs/apps (redirect URI: localhost)

  2. Add to dsec:

    dsec edit d000 dev/app

    Add these lines:

    REDDIT_CLIENT_ID=your-client-id
    REDDIT_CLIENT_SECRET=your-client-secret
    REDDIT_USER_AGENT=netapi/0.2.0
  3. Load credentials:

    dsource d000 dev/app

Public Access (No Auth, 10 req/min)

Reddit’s public JSON API works by appending .json to any Reddit URL:

# Hot posts from a subreddit
curl -s -A "netapi/0.2.0" "https://www.reddit.com/r/programming/hot.json?limit=10" \
  | jq '.data.children[].data | {title, score, num_comments, url}'

# Top posts this week
curl -s -A "netapi/0.2.0" "https://www.reddit.com/r/netsec/top.json?t=week&limit=10" \
  | jq '.data.children[].data | {title, score, author, url}'

# New posts
curl -s -A "netapi/0.2.0" "https://www.reddit.com/r/networking/new.json?limit=10" \
  | jq '.data.children[].data | {title, score, author, created_utc}'

# Search within a subreddit
curl -s -A "netapi/0.2.0" "https://www.reddit.com/r/networking/search.json?q=cisco+ise&restrict_sr=on&sort=relevance&t=all&limit=10" \
  | jq '.data.children[].data | {title, score, num_comments, url}'

# Search all of Reddit
curl -s -A "netapi/0.2.0" "https://www.reddit.com/search.json?q=network+automation&sort=top&t=month&limit=10" \
  | jq '.data.children[].data | {title, subreddit, score, url}'
Always set a User-Agent header (-A). Reddit blocks requests without one.

Post Details and Comments

# Full post + comments (returns array: [post, comments])
curl -s -A "netapi/0.2.0" "https://www.reddit.com/r/netsec/comments/POST_ID.json" \
  | jq '.[0].data.children[0].data | {title, selftext, score, author, num_comments}'

# Top-level comments only
curl -s -A "netapi/0.2.0" "https://www.reddit.com/r/netsec/comments/POST_ID.json" \
  | jq '.[1].data.children[].data | select(.author) | {author, body: .body[0:200], score}'

User Profile

# User info
curl -s -A "netapi/0.2.0" "https://www.reddit.com/user/spez/about.json" \
  | jq '.data | {name, link_karma, comment_karma, created_utc: (.created_utc | todate)}'

# User's recent posts
curl -s -A "netapi/0.2.0" "https://www.reddit.com/user/spez/submitted.json?limit=5" \
  | jq '.data.children[].data | {title, subreddit, score}'

Subreddit Info

# Subreddit metadata
curl -s -A "netapi/0.2.0" "https://www.reddit.com/r/netsec/about.json" \
  | jq '.data | {display_name, subscribers, active_user_count, public_description}'

OAuth2 Access (100 req/min)

For higher rate limits, use OAuth2:

# Load credentials from dsec
dsource d000 dev/app

# Get token
REDDIT_TOKEN=$(curl -s -X POST https://www.reddit.com/api/v1/access_token \
  -u "${REDDIT_CLIENT_ID}:${REDDIT_CLIENT_SECRET}" \
  -d "grant_type=client_credentials" \
  -A "netapi/0.2.0" | jq -r '.access_token')

# 4. Use authenticated endpoint (100 req/min)
curl -s -H "Authorization: Bearer ${REDDIT_TOKEN}" -A "netapi/0.2.0" \
  "https://oauth.reddit.com/r/netsec/hot?limit=10" \
  | jq '.data.children[].data | {title, score, url}'

Security Digest (curl)

# Daily netsec digest as markdown
curl -s -A "netapi/0.2.0" "https://www.reddit.com/r/netsec/top.json?t=day&limit=15" \
  | jq -r '.data.children[].data | "- [\(.title)](\(.url)) (\(.score) pts, \(.num_comments) comments)"'

# Multi-subreddit security feed
for sub in netsec blueteamsec cybersecurity; do
  curl -s -A "netapi/0.2.0" "https://www.reddit.com/r/${sub}/top.json?t=day&limit=5" \
    | jq --arg s "$sub" '.data.children[].data | {title, score, url, sub: $s}'
done | jq -rs 'sort_by(-.score) | .[] | "[\(.sub)] \(.score)pts: \(.title)"'

# Extract all link posts (no self-posts)
curl -s -A "netapi/0.2.0" "https://www.reddit.com/r/programming/hot.json?limit=25" \
  | jq -r '.data.children[].data | select(.is_self == false) | .url'