Skip to main content
Version: v2

Hybrid Automation Configurations

This page covers advanced hybrid automation configurations for users who have already established basic hybrid automation workflows. If you haven't set up basic hybrid automation yet, start with our Hybrid Automation guide.

Below are some advanced configurations and patterns you can explore:

Bandwidth and Quality Optimization

Fine-tune your live sessions for different network conditions and device capabilities:

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
});

Advanced Viewport Control

For applications requiring precise viewport management:

const { liveURL } = await cdp.send('Browserless.liveURL', {  
resizable: false, // Maintain fixed viewport
interactable: true, // Allow user interaction
showBrowserInterface: false, // Show/hide browser tabs and UI
});

By default, the live URL viewport is responsive to the end user's screen size. When you set resizable: false, the browser maintains its current viewport dimensions and the live URL client preserves the appropriate aspect ratio.

Programmatic Session Management

Take full control over when and how sessions end:

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: Some selector appears, programmatically close LiveURL
page.waitForSelector('.someSelector',{timeout: 0}).then(async () => {
console.log('Some selector detected, closing LiveURL programmatically');
await cdp.send('Browserless.closeLiveURL', { liveURLId });
return 'selector_detected';
})
]);

// Set up non-blocking listeners for LiveURL closure
completionPromise.then((result) => {
console.log(`LiveURL closed via: ${result}`);
console.log('Cleaning up browser...');
browser.close().then(() => {
console.log('Script completed successfully - exiting');
process.exit(0);
});
});

Read-Only Monitoring Sessions

Create view-only sessions for compliance monitoring or training:

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);

Session Recording Integration

For detailed recording capabilities, you must set record=true as a query parameter when connecting to the browser endpoint. See our Recording Sessions documentation for more details. Here's an example of session recording with live sessions:

// 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 for compliance (see recording docs for details)
const recording = await cdp.send('Browserless.stopRecording');
fs.writeFileSync('audit-trail.webm', Buffer.from(recording.value, 'binary'));

Bot Detection Integration

For advanced bot detection scenarios, combine hybrid automation with our stealth features and unblocking capabilities.

Multi-Stage Workflows

Chain multiple hybrid sessions for complex business processes:

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();

// Navigate to the practice form
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();
}
};

Error Recovery and Resilience

Implement robust error handling for production hybrid automation environments:

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 successfully on attempt ${attempt}`);
return { liveURL, liveURLId };

} catch (error) {
console.log(`Live session attempt ${attempt} failed:`, error.message);

// Don't retry on certain error types that won't benefit from retries
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));
}
}
};

// Main execution function
(async () => {
let browser = null;

try {
// Replace with your actual Browserless token
const BROWSERLESS_TOKEN = 'YOUR_API_TOKEN_HERE';

// Connect to Browserless
browser = await puppeteer.connect({
browserWSEndpoint: `wss://production-sfo.browserless.io?token=${BROWSERLESS_TOKEN}`,
});

const page = await browser.newPage();
await page.goto('https://example.com');

// Create CDP session for Browserless API access
const cdp = await page.createCDPSession();

// Use your resilient function
const { liveURL, liveURLId } = await createResilientLiveSession(cdp, {
timeout: 300000, // 5 minutes
quality: 50, // Medium quality for bandwidth optimization
maxRetries: 3 // Try up to 3 times
});

console.log('Live URL created:', liveURL);
console.log('Live URL ID:', liveURLId);

// Wait for user to complete their interaction
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();
}
}
})();

Next Steps

Ready to explore more advanced configurations? Continue your journey with these essential topics: