Scraping Behind a Login: Cookies and Sessions
Web scraping with authentication means sending, with every request, whatever the site uses to recognize a signed-in user: usually a session cookie it set when you logged in, sometimes a bearer token or HTTP Basic credentials. Log in once (a form post, an API call or a real browser), keep the cookies in a cookie jar, send them back on each request and keep one IP for the session. When the session ends mid-run, detect it (a redirect to the login page, a 401 or 403, the login form in the HTML), save a checkpoint, log in again once, retry the failed request once, and stop and alert if it fails a second time. Do it only with an account you are entitled to use and within the site's terms. ProxyField residential proxies keep one IP for a logged-in run with sticky sessions of 30 s to 36 h, from $1.95/GB; start with the Easy Trial: 1 GB for $2.95.
- residential IPs
- 412M+
- from, traffic never expires
- $1.95/GB
- Easy Trial
- 1 GB for $2.95
| Step | What your scraper does | Tool |
|---|---|---|
| 1. Log in | Post the form (with its CSRF token), call the login API, or log in with a browser | curl, requests, fetch, Playwright |
| 2. Keep the session | Store every cookie the site sets and send it back on each request | A cookie jar: -c/-b, requests.Session(), fetch-cookie, storage_state |
| 3. Hold one IP | One sticky proxy session per account, for the length of the job | -session-<id>-ttl-<seconds> in the proxy username |
| 4. Check every response | Login redirect, 401/403, login form, a much shorter page | A logged_out() check |
| 5. Recover | Checkpoint, log in again once, retry once, stop on a second failure | The loop below |
On this page 9 sections
- How websites keep you logged in
- What a cookie carries, and what matters for scrapers
- Cookie jars: curl, Python and Node.js
- Reusing cookies from your own browser
- Keep the login state through a proxy
- When the session expires mid-run: detect, log in again, retry
- Paywalls and members-only content
- The legal line
- Scraping Behind a Login FAQ
How websites keep you logged in
| Mechanism | What the site gives you | What your scraper sends back | Typical sites |
|---|---|---|---|
| Session cookie | Set-Cookie: session=... after the login form | The Cookie header on every request | Most classic websites, shops, dashboards |
| Bearer token (often a JWT) | A token in a JSON response | Authorization: Bearer <token> | Single-page apps, mobile and public APIs |
| HTTP Basic authentication | Nothing; the browser asks for a username and password | Authorization: Basic <base64 user: on every request | Admin panels, intranet tools, some feeds |
| API key | A key from your account settings | A header or query parameter the docs name | Official APIs |
| Single sign-on (OAuth, SAML) | Redirects through an identity provider, then a cookie or token | Whatever the final step issues | Business tools, "Sign in with ..." buttons |
Find out which one you have before you write code: log in by hand with DevTools open on the Network tab ("Preserve log" on) and look at the login request and the next one. The Python walkthrough of each type is in scraping a website behind a login with Python.
Keep the login state through a proxy
Sites tie a session to more than the cookie. A session cookie that arrives from a new IP, especially in another city or country, can be ended or sent to a security check. So for authenticated scraping:
- Use a sticky session, not per-request rotation. Rotation gives each request a new IP, which looks like the account hopping around the world.
- One IP per account. If you work with several accounts you are entitled to use, give each one its own sticky session id and keep it.
- Match the location you normally log in from (country, region or city).
- Make the session at least as long as the job, and plan for the moments the IP can still change (the table below).
With ProxyField, the sticky session lasts from 30 s to 36 h (ttl from 30 to 129,600 seconds), with presets of 1, 5, 10 and 30 minutes and 1, 3 and 6 hours. The gateway is gate.proxyfield.io:7000, and <login>-country-us-city-new_york in the username asks for an exit IP in New York. Region, session and session time go in the same username: -region-<region>, -session-<id> and -ttl-<seconds>, as in <login>-country-us-region-new_york-city-new_york-session-he9f2qga-ttl-600; every part after the login is optional.
curl -x gate.proxyfield.io:7000 -U "<login>-country-us-city-new_york-session-acct1-ttl-7200:<password>" -b cookies.txt -c cookies.txt https://example.com/account| When the IP can change during a sticky session | What happens | What your scraper should do |
|---|---|---|
No ttl in the username | The session lasts 20 minutes by default | Set ttl to the length of the job |
The ttl runs out | The next request leaves from a new IP | Work in chunks that fit, or check the login after it |
| The IP sits idle for 120 s | It is replaced with a new IP | Keep pauses under 2 minutes, or expect a new IP |
| The exit node drops | The gateway retries once with a new session, so the IP may change; a broken connection is not restored, and the client reconnects | Reconnect and check the next response for a logout |
The IP is held while its exit node is up. Whenever it changes, a careful site may end the login, which is one more reason to check every response, as below. How the two proxy modes differ is in sticky vs rotating proxies; the authentication options of the proxy itself (username and password or an IP allowlist) are in proxy authentication.
When the session expires mid-run: detect, log in again, retry
A logged-out scraper keeps running and collects login pages instead of data. Check every response for one of these signs:
- a redirect to the login URL, or a final URL that contains
/loginor/signin; - status 401 or 403 from an API;
- the login form (a password field) or a "Sign in" link in the HTML where your account name used to be;
- a page much shorter than usual.
The cookie's expiry date is not the end of the session. Expires and Max-Age only tell the client when to delete the cookie. The server keeps its own session and can end it earlier: after a logout, a password change, an idle timeout, an absolute timeout or a security event (OWASP Session Management Cheat Sheet). Editing the date in your cookie jar changes nothing on the server, so don't do it. If the site issues a refresh token (common with bearer tokens), use its refresh flow instead of a full login.
What to do when a sign appears:
- Stop and checkpoint. Save the last record you processed, so the run can resume there.
- Log in again once, through the normal login flow, and keep the new cookies in the same jar.
- Retry the failed request once. Retry only reads (GET). Don't repeat an action that changes something, such as a form submission or an order, unless you can check whether it already went through.
- Stop and alert on a second failure. A failed re-login usually means a wrong password, a locked account or a new check.
- Stop for a person on MFA or a CAPTCHA. A second factor, a CAPTCHA or a consent screen needs a human; don't try to get past it.
In Python with requests:
import json, os, re, requests
BASE = "https://example.com"
PROXY = "http://<login>-country-us-city-new_york-session-acct1-ttl-7200:<password>@gate.proxyfield.io:7000"
CHECKPOINT = "checkpoint.json"
class SessionLost(Exception):
pass
def logged_out(r):
return ("/login" in r.url or r.status_code in (401, 403)
or 'type="password"' in r.text)
def login(s):
html = s.get(f"{BASE}/login", timeout=30).text
token = re.search(r'name="csrf_token" value="([^"]+)"', html).group(1)
r = s.post(f"{BASE}/login", timeout=30, data={"csrf_token": token,
"username": os.environ["SITE_USER"], "password": os.environ["SITE_PASS"]})
if logged_out(r):
raise SessionLost("login failed: check the password, or a second factor or check page")
def get(s, url):
r = s.get(url, timeout=30)
if not logged_out(r):
return r
login(s) # the session ended: log in once
r = s.get(url, timeout=30) # and retry this request once
if logged_out(r):
raise SessionLost(url) # second failure: stop and alert
return r
s = requests.Session()
s.proxies = {"http": PROXY, "https": PROXY}
start = json.load(open(CHECKPOINT))["next"] if os.path.exists(CHECKPOINT) else 1
login(s)
for page in range(start, 21):
html = get(s, f"{BASE}/items?page={page}").text
# ... parse and store html ...
json.dump({"next": page + 1}, open(CHECKPOINT, "w")) # resume pointWe ran it on 2026-10-27, without the proxy, against a test server that ends each session after 5 requests although its cookie says Max-Age=3600. The loop logged in 5 times (once at the start, then 4 times after the server ended the session) and collected all 20 pages, and the checkpoint ended at page 21. With a wrong password it stopped at once with SessionLost: login failed. Add the fourth sign (a page much shorter than usual) once you know the normal size of your pages.
Log in again only when a sign appears, not at the start of every request or run. Frequent logins from a script are more likely to trigger security checks, emails to the account owner or lockouts than a session that is reused calmly.
Paywalls and members-only content
A paywall is a login with a subscription behind it. Scraping articles you pay for, for your own reading or analysis, is a different matter from republishing them: the content is still protected by copyright (see is web scraping legal?), and subscription terms usually forbid automated downloading and sharing. Don't get around a paywall you haven't paid for; tricks that hide the paywall without logging in still mean taking content the publisher only sells. If you need news or members-only data at scale, ask the publisher about a license or an official feed.
The legal line
Authentication changes the legal picture. Pages anyone can open are treated differently from areas behind a password:
- Computer-misuse law. In the US, the Supreme Court read the Computer Fraud and Abuse Act in Van Buren v. United States (June 3, 2021) as asking whether you entered parts of a system that are off limits to you (opinion). Using someone else's login, or getting into areas your account can't see, is where that risk sits. In the UK, section 1 of the Computer Misuse Act 1990 makes unauthorized access an offense.
- Contract. Creating an account means accepting the site's terms. In the hiQ Labs v. LinkedIn case, the district court ruled in November 2022 that hiQ had breached LinkedIn's User Agreement, and in December 2022 the case ended in a consent judgment against hiQ (docket).
- Privacy. Logged-in pages often show other people's personal data; in the EU and UK, the GDPR applies to collecting it.
- ProxyField's Acceptable Use Policy does not allow using the service to access data behind logins you are not entitled to. Managing your own or your clients' social media and marketplace accounts, one IP per account, is allowed. Some site categories are restricted to protect the network, including financial and government services. Scraping behind a login is allowed only for data you are entitled to and the site's terms allow.
The full picture, with more cases, is in is web scraping legal?. This is not legal advice.
Logged-in scraping on your own accounts? ProxyField residential proxies: sticky sessions from 30 s to 36 h, 412M+ residential IPs in 195+ countries, targeting by country, region (state) and city, from $1.95/GB with no subscription; start with the Easy Trial (1 GB). Traffic never expires, and all purchases are final.
Scraping Behind a Login FAQ
How does web scraping with authentication work?
ProxyField sticky sessions keep one IP for 30 s to 36 h for a logged-in run (residential proxies start at $1.95/GB), and the scrape itself follows the browser: log in once with a form post, an API call or a real browser, keep the cookies or token it returns, and send them with every request. Check each response for signs of a logout and log in again when needed. Use only accounts you are entitled to and stay within the site's terms.
How do I keep a scraper logged in with session cookies, and what should it do when those cookies expire mid-run?
Keep the cookies in one jar (requests.Session(), curl's -c/-b files or a Playwright state file) and send them with every request from one sticky IP. Check each response for a login redirect, a 401 or 403, or the login form; when one appears, save a checkpoint, log in again once, retry the failed request once, and stop and alert if it fails again. On a second factor or a CAPTCHA, stop for a person.
How do I manage cookies when scraping?
Use your HTTP client's cookie jar instead of handling cookies by hand: requests.Session in Python, -c and -b files in curl, fetch-cookie in Node.js, or a browser context in Playwright. Save the jar between runs if the login should survive, keep one jar per account, and clear it when you want a fresh visitor.
Can I scrape content behind a login or paywall?
Only with an account you are entitled to use, and within the site's terms, which often forbid automated access for logged-in users. Content behind a paywall is usually still under copyright, so scraping your own subscription for personal analysis is different from republishing it, and getting around a paywall you haven't paid for is not allowed.
How do I scrape pages that require login with curl?
Load the login page with -c cookies.txt to get the first cookie and the CSRF token, post the form with -b cookies.txt -c cookies.txt -d "field=value&...", then request the protected pages with -b cookies.txt. For HTTP Basic authentication, curl -u user:pass URL is enough.
How do you handle cookies when web scraping with cURL?
Write cookies with -c file and send them with -b file; use both on the same call to keep the file up to date. You can also send a cookie directly with -b "name=value" or -H "Cookie: name=value", and the file keeps HttpOnly cookies on lines that start with #HttpOnly_.
How can I perform Node.js scraping from websites that use authentication or cookies?
Wrap fetch with fetch-cookie (3.2.0) so cookies persist between calls, post the login form or call the login API, and reuse the same wrapped fetch for the protected pages. For token logins, send Authorization: Bearer <token>; for logins that need a browser, log in with Playwright and save its storage state.
What happens when my cookies expire?
The site treats your next request as a logged-out visitor: you get redirected to the login page, receive a 401 or 403 from an API, or see public content instead of your account. Detect it in your scraper and log in again, or refresh the token if the site gives you a refresh token.
Is a cookie's expiry date the real end of a login session?
No. Expires and Max-Age only tell the client when to delete the cookie; the server can end the session earlier after a logout, a password change, an idle or absolute timeout, or a security event. Changing the date in your cookie jar does not bring the session back, so detect the logout and log in again.
What are web cookies?
Small name and value pairs that a website asks your browser or HTTP client to store and send back on later requests. Sites use them to keep you logged in, remember settings and cookie-banner choices, and measure visits.
Show 2 more questionsShow fewer questions
Should you get around login walls when scraping?
No. A login wall is the site saying the content is not public; getting past it without an account you are entitled to use can break the site's terms and, in some cases, computer-misuse law. Scrape the public pages, log in with your own account within the terms, or ask the site for access or a license.
Do I need sticky sessions to stay logged in while scraping?
Usually yes, if you scrape through proxies: a logged-in session that changes IP on every request can be ended or flagged by the site. Keep one sticky IP per account for the length of the job, in the location you normally log in from; with ProxyField an idle IP is replaced after 120 s, so keep pauses shorter or check the login after them.
Related pages
Easy Trial: 1 GB for $2.95.
Try for the price of 1 GB, no subscription, traffic never expires.