Skip to content
Consultation

DeepSeek Login Died Between Sessions. Three Scripts Fixed It.

Adityo Guni Waluyo

Re-logging into DeepSeek via VNC every week got old. I transferred the whole session into Camofox instead: cookies, token, keepalive.

TL;DR

DeepSeek sessions in Camofox died because logging in means two layers: HttpOnly cookies and a localStorage userToken for Bearer API calls. Importing cookies alone patched half the state, so the login page persisted. Three scripts merge cookies into Playwright's storage-state.json, inject the wrapped token, and poll every five minutes to confirm the session.

Lane C of my research setup needed a third chat window. I opened Camofox, clicked DeepSeek, and got the login page again. Profile was still there, tab history intact, but the session? Gone.

My first thought was simple: probably a Camofox quirk. Restart the container, re-login via VNC, move on. That was the guess. Manual VNC login works, but doing it every time DeepSeek forgets me was getting old.

The real problem wasn't Camofox being buggy. It was that I didn't understand what "being logged in" actually means in a browser automation setup.

Two Layers, Not One

Browser sessions aren't a single thing. There is the HttpOnly cookies layer, server-side session state that JavaScript can't touch [4]. And there is the localStorage layer, client-side tokens the app reads directly [2]. DeepSeek uses both. The session cookie tells the server "this is an authenticated user." The userToken in localStorage tells the frontend "send this as a Bearer header on every API call."

When I log in manually via VNC, both layers get populated naturally. But when I exported cookies from my regular browser and tried to import them into Camofox's profile, I was only solving half the equation.

My first attempt: export cookies via curl -c, parse the Netscape format, shove them into Playwright's storage-state.json. Check DeepSeek. Still the login page.

That's because storage-state.json is just a snapshot: cookies and localStorage bundled together [1]. I was writing cookies into the file but ignoring the token that DeepSeek's frontend actually needs to make API calls.

Three Scripts, One Flow

So I broke it into steps with dedicated scripts.

import-ds-cookies.py reads the exported cookies.txt in Netscape format, the same format curl writes with its cookie-jar flag [3]. One cookie per line, a #HttpOnly_ prefix for HttpOnly cookies. The script deduplicates by name and domain pair, keeping the entry with the furthest expiry. Before merging into the profile's storage-state.json, it backs up the existing file and checks /sessions to avoid overwriting an active session. That ordering matters. Merging is selective: it doesn't recreate the storage state from scratch, it patches the existing one.

inject-ds-token.py handles the other layer. It writes the userToken value into the localStorage section of storage-state.json. The value is not raw: it is a wrapped JSON object with a value field and a version field. Without this, the frontend has no Bearer token to authenticate API requests, even if the session cookie is valid.

ds-vnc-keepalive.py runs after both are loaded. It opens a tab to DeepSeek's sign-in page and polls localStorage every 5 minutes, checking if userToken has appeared. Twelve pings over an hour. If the token shows up, the session is live. If it doesn't, something else is wrong and manual intervention is needed.

The whole flow: export cookies from real browser → parse and merge into storage state → inject the API token → verify via keepalive poll. No profile recreation and no VNC login.

Migrate, Don't Recreate

I see this pattern a lot in browser automation discussions: "login broke? Just recreate the profile." That is destructive and unnecessary. Camofox profiles accumulate context: tab history, extensions, settings. Nuking them to fix a session issue is like formatting a drive because an app won't start.

Playwright's storage-state.json is a standard format designed exactly for this use case [1]. Cookies and localStorage in one file, portable between contexts. The tooling exists. The problem was that I did not think about which credential layer I was targeting.

Exported cookies are plaintext credentials. They should not go into version control. Storage state needs periodic regeneration, because there is no auto-refresh mechanism baked in. And headless fingerprints differ from real browsers, so platforms can detect the switch. These are things I track manually now, not things I ignore and hope for the best.

The minutes I used to lose to VNC re-login? Gone. DeepSeek stays authenticated across container restarts. Three small Python scripts did what "recreate the profile" was supposed to do, without the collateral damage.

Sources:

Related articles