omnifeed

ADR 0001: Reading Reddit after the logged-out JSON shutdown

Context

The Reddit engine read every thread and listing from Reddit’s .json endpoints. It fetched them from inside a headless browser through crawl4ai, because Reddit’s edge blocks non-browser HTTP clients that are logged out.

On 2026-05-28 Reddit announced on r/modnews: “We’ll also be shutting down unauthenticated .json endpoints … Logged-in and authenticated access won’t be impacted.” Enforcement reached our deployment later. The engine worked for 117 fetches from 2026-08-20 to 2026-10-08, with no failure. From 2026-10-15 every .json fetch failed with 403 and a “You’ve been blocked by network security” page.

On 2026-09-30 a Reddit admin posted the end of the public Data API on r/redditdev:

Date What happens
2026-10-31 New requests for public API access are no longer accepted.
2027-01-12 API access starts to close for apps and users that have not registered.
March 2027 Public API access closes for all remaining apps and users.

The replacement is the Developer Platform (Devvit), where apps run inside Reddit. It is not a data API an outside agent can call. RSS feeds end on 2026-11-13.

What causes the 403

The block is about the login state. The IP address, the ISP and the browser fingerprint do not cause it. Measured on 2026-10-15 from a residential IP:

Client Logged out Logged in
curl, Go net/http 403 200
Headless Chromium, default user agent (HeadlessChrome) 403 403
Headless Chromium, normal Chrome user agent 403 200
Real Chrome (headful) 403 200

A logged-out browser still gets the HTML thread page (200), and only .json is refused. Stealth flags, a matching user agent and real plugins did not change the logged-out result.

Decision

The engine reads Reddit through a chain of methods, tried in a configurable order (OMNIFEED_REDDIT_METHODS, default client_id,session,browser). A method without its credential is left out.

Method Credential How it reads Budget
client_id OMNIFEED_REDDIT_CLIENT_ID: an OAuth app’s client ID, installed-client grant, no secret app-only token, then oauth.reddit.com JSON 1000 requests per window
session OMNIFEED_REDDIT_SESSION: a logged-in reddit_session cookie www.reddit.com JSON over plain HTTP 100 requests per window, per account
browser none, or a session held by crawl4ai the rendered thread page through crawl4ai, read from the DOM the IP’s logged-out budget

The two direct methods use plain HTTP. One request returns the whole thread (limit=500&depth=20) with live scores.

Failure handling:

Where the skip state lives:

Monitoring

Alert on:

Options measured

All on 2026-10-15, on two reference threads: r/kubernetes 1x0wbf3 (72 comments) and r/ChatGPT 1x66iap (about 290). The reference tree is a logged-in .json fetch.

Option Time per thread Comments (large thread) Nesting and scores Result
client_id, live in omnifeed p50 2.9 s, p90 3.9 s 291 of 297 full depth, live 14/14 ok. Chosen first
session, live in omnifeed p50 1.4 s, p90 2.8 s 282 of 287 full depth, live 13/14 ok, the miss was transient. Chosen second
browser, rendered page plus in-page expansion 7.5 to 31 s 261 (93%) 12 empty bodies (media replies) Works logged out, but each thread costs 1 page load plus up to 40 expansion requests, and Reddit answers 429 after about 2 large threads. Chosen last
crawl4ai holding the cookie (server config) 2.6 s full tree live Works. crawl4ai refuses per-request cookies (“not permitted on BrowserConfig from an untrusted request”), so the cookie must sit in its server config
Logged-in headful Chrome kept open (CDP) 0.6 to 2.8 s full tree live 5/5 ok. A browser adds nothing over the plain-HTTP cookie
Arctic Shift archive API about 1 s 236 (84%), post missing 90 orphan comments, scores frozen at archive time No Reddit load, but incomplete and stale. Not used
Redlib public instances 1.1 to 2.3 s full (small thread) live 2 of 5 instances answered, the others 403 or 429. Not dependable

For the large thread, the logged-out HTML path returned 261 comments in one fetch. Expanding the .json tree fully took several /api/morechildren calls. A direct method returns 282 to 291 comments in one call.

Options rejected

Option Why
Logged-out .json with a better fingerprint (stealth, real user agent, headful) Still 403: the block is about the login state
Arriving on Reddit from a DuckDuckGo result to get an unlocking cookie (a published agent skill) Landed on the real thread, then both .json requests got 403
An empty or fake reddit_session cookie (an old trick posted on X) 403 for an empty value, a junk value and a fake token
PullPush API Returns empty data
RSS No scores, no comment tree, and it ends on 2026-11-13
Public OAuth API for new apps Needs Reddit’s approval, requests close on 2026-10-31, and the API closes in March 2027
Spoofing the official Android app’s API client Terms-of-service gray zone, and no better than client_id
Logged-out old.reddit Login wall
Paid Reddit data APIs Cost money, and the methods above work

Agent tooling surveyed

Tool Access method Result when run
reddit-mcp-buddy OAuth app, else RSS Anonymous mode: listings with every score null, thread details refused
jordanburke/reddit-mcp-server OAuth app, else RSS Comments need OAuth credentials
eliasbiondo/reddit-mcp-server logged-out .json Every call fails
hawstein/mcp-server-reddit redditwarp, installed-client grant Crashes on start (SDK and pydantic versions). Its library’s grant is what revealed the client_id method
dialog.tools hosted MCP hosted, PRAW behind it Needs an account
rdt-cli (agent skill) logged-in browser cookies Same mechanism as session

None of the Reddit MCP servers or skills surveyed uses a session cookie over plain HTTP.

Consequences

Operations

To refresh the session cookie:

  1. Log in to Reddit in a browser profile kept for this purpose.
  2. Copy the reddit_session cookie value. It is HttpOnly, so use the browser’s developer tools or its DevTools protocol.
  3. Set OMNIFEED_REDDIT_SESSION to that value and restart omnifeed.
  4. Check that omnifeed_reddit_session_expiry_timestamp_seconds moved about 6 months ahead.

Keep the cookie out of logs and version control. It gives full access to the account.

Sources