Skip to main content

User Data Directory for persisting sessions

The --user-data-dir flag in browserless allows you to persist browser data such as cookies, localStorage, cache, and login sessions across multiple browser sessions. This is particularly useful for maintaining authenticated states and user preferences without having to re-authenticate or reconfigure settings each time.

note

The --user-data-dir feature is only available for Enterprise plans with dedicated fleets. It cannot be used with shared plans.

Important details when implementing User Data Directories

The directory will be created if it doesn't exist. When using --user-data-dir, make sure to use a unique directory path for each different browser profile you want to maintain. You can only instantiate one browser per userdatadir at a time, meaning it's 1-1 and you can't use the same path in the flag for multiple concurrent browsers.

Pointing to a specific dedicated worker on Enterprise plans

User data directories are stored locally on each worker's file system and do not sync across your fleet. For example, a browser instance using --user-data-dir=~/u/1 on Worker #1 will not be accessible from Worker #2. No need to worry! Browserless allows you to point at a specific worker by using the endpoint provided on your account page under "Production" Clusters. Click on the cell under the Address column to copy the endpoint for the worker you need. You'll want to keep track of which browser session was persisted initially on which worker to ensure consistent access.

  • Your BQL endpoints would change from https://chrome.browserless.io/bql to something like https://chrome.browserless.io/p/53616c7465645f5ff8cc738d5eecb3032823d67e37578fe4531b0f9a83dc80856c66d0fe36aba4d2f4bc5f01c18bdfab/bql?token=YOUR_API_TOKEN_HERE&--user-data-dir=~/custompath/123
  • Your websocket connections would change from wss://chrome.browserless.io/chromium to something like wss://chrome.browserless.io/p/53616c7465645f5ff8cc738d5eecb3032823d67e37578fe4531b0f9a83dc80856c66d0fe36aba4d2f4bc5f01c18bdfab/chromium?token=YOUR_API_TOKEN_HERE&--user-data-dir=~/custompath/456

Using the userdatadir with Puppeteer and Playwright

The following examples demonstrate how to use the --user-data-dir flag with both Puppeteer and Playwright. These examples show how to persist a login session to browserless.io - once you log in and close the tab, running the script again will show you already logged in.

import puppeteer from 'puppeteer-core';

const launchArgs = {
headless: false,
args: ['--user-data-dir=~/u/1']
};

const queryParams = new URLSearchParams({
token: "YOUR_API_TOKEN_HERE", //this script using userdatadir only works for dedicated machines
timeout: 300000,
launch: JSON.stringify(launchArgs)
}).toString();

(async () => {
let browser;
try {
browser = await puppeteer.connect({
browserWSEndpoint: `wss://chrome.browserless.io/chromium?${queryParams}`,
defaultViewport: null
});

console.log('Connected');

const page = await browser.newPage();
await page.goto('https://account.browserless.io/', {
waitUntil: 'domcontentloaded'
});

console.log('Navigated');

const client = await page.target().createCDPSession();
const { liveURL } = await client.send('Browserless.liveURL', {
timeout: 300000
});

console.log('Click for live experience:', liveURL);

await new Promise((resolve) => {
client.on('Browserless.liveComplete', resolve);
});

console.log(`Live URL closed on page: ${page.url()}`);

await browser.close();
} catch (error) {
console.error('An error occurred:', error);
if (browser) {
await browser.close().catch(console.error);
}
throw error;
}
})().catch(error => {
console.error('Fatal error:', error);
});

Using with BrowserQL

The following example demonstrates how to use the --user-data-dir flag with BrowserQL to persist browser state. This example shows how to toggle dark mode on w3schools.com - each time you run it, the initial state will be different since it's persisting the toggle state from previous runs.

import puppeteer from 'puppeteer-core';

const url = 'https://www.browserless.io/';
const token = 'YOUR_API_TOKEN_HERE'; //this script using userdatadir only works for dedicated machines
const timeout = 5 * 60 * 1000;
const launchArgs = {
args: ['--user-data-dir=~/id-togle-test-123']
};
const queryParams = new URLSearchParams({
timeout,
token,
launch: JSON.stringify(launchArgs)
}).toString();

const query = `
mutation DarkModeToggle {
goto(url: "https://www.w3schools.com/", waitUntil: domContentLoaded) {
status
}
DarkModeClassBefore:evaluate(content: "document.body.className") {
value
}
click(selector:"#tnb-dark-mode-toggle-btn"){
time
}
DarkModeClassAfter:evaluate(content: "document.body.className") {
value
}
}
`;

const variables = { url };

const endpoint =
`https://chrome.browserless.io/chromium/bql?${queryParams}`;

const options = {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
query,
}),
};

try {
console.log(`Running BQL Query: ${url}`);

const response = await fetch(endpoint, options);

if (!response.ok) {
throw new Error(`Got non-ok response:\n` + (await response.text()));
}

const { data } = await response.json();

console.log("Full response data:", JSON.stringify(data, null, 2));

if (data && data.DarkModeClassBefore && data.DarkModeClassAfter) {
console.log("Dark mode toggle results:");
console.log("Before:", data.DarkModeClassBefore.value);
console.log("After:", data.DarkModeClassAfter.value);
console.log("Click time:", data.click.time, "ms");
} else {
console.log("Unexpected response structure:", data);
}
} catch (error) {
console.error(error);
}