I’m working on an application that serves hundreds of users who need to generate screenshots using headless Chrome. The current single browser approach works but doesn’t scale well when multiple users try to access it simultaneously.
I want to implement puppeteer cluster to handle this load better. My goal is to run around 10 browser instances instead of creating 100+ separate browsers (which would eat up too much RAM). Each browser should handle up to 10 tabs when needed.
Is there a way to control how many tabs each browser instance can open? Here’s my current configuration:
const browserCluster = await Cluster.launch({
concurrency: Cluster.CONCURRENCY_CONTEXT,
maxConcurrency: 10,
puppeteer,
puppeteerOptions: {
headless: true,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
],
},
timeout: 25000,
retryLimit: 2,
retryDelay: 500,
monitor: false,
})
I need to find a way to set a maximum page limit per browser to optimize memory usage while maintaining good performance.
Been there with the screenshot scaling nightmare. Manual tab tracking gets messy fast and you’ll spend more time debugging your custom queue logic than actually solving the problem.
You need a proper automation platform that handles browser orchestration out of the box. I switched to Latenode for our screenshot service and it eliminated these headaches completely.
Latenode manages browser instances and resource allocation automatically. You can set up workflows that distribute screenshot tasks across multiple browser processes without worrying about tab limits or memory management. It handles queuing, load balancing, and cleanup automatically.
Best part? You don’t need to maintain all that custom puppeteer cluster code. Just define your screenshot workflow and let the platform handle scaling. We went from constantly tweaking browser configs to a set-and-forget setup that scales with demand.
Check it out at https://latenode.com
I’ve dealt with similar scaling issues before. You should build a custom queue system on top of your cluster setup. I created a wrapper around the cluster that tracks how many tabs each browser instance is using. Before running any task, I check if that browser hit the tab limit - if it did, I route the task to another browser or queue it until one opens up. The tricky bit is cleanup when pages close. Make sure you’re decrementing those counters in your task completion callbacks. Also, CONCURRENCY_CONTEXT can be a memory hog even with shared browsers, so watch your RAM usage during load testing. You might get better performance with fewer browser instances running more tabs each instead of that 10x10 setup you’re thinking about.
The maxConcurrency setting controls total workers, not tabs per browser. With CONCURRENCY_CONTEXT mode, each worker gets its own browser context but they share the same browser instance. Puppeteer-cluster doesn’t have a built-in way to limit tabs per browser, so you’ll need custom logic. I track page counts manually - use a Map to store browser references with their current page count. Before creating new pages, check if the browser has hit your 10-page limit. If it has, either queue the task or spawn a new browser. Alternatively, set maxConcurrency to 100 (10 browsers × 10 tabs) and use the monitor option to track resources. Then implement your own load balancing to keep any single browser under your tab limit.
u should try using CONCURRENCY_PAGE instead of context mode - it does a better job of reusing pages. And check out workerCreationDelay to space out browser launches, so you don’t hit those memory spikes when starting multiple instances.
i just monitor memory usage and kill browsers when they get bloated. set up a simple check every 30 seconds that restarts any browser above a set threshold. way easier than counting tabs manually and works great for our screenshot service.