How to Screenshot Authenticated Pages
Capturing a public URL is straightforward. Capturing a dashboard, invoice, or any page that requires login is where headless browser automation breaks down: you need to log in first, preserve the session cookie, pass it to the screenshot request, and handle session expiry.
PageBolt lets you pass cookies and headers directly — no login automation required.
Pass a session cookie
If your app uses cookie-based sessions (most server-rendered apps do):
const res = await fetch("https://pagebolt.dev/api/v1/screenshot", {
method: "POST",
headers: {
"x-api-key": process.env.PAGEBOLT_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://yourapp.com/dashboard",
cookies: [
{
name: "session",
value: "your-session-token-here",
domain: "yourapp.com",
},
],
fullPage: true,
blockBanners: true,
}),
});
const image = Buffer.from(await res.arrayBuffer());
Pass a Bearer token via headers
For SPAs and APIs that use Authorization headers:
const res = await fetch("https://pagebolt.dev/api/v1/screenshot", {
method: "POST",
headers: {
"x-api-key": process.env.PAGEBOLT_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://yourapp.com/reports/q4-2024",
headers: {
Authorization: `Bearer ${userToken}`,
},
fullPage: true,
}),
});
Multiple cookies (e.g., CSRF + session)
Some frameworks require both a session cookie and a CSRF token:
body: JSON.stringify({
url: "https://yourapp.com/admin/users",
cookies: [
{ name: "session_id", value: sessionId, domain: "yourapp.com" },
{ name: "csrf_token", value: csrfToken, domain: "yourapp.com" },
],
}),
Generate a screenshot from inside your app (server-side)
The cleanest pattern for internal tools: generate a short-lived token on the server, embed it in the URL, screenshot the page, expire the token:
// Express route — generates signed URL, screenshots it, returns PDF
app.get("/invoices/:id/pdf", requireAuth, async (req, res) => {
const { id } = req.params;
// Create a single-use signed token
const token = await db.signedTokens.create({
invoiceId: id,
userId: req.user.id,
expiresAt: new Date(Date.now() + 60_000), // 1 minute
});
const signedUrl = `https://yourapp.com/invoices/${id}?token=${token.value}`;
const pdfRes = await fetch("https://pagebolt.dev/api/v1/pdf", {
method: "POST",
headers: {
"x-api-key": process.env.PAGEBOLT_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ url: signedUrl }),
});
const pdf = Buffer.from(await pdfRes.arrayBuffer());
// Expire the token immediately
await db.signedTokens.expire(token.id);
res.setHeader("Content-Type", "application/pdf");
res.setHeader("Content-Disposition", `attachment; filename="invoice-${id}.pdf"`);
res.send(pdf);
});
This avoids passing long-lived credentials to a third-party service — the token is valid for 60 seconds and invalidated after use.
Capture a user's dashboard on their behalf
For SaaS apps that need to email users a screenshot of their account state:
async function captureUserDashboard(userId) {
// Get the user's current session token from your DB
const user = await db.users.findById(userId);
const sessionToken = await generateSessionToken(user);
const res = await fetch("https://pagebolt.dev/api/v1/screenshot", {
method: "POST",
headers: {
"x-api-key": process.env.PAGEBOLT_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: `https://yourapp.com/users/${userId}/dashboard`,
cookies: [
{
name: "session",
value: sessionToken,
domain: "yourapp.com",
},
],
fullPage: true,
blockBanners: true,
blockAds: true,
}),
});
return Buffer.from(await res.arrayBuffer());
}
// Send weekly dashboard screenshot to all users
async function sendWeeklyDigest() {
const users = await db.users.findActive();
for (const user of users) {
const image = await captureUserDashboard(user.id);
await email.send({
to: user.email,
subject: "Your weekly summary",
attachments: [{ filename: "dashboard.png", content: image }],
});
}
}
Python example
import os
import requests
def screenshot_authenticated(url: str, session_cookie: str) -> bytes:
resp = requests.post(
"https://pagebolt.dev/api/v1/screenshot",
headers={"x-api-key": os.environ["PAGEBOLT_API_KEY"]},
json={
"url": url,
"cookies": [{"name": "session", "value": session_cookie, "domain": url.split("/")[2]}],
"fullPage": True,
"blockBanners": True,
},
)
resp.raise_for_status()
return resp.content
image = screenshot_authenticated(
"https://yourapp.com/dashboard",
session_cookie="your-session-token"
)
with open("dashboard.png", "wb") as f:
f.write(image)
What doesn't work (and why)
The alternative — automating login via a sequence of clicks — is fragile:
- Login forms change layout → automation breaks
- CAPTCHAs and bot detection block headless browsers
- MFA flows are hard to automate
- Session cookies from automated logins expire differently than API tokens
Passing a cookie or header directly sidesteps all of that. Generate a token server-side where you control the auth logic, pass it to the capture request, and expire it immediately after.
Try it free — 100 requests/month, no credit card. → Get started in 2 minutes
Top comments (0)