For AI agents: a documentation index is available at /llms.txt
Skip to main content

Cookies and page setup in BAP

Cookie injection is how you skip a login: authenticate once, keep the cookies, and start later sessions already signed in. This guide covers reading and injecting cookies, plus the other session-level setup methods: user agent, direct HTML, injected scripts and styles, and disabling JavaScript.

Prerequisites

Read cookies

cookies() returns the current cookies as structured records. Save these after a successful login and you have a reusable credential for future sessions.

import Browserless from "@browserless.io/bap-ts";

const TOKEN = "YOUR_API_TOKEN_HERE";

const browser = Browserless.connect({
browserWSEndpoint: "wss://production-sfo.browserless.io/chromium/bql",
token: TOKEN,
});

try {
const page = await browser.newPage();
await page.goto("https://example.com/login");

await page.type("#user", "name@example.com");
await page.type("#pass", "secret");

// Start the wait before the click, or a fast navigation finishes first.
const navigated = page.waitForNavigation({ waitUntil: "networkIdle" });
await page.click("#submit");
await navigated;

// Persist these and later sessions can skip the login entirely.
const cookies = await page.cookies();
console.log(cookies.length);
} finally {
await browser.close();
}

Response:

4

Inject cookies to skip the login

Set cookies before navigating, so the very first request carries them. Each cookie needs at least a name and value, plus a domain or url so the browser knows where it applies.

The two SDKs differ here by inheritance: TypeScript follows Puppeteer's setCookie(...cookies) varargs, while Python follows Playwright's add_cookies([...]) with a single sequence.

const page = await browser.newPage();

// Before goto(), so the first request is already authenticated.
await page.setCookie(
{ name: "session", value: SAVED_SESSION_VALUE, domain: "example.com" },
{ name: "csrf", value: SAVED_CSRF_VALUE, domain: "example.com" },
);

await page.goto("https://example.com/dashboard");
console.log(await page.url());

Response, landing on the dashboard rather than being bounced to the login:

https://example.com/dashboard

Cookies also accept path, expires, httpOnly, secure, sameSite, and priority. Copy those through from what cookies() returned rather than guessing, since a session cookie recreated without its original secure or sameSite flags may be rejected or ignored.

When the credential is a password rather than a cookie, and you'd rather it never touch your script, see loading secrets instead.

Set the user agent

setUserAgent() replaces the string the browser reports. On stealth sessions, leave it alone unless you have a specific reason: Browserless manages a coherent fingerprint, and a hand-set user agent that disagrees with the rest of it is easier to detect than the default.

await page.setUserAgent("MyCrawler/1.0 (+https://example.com/bot)");
await page.goto("https://example.com");

Identifying yourself honestly is the right move on sites you own or whose crawl policy you're respecting. For sites that block automation, stealth and humanization is the relevant guide.

Load HTML directly

setContent() puts your own markup in the page instead of navigating. It's how you render a template to a PDF or screenshot without hosting it anywhere first.

await page.setContent("<h1>Invoice 1042</h1><p>Paid in full.</p>");
await page.pdf({ path: "invoice.pdf", format: "a4", printBackground: true });

Relative URLs in that markup have no origin to resolve against, so reference images, styles, and scripts absolutely, or inline them.

Inject scripts and styles

addScriptTag() and addStyleTag() add a <script> or <style> to the current page, from a url, a local path, or inline content. Injected styles are the practical way to hide cookie banners or sticky headers before a screenshot.

// Hide chrome that would otherwise cover the screenshot.
await page.addStyleTag({ content: ".cookie-banner, .sticky-nav { display: none !important; }" });

// Load a helper library into the page.
await page.addScriptTag({ url: "https://cdn.example.com/helper.js" });

Inline content must be a single line, because the BrowserQL server rejects multi-line content. Host the script and pass url instead, or collapse the source to one line, which only works when it has no newline-sensitive syntax such as // comments or multi-line template literals.

Disable JavaScript

setJavaScriptEnabled(false) loads pages without running their scripts. Server-rendered content arrives faster and cheaper, and ad and tracking scripts never execute. Anything client-rendered will be missing, so this only suits sites whose content is in the initial HTML.

await page.setJavaScriptEnabled(false);
await page.goto("https://example.com/article");

const { text } = await page.text({ selector: "article" });

FAQ & Troubleshooting

My injected cookies didn't log me in

Three usual causes: they were set after goto() rather than before, the domain doesn't match the site (including the leading-dot and subdomain rules), or flags like secure and sameSite were dropped when you recreated the cookie. Copy every field through from what cookies() returned.

Is storing session cookies safe?

They're live credentials, so treat them like passwords: keep them in your secret store rather than in source, and expect them to expire. For password-based logins where you'd rather the credential never reach your code, use loadSecret().

Images and CSS are missing after setContent()

Relative URLs have no origin to resolve against when the markup didn't come from a navigation. Use absolute URLs, or inline the assets as data URIs.

Should I set a custom user agent on stealth sessions?

Usually not. Browserless manages a coherent fingerprint on the stealth endpoint, and a user agent that contradicts the rest of it stands out more than the default. Set one when you're identifying your crawler to a site that expects it.

Next steps

Was this page helpful?