How Does Session Persistence Work in Scraping? β Definition and How It Works
Learn what makes a session persist, which state must stay together, and why an IP change invalidates a session.
Session persistence is keeping the state that makes consecutive requests look like one continuous visit: cookies, storage, tokens, and a stable exit address.
1. What Makes Up a Session
| Component | Held in |
|---|---|
| Session cookie | Cookie jar |
| CSRF token | A cookie, a header, or page markup |
| Local and session storage | Browser storage |
| Authentication token | Cookie or header |
| Exit IP address | The proxy or network |
| TLS session ticket | The client's TLS state |
| Fingerprint | The client itself |
The critical point: these must stay consistent together. A valid cookie presented from a different country, or with a different fingerprint, is a contradiction β and it is that contradiction, rather than any single value, that invalidates the session.
2. The Minimum: A Cookie Jar
import requests
session = requests.Session()
session.get("https://example.com/") # collects cookies
session.post("https://example.com/login", data=creds) # sets auth cookie
r = session.get("https://example.com/account") # authenticated
A session object carries cookies between requests and reuses connections. Making a bare request instead of using the session is the commonest reason "the login worked but the next page is logged out".
3. Exit Address Stability Is the Hard Part
A session established from one address and continued from another is a signal many sites act on, because a legitimate user's address rarely changes mid-session.
That is why per-request proxy rotation and authenticated sessions are incompatible. Rotating is correct for stateless collection; a sticky session is required for anything with a login or a multi-step flow.
The practical implication is that the whole flow β login, navigation, data retrieval β must run inside one sticky session, and the session must be released when it ends rather than held for the life of a worker.
4. Persisting Across Runs
Storage state export is the light-weight approach in browser automation: cookies and storage saved to a file and reloaded, without the whole profile.
context.storage_state(path="state/session-a.json")
# later
context = browser.new_context(storage_state="state/session-a.json")
A user data directory persists the whole profile, including cache and extension state, which preserves more but is larger and cannot be used by two browsers at once.
Either way the artefact is credential-equivalent: it grants what the session grants. Restrict permissions, never commit it, and never copy it into a shared environment.
5. Validate Before Use
A saved session expires silently. Requests then return the unauthenticated version of a page β a 200 with the wrong content, which extraction happily processes as though it were correct.
def session_valid(session):
r = session.get("https://example.com/account", allow_redirects=False, timeout=30)
return r.status_code == 200 and "Sign in" not in r.text
One cheap check before a run converts a silent data-quality failure into a caught error. Its absence is the single most common defect in session-based collection.
6. One Session Per Identity
Sessions must not be shared across concurrent tasks. Two workers using one cookie jar produce interleaved state, and one worker's logout or token refresh breaks the other.
The clean model is one session per logical identity, used serially, with its own sticky proxy and its own storage artefact. Tasks belonging to different identities never share any of it.
7. Refreshing Tokens
Where an API issues a short-lived access token with a refresh token, persistence means storing both and refreshing before expiry rather than after a failure.
Two details matter: refresh under a lock so concurrent workers do not race and invalidate each other's token, and persist the new refresh token immediately if the server rotates it β losing a rotated refresh token means re-authenticating from scratch.
8. Summary
Session persistence keeps cookies, storage, tokens, exit address, and fingerprint consistent so consecutive requests read as one visit β and it is the consistency between them, not any single value, that a site checks.
Use a session object rather than bare requests, keep an authenticated flow inside one sticky proxy session, persist storage state as the credential it is, validate the session before every run so an expiry is not mistaken for changed content, and never share one session across concurrent workers.