Summary
get-my-articles (and the other authenticated tools) return empty results, and the user is forced to log in on almost every run. While debugging this I found it is actually several overlapping issues in the browser automation layer. I have a fix ready and will open a PR that references this issue.
Symptoms
- A Chromium window opens on (almost) every call instead of staying in the background.
- Re-login is required repeatedly even though a session was "saved".
login-to-medium reports success, but the next tool call still behaves as logged-out.
get-my-articles returns [] even when the account has published stories.
Root causes (verified empirically)
- Session cookies are lost across context restarts. Medium's auth relies on session cookies (
sid, xsrf). A persistent profile keeps cookies with an expiry, but Chromium drops pure session cookies when the context is closed/reopened — so the headed→headless switch (and server restarts) silently log the user out. (Reproduced with a minimal persistent-context add/close/reopen test.)
- Cloudflare bot challenge blocks headless navigation. Medium serves a "Just a moment…" interstitial. The code never waits it out, so extraction runs against the challenge page. It is also made worse by a User-Agent mismatch: the visible login uses a normal "Chrome" UA while headless reports "HeadlessChrome", which invalidates the
cf_clearance cookie and re-triggers the challenge.
- Wrong stories URL.
get-my-articles navigates to https://medium.com/me/stories/public, which now redirects to the Drafts tab. The published list lives at https://medium.com/me/stories?tab=posts-published.
- Login is detected from cookie presence only. Medium sets
uid/sid for anonymous visitors too, so sid+uid is not proof of authentication — the page renders logged-out while the code thinks it is logged in.
- Outdated selectors for the stories list.
Proposed fix (in the upcoming PR)
- Persistent Chrome profile plus a full
storageState snapshot that is re-injected on every launch (carries session cookies through the headed→headless switch and across restarts).
- A fixed, consistent User-Agent for both login and headless runs, and an explicit Cloudflare "Just a moment…" wait after each navigation.
- Correct published-tab URL and more robust extraction.
- Auth detected from the actual page (absence of the header Sign-in button), not cookie presence.
- Headless-by-default background operation; the visible window appears only for the one-time login.
Notably this also fixes the documented "Google login session" limitation
The README notes Google login sessions couldn't be persisted. With the persistent profile + storageState re-seeding, a Google login is captured and reused silently in the background (verified end-to-end: get-my-articles returns all published stories headless, no window, no re-login).
Environment
- Playwright bundled Chromium 138
- Windows 10/11, Node.js
- Medium web (mid-2026 layout)
Thanks for the browser-based rewrite — happy to adjust the PR to your preferences.
Summary
get-my-articles(and the other authenticated tools) return empty results, and the user is forced to log in on almost every run. While debugging this I found it is actually several overlapping issues in the browser automation layer. I have a fix ready and will open a PR that references this issue.Symptoms
login-to-mediumreports success, but the next tool call still behaves as logged-out.get-my-articlesreturns[]even when the account has published stories.Root causes (verified empirically)
sid,xsrf). A persistent profile keeps cookies with an expiry, but Chromium drops pure session cookies when the context is closed/reopened — so the headed→headless switch (and server restarts) silently log the user out. (Reproduced with a minimal persistent-context add/close/reopen test.)cf_clearancecookie and re-triggers the challenge.get-my-articlesnavigates tohttps://medium.com/me/stories/public, which now redirects to the Drafts tab. The published list lives athttps://medium.com/me/stories?tab=posts-published.uid/sidfor anonymous visitors too, sosid+uidis not proof of authentication — the page renders logged-out while the code thinks it is logged in.Proposed fix (in the upcoming PR)
storageStatesnapshot that is re-injected on every launch (carries session cookies through the headed→headless switch and across restarts).Notably this also fixes the documented "Google login session" limitation
The README notes Google login sessions couldn't be persisted. With the persistent profile + storageState re-seeding, a Google login is captured and reused silently in the background (verified end-to-end:
get-my-articlesreturns all published stories headless, no window, no re-login).Environment
Thanks for the browser-based rewrite — happy to adjust the PR to your preferences.