Scrape data from pages behind a login without scripting the sign-in
To scrape a website behind a login, the request has to arrive with a session the site already trusts. Account balances, order histories, analytics dashboards, supplier portals and internal tools all sit behind authentication. The Scraping API forwards your cookie or token as a real request header, so the rules run on the page your user sees.
An anonymous scraper only ever sees the login form
A fresh browser has no cookies. Request an authenticated URL and the site redirects to its sign-in page, which returns 200 like any other page, so your rules run against the login form and every field comes back null without an error.
Scripting the login looks like the fix and is the fragile path. You store a real password next to the scraper, replay a form whose markup changes, and run into the multi-factor prompts and bot checks that exist precisely to stop automated sign-ins. Each run pays for the whole login flow before extracting anything.
If your application already holds a valid session or API token, forward it. Any request header prefixed with x-api-header- reaches the target with the prefix stripped, so x-api-header-cookie arrives as cookie and x-api-header-authorization as authorization. The private pages guide shows the pattern for data extraction.
How to scrape authenticated pages with a forwarded session
Headers are a Pro feature, so authenticated requests go to pro.microlink.io with your API key. Keep them on your backend, never in client-side code.
import createClient from 'microlink.io'
const microlink = createClient({
apiKey: process.env.MICROLINK_API_KEY
})
const { balance, orders } = await microlink.extract(
'https://app.example.com/account',
{
balance: { selector: '[data-testid=balance]', attr: 'text', type: 'number' },
orders: { selectorAll: '.order-row .order-id', attr: 'text' }
},
{
headers: {
'x-api-header-cookie': `session=${process.env.SESSION_COOKIE}`
},
cacheKey: `user-${userId}`,
waitForSelector: '[data-testid=balance]'
}
)The SDK sends headers as real HTTP request headers, never in the URL. Forwarded headers are not part of the cache key, so cacheKey keeps each user in a separate cache entry, and waitForSelector on an element that only exists when signed in doubles as a check that the session was accepted.
import createClient from 'microlink.io'
const microlink = createClient({
apiKey: process.env.MICROLINK_API_KEY
})
const { content } = await microlink.extract(
'https://api.example.com/v1/invoices',
{ content: { attr: 'json' } },
{
prerender: false,
headers: {
'x-api-header-authorization': `Bearer ${process.env.APP_TOKEN}`
},
cacheKey: `tenant-${tenantId}`
}
)For endpoints that answer with JSON, attr json parses the whole body and returns it with its original shape. prerender: false skips the browser because there is nothing to render, and cacheKey scopes the cached response to the tenant that owns the token.
curl -G https://pro.microlink.io \
-d url=https://app.example.com/account \
-d 'data.balance.selector=[data-testid=balance]' \
-d data.balance.attr=text \
-d meta=false \
-d cacheKey=user-42 \
-H "x-api-key: $MICROLINK_API_KEY" \
-H 'x-api-header-cookie: session=abc123'x-api-key authenticates you against pro.microlink.io and the x-api-header-cookie value is what the target receives. The rules travel as data query parameters and the secret only as a header.
- headers Public request shaping such as a language. Secrets go in x-api-header-* request headers instead. Pro plans.
- cacheKey Adds a custom identifier, such as a user id, so each user gets a separate cache entry. Pro plans.
- waitForSelector Waits for an element that only renders for a signed-in user.
- data The extraction rules, identical to any public page.
- force Skips the cache when a private page must be read fresh.
Sending x-api-key to the free endpoint fails with EPRO, and the headers parameter without a Pro plan returns EHEADERS. The SDK options reference explains how the headers option is routed.
Why forwarding a session beats automating the login
The session is the smallest credential that makes the page render for a user. Forwarding it keeps the password out of your scraper entirely.
The same header pattern captures the page as an image in screenshots behind a login and as a document in PDF invoices from authenticated pages.
The request isolation page describes the one-browser-per-call model, and the custom headers feature shows how values ride the HTTP layer.
When not to: Microlink does not log in for you. If all you have is a username and password, sign in with your own backend first and forward the resulting session. Never forward a session that belongs to someone who has not authorized it.
FAQ
How do I scrape a website behind a login?
Can I scrape an API that needs a bearer token?
Why does my authenticated scrape return null for every field?
Is it safe to put the session cookie in the headers query parameter?
Can I scrape pages behind a login on the free plan?
Solve the next problem with the same API
Screenshots behind a login
PDF invoices from authenticated pages
Any website to JSON
Cached JSON endpoints
Custom fields from JavaScript apps
Puppeteer without hosting Chrome
Ready to scrape authenticated pages?
Forward the session, keep the password out of the scraper. Get a Pro key and extract data from the pages only your users can see.