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
-
Click Create another app…
-
Select script as the application type
-
Set the redirect URI to
localhost:8080(unused for script apps, but required) -
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}"
Commands (15 total)
| Command | Description |
|---|---|
|
Hot posts from a subreddit |
|
New posts from a subreddit |
|
Top posts (with time filter) |
|
Rising posts from a subreddit |
|
Full post details by ID |
|
Comment tree for a post |
|
Search posts across subreddits |
|
User profile information |
|
A user’s submissions |
|
A user’s comments |
|
Subreddit metadata and rules |
|
Multireddit listing |
|
Saved posts (requires user auth) |
|
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
# 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 |
|---|---|
|
OAuth2 client ID from reddit.com/prefs/apps (required) |
|
OAuth2 client secret (required) |
|
Custom User-Agent string (required — Reddit blocks generic agents) |
|
Reddit username (optional — needed for user-context endpoints) |
|
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")
'
Extract All External Links
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:
-
Create a "script" app at www.reddit.com/prefs/apps (redirect URI:
localhost) -
Add to dsec:
dsec edit d000 dev/appAdd these lines:
REDDIT_CLIENT_ID=your-client-id REDDIT_CLIENT_SECRET=your-client-secret REDDIT_USER_AGENT=netapi/0.2.0
-
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'