Skip to content

Read Facebook Pages with a session, not a Page Access Token - #161

Merged
ralyodio merged 1 commit into
mainfrom
fb-scrape
Aug 29, 2026
Merged

Read Facebook Pages with a session, not a Page Access Token#161
ralyodio merged 1 commit into
mainfrom
fb-scrape

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

/fb/ shipped as connected-Pages-only, on the grounds that Graph reaches only Pages the caller administers. That was true and it was also inconsistent: X is read with an auth_token cookie and Instagram with an IG_COOKIE, and refusing Facebook the same bargain made /fb/ a namespace almost nobody could add to.

So a Page is now read the way the other two are — a logged-in session against mbasic.facebook.com, which still renders server-side HTML and which 302s to login.php rather than 404ing, so it is gated rather than gone.

Graph is kept and preferred where a token happens to exist, because a supported API beats guessing at markup. It is never required. Both paths key on the post id, so a Page that gains a token later keeps its identity and nobody's reader marks the feed unread.

/fb/ now takes open submissions like the other three.

This is the least dependable thing in the directory

RSSHub maintains Twitter and Instagram and has no Facebook namespace. That is a verdict, not an oversight. So the fragility is handled in code rather than promised away in the README:

  • Every selector is in one SELECTORS object, so the inevitable break is one edit in one known place — fetch a page with a live cookie, look at the HTML, edit that object.
  • A login wall or checkpoint retires the session, never the Page. Ten failures retire a feed; getting this wrong would delete the whole namespace in an afternoon.
  • Each platform now has its own floor rather than sharing X's five minutes: X 5, Instagram 30, Facebook 60. The cost of asking Facebook too often is a locked account, not a 429 — and a Page that posts twice a week loses nothing to an hourly floor.

Two real bugs found on the way

Bug Effect
Vanity regex required 5 chars That's Facebook's rule for new usernames. facebook.com/NASA is four — real Pages were rejected outright
"No session configured" classified as an upstream anomaly Retried every 20 min instead of hourly; it is a deployment that hasn't happened, not a service that's down

Also a layering fix: packages/db no longer imports @rssamplifier/social for the interval — the caller supplies it, since social reads nothing from db and db has no reason to know what a platform is.

Verified

97 tests in packages/social (9 new, against an mbasic-shaped fixture), 1,354 across 12 packages, all green. Build clean.

The selectors themselves are not verified — only a live cookie proves those, and they will change regardless. What is verified is everything around them: the login wall classifies correctly, a post with no id is dropped rather than stored undeduplicatable, relative mbasic links come out pointing at facebook.com, and an unparseable relative date stays null rather than being stamped now.

Collects nothing until FB_COOKIE is set.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Q6QEgpuS4MLamogXtr2ZX6

/fb/ shipped as connected-Pages-only, on the grounds that Graph reaches
only Pages the caller administers. That was true and it was also
inconsistent: X is read with an auth_token cookie and Instagram with an
IG_COOKIE, and refusing Facebook the same bargain made /fb/ a namespace
almost nobody could add to.

So a Page is now read the way the other two are — a logged-in session
against mbasic.facebook.com, which still renders server-side HTML and
which 302s to login.php rather than 404ing, so it is gated rather than
gone. Graph is kept and preferred where a token happens to exist for a
Page, because a supported API beats guessing at markup; it is never
required. Both paths key on the post id, so a Page that gains a token
later keeps its identity and nobody's reader marks the feed unread.

/fb/ now takes open submissions like the other three.

This is the least dependable thing in the directory and the code says so
rather than the README alone:

- every selector lives in one SELECTORS object, so the inevitable break
  is one edit in one known place
- a login wall or checkpoint is classified as an auth failure, which
  retires the SESSION and never the Page. Ten failures retire a feed, so
  getting this wrong would delete the namespace in an afternoon
- each platform now has its own floor rather than sharing X's five
  minutes: X 5, Instagram 30, Facebook 60. The cost of asking Facebook
  too often is a locked account, not a 429, and a Page that posts twice
  a week loses nothing to an hourly floor

Two bugs found on the way, both real:

- the vanity-name regex required five characters, which is Facebook's
  rule for usernames created now and not for Pages that already exist.
  facebook.com/NASA is four, so real Pages were being rejected outright
- "no session configured" was classified as an upstream anomaly (twenty
  minutes) rather than as a deployment that has not happened (an hour),
  alongside the equivalent cases for the other platforms

Layering fix while here: packages/db no longer imports
@rssamplifier/social for the interval — the caller supplies it, since
social reads nothing from db and db has no reason to know what a
platform is.

97 tests in packages/social, 1,354 across 12 packages, all green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q6QEgpuS4MLamogXtr2ZX6
@ralyodio
ralyodio merged commit 8830d23 into main Aug 29, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant