Find current, topic-relevant Reddit threads in a known subreddit. Prefer the subreddit’s /new/ listing for all recent posts, or use Reddit’s direct search URL when the caller supplies a query and optional time window. Return canonical permalink URLs and metadata needed to open the thread and read its comments. When requested, collect and label every loaded post in one or more date bands, such as the last 14 days and the preceding 14–21 days.
Use Cases
Use when the caller wants to inspect recent discussions in a subreddit, find a live thread to comment on, read current posts matching a query, or collect posts from a bounded recent date range. If a subreddit is known, navigate directly to it; do not open Reddit’s homepage first. For extracting the actual post and comment bodies after a thread is selected, use the returned permalink with Summarize and Analyze a Reddit Post.
Automation Flow
- If no query is required, navigate directly to
https://www.reddit.com/r/{subreddit}/new/. For a query, constructhttps://www.reddit.com/r/{subreddit}/search/?q={query}&restrict_sr=on&sort=new&t={time-window}, URL-encoding{query}and using{time-window}such asday,week,month,year, orall. - After
domcontentloaded, wait briefly for Reddit’s client-renderedshreddit-postelements, then run the evaluator below in the same browser sequence. For a listing that initially has no posts, wait for client rendering before treating it as empty. - For ordinary discovery, choose the first returned post with a canonical
/r/{subreddit}/comments/{post-id}/...permalink, a nonzero or unknown comment count, and no locked, archived, removed, or deleted marker. Return all candidates as well as the selected thread so the caller can choose which discussion to read. - For a date-range collection, use the same direct
/new/URL and run the collection evaluator below. It scrolls the client-rendered listing until it reaches the requested lower cutoff or loading stabilizes, deduplicates by permalink, and assigns each post to the requested date band. Do not rely on a single viewport or on the approximatet=dayfilter for multi-week collection. - Open the selected permalink with Summarize and Analyze a Reddit Post; do not infer a post ID or fabricate a URL from its title.
Standard discovery evaluator
(() => {
const clean = v => String(v ?? '').replace(/\s+/g, ' ').trim();
const visible = el => { const r = el.getBoundingClientRect(), s = getComputedStyle(el); return r.width > 0 && r.height > 0 && s.display !== 'none' && s.visibility !== 'hidden' && Number(s.opacity || 1) > 0; };
const abs = href => { try { return new URL(href, location.href).href; } catch { return clean(href); } };
const posts = [...document.querySelectorAll('shreddit-post')].filter(visible).map((p, index) => {
const title = clean(p.getAttribute('post-title') || p.querySelector('h1,[slot="title"]')?.textContent);
const permalink = abs(p.getAttribute('permalink') || p.querySelector('a[href*="/comments/"]')?.getAttribute('href') || '');
const text = clean(p.innerText || p.textContent);
const attrs = [...p.attributes].filter(a => !['post-title','permalink','content-href'].includes(a.name)).map(a => `${a.name}=${a.value}`).join(' ');
const unavailable = /\b(?:locked|archived|removed|deleted)\b/i.test(attrs);
const commentRaw = p.getAttribute('comment-count'), scoreRaw = p.getAttribute('score');
return { rank: index + 1, title, permalink, subreddit: clean(p.getAttribute('subreddit-prefixed-name') || p.getAttribute('subreddit-name') || location.pathname.match(/\/r\/([^/]+)/i)?.[1]), postId: clean(p.getAttribute('id') || p.getAttribute('data-post-id')), score: scoreRaw == null || scoreRaw === '' ? null : Number(scoreRaw), commentCount: commentRaw == null || commentRaw === '' ? null : Number(commentRaw), created: clean(p.getAttribute('created-timestamp')), unavailable, likelyLive: !unavailable && /\/comments\/[^/]+/i.test(permalink) };
}).filter(p => p.permalink);
const candidates = posts.filter(p => p.likelyLive && !p.unavailable && (p.commentCount == null || p.commentCount > 0));
return { listingUrl: location.href, subreddit: location.pathname.match(/\/r\/([^/]+)/i)?.[1] || null, query: new URL(location.href).searchParams.get('q'), sort: new URL(location.href).searchParams.get('sort'), timeWindow: new URL(location.href).searchParams.get('t'), posts, candidates, selected: candidates[0] || null };
})()Optional date-range collection evaluator
Pass {bands} as an array of objects with name, fromDaysAgo, and toDaysAgo, for example [{name:'past-14-days',fromDaysAgo:0,toDaysAgo:14},{name:'14-21-days',fromDaysAgo:14,toDaysAgo:21}]. The evaluator uses the current browser time as the reference; supply a fixed asOfMs in place of Date.now() when reproducibility around a boundary matters.
(async ({bands = [{name:'past-14-days',fromDaysAgo:0,toDaysAgo:14},{name:'14-21-days',fromDaysAgo:14,toDaysAgo:21}], asOfMs = Date.now()} = {}) => {
const clean = v => String(v ?? '').replace(/\s+/g, ' ').trim();
const abs = href => { try { return new URL(href, location.href).href; } catch { return clean(href); } };
const day = 86400000;
const lowerDays = Math.max(...bands.map(b => Number(b.toDaysAgo)));
const cutoff = asOfMs - lowerDays * day;
const rows = new Map();
const grab = () => {
for (const p of document.querySelectorAll('shreddit-post')) {
const permalink = abs(p.getAttribute('permalink') || p.querySelector('a[href*="/comments/"]')?.getAttribute('href') || '');
const created = p.getAttribute('created-timestamp');
if (!permalink || !created || rows.has(permalink)) continue;
const time = new Date(created).getTime();
if (!Number.isFinite(time)) continue;
const title = clean(p.getAttribute('post-title') || p.querySelector('h1,[slot="title"]')?.textContent);
const body = clean(p.querySelector('[slot="text-body"],shreddit-post-text-body')?.innerText);
const attrs = [...p.attributes].filter(a => !['post-title','permalink','content-href'].includes(a.name)).map(a => `${a.name}=${a.value}`).join(' ');
const unavailable = /\b(?:locked|archived|removed|deleted)\b/i.test(attrs);
const score = p.getAttribute('score'), comments = p.getAttribute('comment-count');
rows.set(permalink, { permalink, postId: clean(p.getAttribute('id') || p.getAttribute('data-post-id')), title, body, created, createdMs: time, date: new Date(time).toISOString(), subreddit: clean(p.getAttribute('subreddit-prefixed-name') || p.getAttribute('subreddit-name')), score: score == null || score === '' ? null : Number(score), commentCount: comments == null || comments === '' ? null : Number(comments), unavailable });
}
};
let previous = 0, stable = 0;
for (let i = 0; i < 60; i++) {
grab();
const times = [...rows.values()].map(x => x.createdMs);
if (times.some(t => t <= cutoff)) break;
if (rows.size === previous) stable++; else stable = 0;
if (stable >= 5) break;
previous = rows.size;
window.scrollTo(0, document.body.scrollHeight);
await new Promise(r => setTimeout(r, 1200));
}
grab();
const posts = [...rows.values()].sort((a,b) => b.createdMs - a.createdMs).map(p => {
const ageDays = (asOfMs - p.createdMs) / day;
const band = bands.find(b => ageDays >= Number(b.fromDaysAgo) && ageDays < Number(b.toDaysAgo));
return {...p, ageDays, band: band?.name || null, likelyLive: !p.unavailable && /\/comments\/[^/]+/i.test(p.permalink)};
}).filter(p => p.createdMs >= cutoff && p.band);
return {listingUrl: location.href, asOf: new Date(asOfMs).toISOString(), bands, posts, counts: Object.fromEntries(bands.map(b => [b.name, posts.filter(p => p.band === b.name).length])), loadedCount: rows.size};
})({bands: {bands}})Possible Friction Points
- Reddit’s newest listing is directly reachable at
/r/{subreddit}/new/; avoid a homepage visit and search-box interaction when the subreddit is already known. - Subreddit-restricted recent searches use
/r/{subreddit}/search/?q={query}&restrict_sr=on&sort=new&t={time-window}. The observedday,month, andyearvalues are valid time-window filters; omit the search route when an unfiltered newest listing is requested. - Reddit renders listing entries as custom
shreddit-postelements. Generic article selectors can miss posts or mix in navigation and recommendation cards. - Durable post metadata is exposed through
post-title,permalink,score,comment-count,created-timestamp, and subreddit attributes onshreddit-post. - Wait for client rendering after
domcontentloaded; an empty result may mean the custom elements have not populated yet. - A listing does not guarantee that every post is commentable. Exclude entries marked locked, archived, removed, or deleted, and prefer canonical
/comments/{post-id}/permalinks. - Multi-week collection requires scrolling because
/new/is client-paginated/infinite-scrolling; deduplicate by permalink and stop only after reaching the lower date cutoff or observing stable loading. - Use timestamp comparisons for date bands rather than displayed date strings. Treat the lower bound as inclusive and the upper bound as exclusive, so adjacent bands do not overlap.
- The evaluator reports candidates rather than guessing an opaque post ID. Use the returned permalink directly for subsequent reading or commenting.
- Search results may cover only the requested time window; use
/new/for a complete currently available listing or adjusttexplicitly.