Writing

Research Tool / React + Archive API · February 10, 2026 · 5 min read

reddit-core: A Faceted Search Front-End for Reddit's Public Archives

Reddit's own search can't filter by date range, score, or author together, and it can't see what has already scrolled out of reach. reddit-core is a small React app on top of the PullPush archive API that can, plus a one-click hand-off into my curation CMS.

20192026subreddit: r/indiascore ≥ 100size 200retry 1s → 2s → 4sfig. 12 — faceted archive search

A lot of my curation work for Quora starts on Reddit. Reddit is a great place to find things and a poor place to find them again. Native search ranks by its own idea of relevance, can't combine a date window with a score threshold and a specific author, and older threads can be hard to reach. Sometimes the thread I remembered had also been removed by moderators, or the post had been edited until it no longer said what I came for.

reddit-core is my answer to that. It's a single-page React app that queries the PullPush archive, a community-run index of public Reddit posts and comments, with a proper filter panel. Because the archive captured content when it was public, it can also surface posts and comments that have since been edited or removed from Reddit itself. That capability is useful, and it comes with responsibilities, which I get to further down.

10
API query parameters wired to the UI
200
results per query (raised from 50)
3
retries with exponential backoff
1
component file doing the real work

Architecture: deliberately thin

There's no backend of mine in this project. The browser talks directly to the archive API, and a single Firestore collection is the only state I own.

  1. Filter panel
    React state
    Keywords, author, subreddit, dates, score, IDs.
  2. URLSearchParams
    query builder
    Only set fields are sent.
  3. PullPush API
    /submission or /comment
    Public archive search.
  4. Archive feed
    grid or list cards
    Score, author, date, preview image.
  5. Add to CMS
    Firestore
    Hand-off to my curation pipeline.

The stack is React 19 on Vite 7, lucide-react for icons, and the Firebase v12 SDK. Vite's base is set to /reddit-core/ so the build can be served from GitHub Pages.

Building the query

Everything happens in one executeSearch callback. The filter panel's state is turned into query parameters, and I only append the ones that are actually set, so an empty field never narrows the search by accident:

text
const type = searchFor === 'submission' ? 'submission' : 'comment'; const params = new URLSearchParams({ size: '200', sort: sortOrder, sort_type: sortBy, }); if (query) params.append('q', query); if (subreddit) params.append('subreddit', subreddit); if (username) params.append('author', username); if (ids) params.append('ids', ids); if (enableAfter) { const dt = new Date(`${afterDate}T${afterTime}:00`); params.append('after', Math.floor(dt.getTime() / 1000)); }

A few choices worth explaining:

  • Date and time, not just date. The archive takes Unix epoch seconds, so I let you pick a time as well as a day. Each bound has its own "Enable" checkbox, so an open-ended range is one click away. The defaults run from 2010-01-01 to today.
  • Score as an operator plus a value. The API accepts expressions like >100, so the UI is a Greater/Less/Equal dropdown next to a number. A score of 0 means "don't filter".
  • Sort is exposed directly. Score, creation date, or comment count, ascending or descending. Sorting by date ascending inside a narrow window is the closest thing to a time machine for a subreddit.
  • Posts vs comments just switches the endpoint between /submission/ and /comment/.

The page size started at 50. In April I raised it to 200, because for research you want to skim a wide slice and then narrow the filters. Paging through tiny result sets was slower than reading a larger one.

Being polite to a free API

PullPush is a free, community-run service, and it rate-limits. A search that fails once shouldn't fail for good, but it also shouldn't hammer the server. So the fetch retries up to three times with exponential backoff, waiting 1 s, then 2 s, then 4 s, before showing an error:

text
} catch (err) { if (retryCount < 3) { const delay = Math.pow(2, retryCount) * 1000; setTimeout(() => executeSearch(retryCount + 1), delay); } else { setError("Failed to fetch data. PullPush might be rate-limiting."); setIsSearching(false); } }

Rendering messy data

Archive records aren't uniform. A post might have a preview with several resolutions, only a source image, a direct image url, a thumbnail, or nothing at all. Comments have a body instead of a title. PostCard handles this in a fixed order. For previews it picks the resolution whose width is closest to 640 px, which is enough for a card without pulling the full-size original. It also decodes the &amp; entities Reddit leaves in preview URLs. Any field that might not be a string goes through a small renderContent guard so a stray object or null can't crash the render.

The CMS hand-off

The button on every card says Add to CMS. reddit-core is one of several feeders into a small Firestore-backed content store I use when assembling curation posts. Another is a right-click browser extension that does the same thing from reddit.com itself. The app signs in anonymously and writes the post under a per-ID document:

text
// Path: /artifacts/quora-cms/public/data/content/{postId} const postRef = doc(db, 'artifacts', CMS_APP_ID, 'public', 'data', 'content', postId); const sanitizedPost = JSON.parse(JSON.stringify(post)); await setDoc(postRef, { ...sanitizedPost, saved_at: serverTimestamp(), source: 'PullPush Dashboard' });

Keying the document on the Reddit ID means saving the same post twice just overwrites it instead of creating a duplicate. The JSON.parse(JSON.stringify(...)) round-trip strips anything Firestore can't store. The UI tracks in-flight and completed saves in two Sets, so each card shows a spinner and then "In CMS".

What's rough, honestly

This is a working tool I use, not a polished product, and the code shows it:

AreaState
Search target (posts/comments), author, subreddit, dates, score, IDs, sortWired to the API
"Search By: Title / Body / Both" toggleUI only, not sent to the API yet
"Highlight keywords" checkboxUI only, not implemented
Timezone labelHard-coded to IST; dates use the browser's local time
Firestore writesAnonymous auth; safety depends entirely on Firestore security rules

The README is also still the Vite template. Next on the list: wire up the title/body split (the archive API, like Pushshift before it, has field-specific parameters for this), add real highlighting, add cursor-based pagination so 200 isn't a hard ceiling, and move the "Add to CMS" path behind an authenticated user instead of anonymous sign-in.

github.com/shubhrgunjan
reddit-core

Faceted search over Reddit's public archives, with a hand-off to a curation CMS.

git clone https://github.com/shubhrgunjan/reddit-core

The lesson I keep relearning with small tools like this is that the value is in the filters, not the UI. Native Reddit search and reddit-core read the same content. What made the difference was being able to ask for "this author, this subreddit, this week of 2019, score above 500" in one query.