Based on @ggorlen suggestion and a bunch of retry i finally get it to work. This is the base code that generates a red dot at where your mouse is. It will continue to follow your mouse where ever you take it and after 300 msec the red dot fade away, thus leaving a trail.
await page.evaluate(
"""
// First we create the styles
const style = document.createElement('style');
style.innerHTML = `
.cursor-trail {
position: fixed;
width: 10px; /* Size */
height: 10px;
background-color: red; /* Color */
border-radius: 50%;
pointer-events: none;
z-index: 10000;
opacity: 0.5;
transition: opacity 0.3s, transform 0.3s;
}
`;
document.head.appendChild(style);
// Then we append an event listener for the trail
document.addEventListener('mousemove', (event) => {
const trailDot = document.createElement('div');
trailDot.classList.add('cursor-trail');
document.body.appendChild(trailDot);
trailDot.style.left = `${event.clientX}px`;
trailDot.style.top = `${event.clientY}px`;
// after 300ms we fade out and remove the trail dot
setTimeout(() => {
trailDot.style.opacity = '0';
setTimeout(() => trailDot.remove(), 300);
}, 50);
});
"""
)
Then if you mix it with a function like this, playwright moves your cursor randomly and the red dot follows it ->
async def move_cursor_randomly(page: Page, duration: int = 10):
"""
Moves the cursor randomly within the viewport for the specified duration.
A cursor trail is drawn at each new cursor position.
"""
viewport_size = page.viewport_size
width = viewport_size["width"]
height = viewport_size["height"]
await page.evaluate(
"""
// First we create the styles
const style = document.createElement('style');
style.innerHTML = `
.cursor-trail {
position: fixed;
width: 10px; /* Size */
height: 10px;
background-color: red; /* Color */
border-radius: 50%;
pointer-events: none;
z-index: 10000;
opacity: 0.5;
transition: opacity 0.3s, transform 0.3s;
}
`;
document.head.appendChild(style);
// Then we append an event listener for the trail
document.addEventListener('mousemove', (event) => {
const trailDot = document.createElement('div');
trailDot.classList.add('cursor-trail');
document.body.appendChild(trailDot);
trailDot.style.left = `${event.clientX}px`;
trailDot.style.top = `${event.clientY}px`;
// after 300ms we fade out and remove the trail dot
setTimeout(() => {
trailDot.style.opacity = '0';
setTimeout(() => trailDot.remove(), 300);
}, 50);
});
"""
)
end_time = asyncio.get_event_loop().time() + duration
while asyncio.get_event_loop().time() < end_time:
x = min(random.randint(0, width), width)
y = min(random.randint(0, height), height)
await page.mouse.move(x, y, steps=random.randint(10, 30))
await asyncio.sleep(random.uniform(1, 3))