Advanced Hybrid Automation Configurations
This page is the comprehensive reference for all Browserless.liveURL options and advanced patterns. It covers bandwidth tuning, viewport control, programmatic session management, recording integration, CAPTCHA fallback handling, multi-stage workflows, and error recovery.
If you are new to hybrid automation, start with the Hybrid Automation guide.
Bandwidth and Quality Optimization
Fine-tune live sessions for different network conditions and device capabilities.
- Puppeteer
- Playwright
const { liveURL } = await cdp.send('Browserless.liveURL', {
quality: 30, // Optimized for mobile/slow connections
type: 'jpeg', // Better compression than PNG
timeout: 300000, // 5 minutes for complex workflows
});
const { liveURL } = await cdpSession.send('Browserless.liveURL', {
quality: 30, // Optimized for mobile/slow connections
type: 'jpeg', // Better compression than PNG
timeout: 300000, // 5 minutes for complex workflows
});
Advanced Viewport Control
Control viewport behavior and browser UI visibility for live sessions.
By default, the live URL viewport resizes to match the end user's screen. Set resizable: false to lock the browser at its current viewport dimensions. The live URL client preserves the aspect ratio.
- Puppeteer
- Playwright
const { liveURL } = await cdp.send('Browserless.liveURL', {
resizable: false, // Maintain fixed viewport
interactable: true, // Allow user interaction
showBrowserInterface: false, // Hide browser tabs and UI
});
const { liveURL } = await cdpSession.send('Browserless.liveURL', {
resizable: false, // Maintain fixed viewport
interactable: true, // Allow user interaction
showBrowserInterface: false, // Hide browser tabs and UI
});
Multi-Tab Workflows
For workflows involving multiple tabs or separate windows, set showBrowserInterface: true to stream all open tabs. End users can switch between tabs as needed. This option injects UI overlay code into the page, which may increase CAPTCHA challenge likelihood on some sites.
- Puppeteer
- Playwright
const { liveURL } = await cdp.send('Browserless.liveURL', {
showBrowserInterface: true, // Show all tabs and browser UI
quality: 50,
timeout: 300000, // 5 minutes for complex workflows
});
const { liveURL } = await cdpSession.send('Browserless.liveURL', {
showBrowserInterface: true, // Show all tabs and browser UI
quality: 50,
timeout: 300000, // 5 minutes for complex workflows
});
Programmatic Session Management
Take full control over when and how sessions end. The Browserless.closeLiveURL command lets your script close a live session based on page state, while Browserless.liveComplete fires when a user closes the session manually.
- Puppeteer
const cdp = await page.createCDPSession();
const { liveURL, liveURLId } = await cdp.send('Browserless.liveURL', {
timeout: LIVE_URL_TIMEOUT
});
console.log('Click for live experience:', liveURL);
const completionPromise = Promise.race([
// Scenario 1: User closes LiveURL manually
new Promise(resolve => cdp.on('Browserless.liveComplete', () => {
console.log('Live URL was closed by user');
resolve('user_closed');
})),
// Scenario 2: A selector appears, programmatically close LiveURL
page.waitForSelector('.someSelector', { timeout: 0 }).then(async () => {
console.log('Selector detected, closing LiveURL programmatically');
await cdp.send('Browserless.closeLiveURL', { liveURLId });
return 'selector_detected';
})
]);
completionPromise.then((result) => {
console.log(`LiveURL closed via: ${result}`);
console.log('Cleaning up browser...');
browser.close().then(() => {
console.log('Script completed successfully');
process.exit(0);
});
});
Read-Only Monitoring Sessions
Create view-only sessions for compliance monitoring or training by setting interactable: false. The viewer sees the browser but cannot click, type, or interact.
- Puppeteer
- Playwright
const { liveURL } = await cdp.send('Browserless.liveURL', {
interactable: false, // View-only mode
quality: 80, // Higher quality for monitoring
timeout: 1800000, // 30 minutes for extended monitoring
});
// Share with compliance team or supervisors
console.log('Monitoring URL (read-only):', liveURL);
const { liveURL } = await cdpSession.send('Browserless.liveURL', {
interactable: false, // View-only mode
quality: 80, // Higher quality for monitoring
timeout: 1800000, // 30 minutes for extended monitoring
});
// Share with compliance team or supervisors
console.log('Monitoring URL (read-only):', liveURL);
Session Recording Integration
Combine screen recording with live sessions to capture an audit trail. Set record=true as a query parameter when connecting to the browser endpoint. See Screen Recording for full details.
- Puppeteer
- Playwright
// Start recording before creating live session
await cdp.send('Browserless.startRecording');
const { liveURL } = await cdp.send('Browserless.liveURL', {
timeout: 300000
});
// Wait for session completion
await new Promise(resolve => cdp.on('Browserless.liveComplete', resolve));
// Save recording (see recording docs for details)
const recording = await cdp.send('Browserless.stopRecording');
fs.writeFileSync('audit-trail.webm', Buffer.from(recording.value, 'binary'));
// Start recording before creating live session
await cdpSession.send('Browserless.startRecording');
const { liveURL } = await cdpSession.send('Browserless.liveURL', {
timeout: 300000
});
// Wait for session completion
await new Promise(resolve => cdpSession.on('Browserless.liveComplete', resolve));
// Save recording (see recording docs for details)
const recording = await cdpSession.send('Browserless.stopRecording');
fs.writeFileSync('audit-trail.webm', Buffer.from(recording.value, 'binary'));
CAPTCHA Handling with Hybrid Fallback
Try automated CAPTCHA solving first, then fall back to a live URL for human intervention if the solver fails. Listen for the Browserless.captchaFound event to trigger this flow. For full CAPTCHA solver documentation, see CAPTCHA Solving.
- Puppeteer
- Playwright
// Set up CAPTCHA detection before navigation
cdp.on('Browserless.captchaFound', async () => {
console.log('CAPTCHA detected, attempting automatic solve');
const { solved } = await cdp.send('Browserless.solveCaptcha');
if (!solved) {
// Fall back to human intervention
const { liveURL } = await cdp.send('Browserless.liveURL', {
timeout: 120000 // 2 minutes for CAPTCHA solving
});
console.log('Manual CAPTCHA solving needed:', liveURL);
}
});
// Set up CAPTCHA detection before navigation
cdpSession.on('Browserless.captchaFound', async () => {
console.log('CAPTCHA detected, attempting automatic solve');
const { solved } = await cdpSession.send('Browserless.solveCaptcha');
if (!solved) {
// Fall back to human intervention
const { liveURL } = await cdpSession.send('Browserless.liveURL', {
timeout: 120000 // 2 minutes for CAPTCHA solving
});
console.log('Manual CAPTCHA solving needed:', liveURL);
}
});
Multi-Stage Workflows
Chain multiple hybrid sessions for complex business processes. Each stage alternates between automated steps and human handoffs.
- Puppeteer
- Playwright
const multiStageWorkflow = async () => {
const browser = await puppeteer.connect({
browserWSEndpoint: 'wss://production-sfo.browserless.io?token=YOUR_TOKEN'
});
try {
const page = await browser.newPage();
const cdp = await page.createCDPSession();
await page.goto('https://practice.expandtesting.com/inputs');
await page.waitForSelector('input[name="input-number"]');
// Stage 1: User fills the number input via liveURL
let { liveURL } = await cdp.send('Browserless.liveURL', {
timeout: 180000 // 3 minutes for number entry
});
console.log('Stage 1 - Enter a number:', liveURL);
await new Promise(resolve => cdp.on('Browserless.liveComplete', resolve));
// Stage 2: Automated filling of text and password fields
await page.type('input[name="input-text"]', 'Automated text entry');
await page.type('input[name="input-password"]', 'SecurePass123');
console.log('Stage 2 - Automated text and password fields completed');
// Stage 3: User fills the date input via liveURL
({ liveURL } = await cdp.send('Browserless.liveURL', {
timeout: 300000 // 5 minutes for date selection
}));
console.log('Stage 3 - Select a date:', liveURL);
await new Promise(resolve => cdp.on('Browserless.liveComplete', resolve));
console.log('Multi-stage workflow completed successfully');
} finally {
await browser.close();
}
};
const multiStageWorkflow = async () => {
const browser = await playwright.chromium.connectOverCDP(
'wss://production-sfo.browserless.io?token=YOUR_TOKEN'
);
try {
const context = browser.contexts()[0];
const page = await context.newPage();
const cdpSession = await context.newCDPSession(page);
await page.goto('https://practice.expandtesting.com/inputs');
await page.waitForSelector('input[name="input-number"]');
// Stage 1: User fills the number input via liveURL
let { liveURL } = await cdpSession.send('Browserless.liveURL', {
timeout: 180000 // 3 minutes for number entry
});
console.log('Stage 1 - Enter a number:', liveURL);
await new Promise(resolve => cdpSession.on('Browserless.liveComplete', resolve));
// Stage 2: Automated filling of text and password fields
await page.fill('input[name="input-text"]', 'Automated text entry');
await page.fill('input[name="input-password"]', 'SecurePass123');
console.log('Stage 2 - Automated text and password fields completed');
// Stage 3: User fills the date input via liveURL
({ liveURL } = await cdpSession.send('Browserless.liveURL', {
timeout: 300000 // 5 minutes for date selection
}));
console.log('Stage 3 - Select a date:', liveURL);
await new Promise(resolve => cdpSession.on('Browserless.liveComplete', resolve));
console.log('Multi-stage workflow completed successfully');
} finally {
await browser.close();
}
};
Error Recovery and Resilience
Implement retry logic for production hybrid automation. This helper retries on transient failures but exits immediately on permanent errors like invalid tokens or rate limits.
import puppeteer from 'puppeteer-core';
const createResilientLiveSession = async (cdp, options = {}) => {
const { timeout = 300000, quality = 50, maxRetries = 2 } = options;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const { liveURL, liveURLId } = await cdp.send('Browserless.liveURL', {
timeout,
quality,
type: 'jpeg'
});
console.log(`Live session created on attempt ${attempt}`);
return { liveURL, liveURLId };
} catch (error) {
console.log(`Live session attempt ${attempt} failed:`, error.message);
// Don't retry on permanent errors
if (error.message.includes('Invalid token') ||
error.message.includes('Rate limit exceeded')) {
throw error;
}
if (attempt === maxRetries) {
throw new Error(`Failed to create live session after ${maxRetries} attempts: ${error.message}`);
}
// Brief wait before retry
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
};
(async () => {
let browser = null;
try {
const BROWSERLESS_TOKEN = 'YOUR_API_TOKEN_HERE';
browser = await puppeteer.connect({
browserWSEndpoint: `wss://production-sfo.browserless.io?token=${BROWSERLESS_TOKEN}`,
});
const page = await browser.newPage();
await page.goto('https://practicetestautomation.com/practice-test-login/');
const cdp = await page.createCDPSession();
const { liveURL, liveURLId } = await createResilientLiveSession(cdp, {
timeout: 300000,
quality: 50,
maxRetries: 3
});
console.log('Live URL created:', liveURL);
console.log('Live URL ID:', liveURLId);
await new Promise((resolve) => {
cdp.on('Browserless.liveComplete', resolve);
});
console.log('Live session completed');
} catch (error) {
console.error('Error:', error);
} finally {
if (browser) {
await browser.close();
}
}
})();