I’m using Puppeteer and creating a CDP (Chrome DevTools Protocol) session with page.target().createCDPSession() to simulate user gestures.
let browser = await puppeteer.launch(options);
const page = await browser.newPage();
const session = await page.target().createCDPSession();
await session.send('Input.synthesizeScrollGesture', {
x: 100,
y: 200,
yDistance: -150
});
The issue: if I call page.close() while the scroll gesture or any CDP command is still running, Puppeteer crashes with errors like:
TargetCloseError: Protocol error (Input.synthesizeScrollGesture): Target closed
I’m looking for a safe way to detach or clean up CDP sessions before closing the page to prevent these errors.
Has anyone figured out a reliable method or sequence to gracefully end CDP sessions before calling page.close() when using puppeteer.createCDPSession?
I ran into the same crash while automating scroll gestures. What helped me was explicitly detaching the CDP session before closing the page.
You can call:
await session.detach();
await page.close();
This ensures the CDP connection is released first. Also, make sure no pending commands are running - for example, wait for the scroll gesture to complete or wrap it with a small delay using await new Promise(r => setTimeout(r, 200)); before closing.
In short:
-
Send your CDP commands
-
Wait for them to finish
-
Then call session.detach()
-
Finally close the page
That sequence completely stopped the TargetCloseError in my scripts.
This happens because the page is closed while the DevTools session is still processing commands.
Puppeteer doesn’t auto-detach CDP sessions, so it’s up to you to clean up.
What I do is wrap my CDP actions in a try…finally block:
const session = await page.target().createCDPSession();
try {
await session.send('Input.synthesizeScrollGesture', { x: 100, y: 200, yDistance: -150 });
} finally {
await session.detach();
await page.close();
}
That way, even if something fails mid-command, you still detach cleanly before the page closes.
When I first saw the TargetCloseError, I thought it was a timing issue - and it was. The trick was to avoid closing the page while CDP was still active.
My final working flow:
-
Wait for the command to finish
-
Detach the session
-
Close the page
Something like this works smoothly:
await session.send('Input.synthesizeScrollGesture', { x: 100, y: 200, yDistance: -150 });
await session.detach();
await page.close();
If you have multiple sessions, detach them all before calling page.close(). After that, Puppeteer stops throwing the error.