Extract the meaningful content of a Reddit post and supporting discussion without confusing the original post with comments, recommendations, navigation, or mixed page content. Return the title, author, subreddit, body, media references, and discussion context in a form suitable for detailed status-update analysis.
Use Cases
Use when the caller supplies a Reddit post URL, canonical URL, or share link such as /r/{subreddit}/s/{share-id} and asks to open, read, summarize, investigate, or understand the post. Share links must be resolved by Reddit; never guess a post ID from the share token. Use the media references when the post is image- or video-based, but distinguish directly observed post data from interpretation.
Automation Flow
- Use the supplied Reddit URL directly and construct its JSON variant by appending
.jsonto the path, for examplehttps://www.reddit.com/r/{subreddit}/comments/{post-id}/{slug}.json. For a share URL, usehttps://www.reddit.com/r/{subreddit}/s/{share-id}.jsonand let Reddit resolve it. If the supplied URL already ends in.json, use it unchanged. This avoids a homepage visit and usually returns both the post listing and discussion listing in one navigation. - In one browser sequence, navigate to that JSON URL with
waitUntil: "domcontentloaded", wait briefly for the response/viewer to populate, and run the evaluator below. It handles Reddit JSON responses and falls back to the renderedshreddit-postpage if Reddit serves HTML instead. - Ground the analysis primarily in
title,body,mediaTopic, andmediaAssets. UsekeyContextonly as supporting discussion context, clearly distinguishing commenters' reactions from the post's claims. If the body is empty, report that the post is textless and rely on title, media metadata, linked media, and discussion context. - When a post links to
preview.redd.it, retain the direct media URL and its metadata as an evidence reference. Do not treat a media URL, filename, or image preview as proof of claims that are not represented in the extracted post or visible media.
(() => {
const clean = v => String(v || '').replace(/\s+/g, ' ').trim();
const absolute = u => { try { return new URL(u, location.href).href; } catch { return String(u || ''); } };
const visible = el => {
if (!el) return false;
const r = el.getBoundingClientRect(), s = getComputedStyle(el);
return r.width > 0 && r.height > 0 && s.display !== 'none' && s.visibility !== 'hidden';
};
const text = el => clean(el?.innerText || el?.textContent);
const postData = x => x?.data?.children?.find(c => c?.kind === 't3')?.data;
const mediaOf = post => {
const out = [];
const add = (url, type = 'unknown') => { if (url) out.push({url: absolute(url), type}); };
add(post.url, post.post_hint || post.media?.type || 'linked-media');
add(post.thumbnail, 'thumbnail');
for (const p of post.preview?.images || []) {
add(p?.source?.url, 'preview-source');
for (const r of p?.resolutions || []) add(r?.url, 'preview-resolution');
}
if (post.media?.oembed?.thumbnail_url) add(post.media.oembed.thumbnail_url, 'oembed-thumbnail');
return [...new Map(out.filter(x => x.url).map(x => [x.url, x])).values()];
};
let parsed = null;
for (const el of [...document.querySelectorAll('pre,body')]) {
try { const x = JSON.parse(el.textContent.trim()); if (x) { parsed = x; break; } } catch {}
}
if (parsed) {
const listings = Array.isArray(parsed) ? parsed : [parsed];
const post = listings.map(postData).find(Boolean);
if (!post) throw new Error('Reddit JSON contained no post listing');
const commentListing = listings.find(x => x?.data?.children?.some(c => c?.kind === 't1'));
const comments = (commentListing?.data?.children || []).map(c => c.data).filter(Boolean).slice(0, 8).map(c => ({author: clean(c.author), text: clean(c.body), score: c.score ?? null})).filter(x => x.text);
const mediaAssets = mediaOf(post);
return {
url: post.permalink ? new URL(post.permalink, 'https://www.reddit.com').href : location.href.replace(/\.json(?:\?.*)?$/, ''),
resolvedUrl: location.href,
subreddit: clean(post.subreddit_name_prefixed || post.subreddit),
postId: clean(post.id),
author: clean(post.author),
title: clean(post.title),
body: clean(post.selftext),
mediaTopic: [...new Set([post.domain, post.post_hint, post.media?.type, post.link_flair_text, post.url].map(clean).filter(Boolean))],
mediaAssets,
keyContext: comments,
pageTitle: clean(document.title)
};
}
const post = [...document.querySelectorAll('shreddit-post')].find(visible);
if (!post) throw new Error('Neither Reddit JSON nor rendered shreddit-post was found');
const first = selectors => { for (const s of selectors) { const v = text(post.querySelector(s)); if (v) return v; } return ''; };
const links = [...post.querySelectorAll('a[href]')].map(a => ({text: text(a), href: absolute(a.href)})).filter(x => x.href);
const mediaAssets = links.filter(x => /(?:preview|i)\.redd\.it|\.(?:png|jpe?g|gif|webp|mp4)(?:[?#]|$)/i.test(x.href)).map(x => ({url: x.href, type: 'linked-media'}));
const comments = [...document.querySelectorAll('shreddit-comment')].filter(visible).slice(0, 8).map(c => ({author: clean(c.getAttribute('author') || c.querySelector('a[href*="/user/"]')?.textContent), text: text(c.querySelector('[slot="comment"]') || c.querySelector('[data-testid="comment"]') || c)})).filter(x => x.text);
return {
url: links.find(x => /\/comments\//i.test(x.href))?.href || location.href,
resolvedUrl: location.href,
subreddit: clean(post.getAttribute('subreddit-name') || post.getAttribute('subreddit')),
postId: clean(post.getAttribute('id') || post.getAttribute('data-post-id') || (location.pathname.match(/\/comments\/([^/]+)/i) || [])[1]),
author: clean(post.getAttribute('author') || links.find(x => /\/user\//i.test(x.href))?.text),
title: first(['[slot="title"]','h1']),
body: first(['[slot="text-body"]','shreddit-post-text-body','[data-testid="post-content"]']),
mediaTopic: links.filter(x => !/\/comments\//i.test(x.href) && !/\/user\//i.test(x.href)).slice(0, 10),
mediaAssets,
keyContext: comments,
pageTitle: clean(document.title)
};
})()Possible Friction Points
- Reddit share links use
/r/{subreddit}/s/{share-id}and normally redirect to a canonical post; do not infer or fabricate the opaque post ID from the share token. - Appending
.jsonto a supplied share or canonical post path is a useful direct endpoint. Reddit commonly returns an array containing at3post listing followed by at1comment listing. - A browser JSON viewer may expose the response in
preorbody; parse the page text rather than selecting arbitrary visible page text. - If the JSON endpoint falls back to HTML, Reddit renders the post through the custom
shreddit-postelement; generic article selectors can mix the post with comments or recommendation cards. - Wait briefly after
domcontentloadedfor client rendering when using the HTML fallback. - Prefer JSON fields
title,selftext,url,domain,post_hint,preview, andlink_flair_textfor media and topic identification. Preview URLs may be encoded or contain resizing parameters; preserve them as references rather than treating them as independent claims. shreddit-commentelements or JSONt1entries are supporting context only; visible comments may be incomplete and are not representative of the entire thread.- If Reddit shows access denial, a security challenge, a generic error, or a large login overlay, report that the post could not be read instead of summarizing surrounding page text.
- A textless image post may have no
selftext; analyze only the title, linked/preview media metadata, and available discussion unless visual media inspection is explicitly available.