# Puppeteer voting bot: what a 2020 demo shows

> Published 2026-10-26T00:42:01.749Z on https://youblog.app/p/puppeteer-voting-bot-what-a-2020-demo-shows/
> Source video: https://www.youtube.com/watch?v=i0G8XBfWV8I

A Puppeteer voting bot is a Node.js script that drives headless Chrome to click a vote button repeatedly. A Brazilian developer demonstrated one in December 2020, and the recording shows the real work is not the code but the retries, timeouts and request bookkeeping around a page that keeps interrupting the click path.

## Puppeteer voting bot: what the 2020 demo actually built

A Puppeteer voting bot is a Node.js script that opens Chrome in headless mode and repeats clicks on a page's vote control. The demonstration this article examines was published on 13 December 2020 by the Brazilian channel Dev doido, and it automates votes on a reality show page rather than a general-purpose site.

The stack in that video is small: [Puppeteer](https://pptr.dev/) for browser control, puppeteer-extra with the stealth plugin to mask automation signals, and npm-run-all to launch several Node instances at once. The host describes it as basic Puppeteer scraping and runs it from a local project folder with two URLs stored in a .env file.

The claim worth checking is not that the script works on the day it was recorded. It is that most of the effort went into waiting, retrying and confirming a response status. That pattern still applies to any browser automation aimed at a page you do not control.

The video is a 10-minute walkthrough on a channel with a small audience, so treat it as a first-hand demo (evidence class D), not a benchmark. No timing, success rate or server-side detection data is reported.

## Which tools does the demo stack together?

The demo combines four tools, each handling one job. [Node.js](https://nodejs.org/en) runs the script, Puppeteer talks to Chrome through the DevTools protocol, [puppeteer-extra](https://github.com/berstend/puppeteer-extra) loads the stealth plugin, and [npm-run-all](https://github.com/mysticatea/npm-run-all) starts several copies of the script in parallel.

Each piece has a narrow role, which makes the setup easy to audit.

### Puppeteer and puppeteer-extra

Puppeteer is a Node library that provides a high-level API to control Chrome or Chromium over the DevTools protocol. It is maintained by the Chrome DevTools team and documented at pptr.dev. The plugin architecture comes from puppeteer-extra, a separate community wrapper that lets you register plugins such as the stealth plugin named in the video.

### npm-run-all for parallel processes

npm-run-all runs multiple npm scripts in sequence or in parallel. The demo uses it to start many browser sessions, which is why the narrator says 16 Node instances will take a while and asks viewers to close other Chrome windows first.

| Tool | Job in the demo | Where it comes from |
| --- | --- | --- |
| Puppeteer | Opens pages, clicks elements, reads responses | Chrome DevTools team |
| puppeteer-extra | Loads the stealth plugin | Community package |
| npm-run-all | Starts several scripts at once | Community package |
| .env file | Stores the site URL and vote request URL | Local project config |

## How does the script find the photo and the vote button?

The script locates a participant by the name embedded in a photo's src attribute, clicks that photo, then waits for a vote button that changes as the page updates. Both targets are identified through page inspection rather than a fixed selector, which is why the demo spends time in Chrome's developer tools.

The narrator opens the page, inspects the photo element, and copies the name string, noting that surnames appear separated by hyphens. That string becomes the identifier the script searches for, and the same inspection step reveals the vote button.

- Read the page source to find the element that holds the participant name

- Confirm the name format, including hyphenated surnames

- Copy the vote button selector from the developer tools

- Record the vote request URL from the Network tab

The script's click sequence is wrapped in retry logic because the page serves ads that interfere with the intended target. The narrator says this directly: the code works by insistence because the site keeps putting advertising in front of the real goal.

## Why does headless mode still need a stealth plugin?

A headless browser can still be identified by the site it visits, which is why the demo loads a stealth plugin rather than relying on Puppeteer's defaults. The narrator states that the site is easily able to detect automation and that the plugin makes the request look like a normal Chrome session.

This is the most fragile part of the approach. [puppeteer-extra-plugin-stealth](https://github.com/berstend/puppeteer-extra/tree/master/packages/puppeteer-extra-plugin-stealth) patches a set of browser fingerprints, but its documentation is explicit that it is an arms race with detection vendors and does not guarantee undetectability.

The demo also sets a headless flag to true so no visible Chrome windows appear, and a viewport of 1366 by 768 so the page renders at a desktop size. The narrator explains the combination as hiding the browser locally while presenting normal headers to the server.

Treat any stealth claim as time-bound. Fingerprinting code changes, and a 2020 workaround is not evidence about what a site checks in 2026.

## What breaks when you run many votes in parallel?

Running many browser sessions at once is limited by the local machine, and the demo hits that limit live. The narrator launches 16 Node instances, warns that 16 Chrome processes will slow the machine, then reduces the run to a single instance to keep the recording short.

The script also carries three timing decisions that matter more than the click code.

1. A default timeout of 60 seconds for opening a browser, which the narrator calls reasonable and treats as a signal that a slow run is not efficient.

2. A three-second wait for the page to load, described in the video as generous for a slow site.

3. A one-second pause before retrying a click or a selector lookup, repeated until the element appears.

Those numbers are the narrator's choices on one machine in 2020, not tuned defaults. Copy the structure and measure your own timings.

## How does the script confirm a vote was accepted?

The script treats an HTTP response and its URL as the confirmation step, waiting for the response that matches the vote request URL stored in the environment file. The narrator checks the returned status and stops the run if it is not the expected success code, on the reasoning that continuing would waste time.

The Network tab supplies the vote request URL during setup. Once the script has that URL, it can wait for the matching response and read the status code, and the demo shows a status of 200 before the vote counter increments.

That check is thin. A successful status confirms the request was answered, not that the site counted the vote or that the same session will be accepted again. The demo does not test for server-side deduplication, account binding or rate limits.

The final loop never ends: it wraps the click sequence in a repeating block, prints the running vote total, and calls the voting function again.

## Where does Crazystack typescript fit, and what is the 2026 status?

Crazystack typescript is the TypeScript-focused material from [Crazystack](https://crazystack.com.br), a Brazilian programming education project, and it is not part of the 2020 demo's stack. The video uses plain JavaScript with Node; no TypeScript build step appears in the walkthrough.

That distinction matters when you rebuild the script. A TypeScript version needs a compile step or a runtime loader, and the Puppeteer API surface is the same either way. Puppeteer ships its own TypeScript type definitions, so the typing cost is low and the automation logic is unchanged.

Check current versions before copying anything. Puppeteer's documented installation and API are the primary reference, and package versions, Node requirements and default browser download behavior have changed since 2020. The demo is a historical snapshot (13 December 2020), not a current tutorial.

## Is automating a vote allowed?

Automating votes usually conflicts with a site's terms of service, and the demo does not address legality, consent, or the reality show's voting rules. Nothing in the video establishes permission, and no rule of the program is quoted.

This article describes a published technical demonstration. It does not recommend running vote automation against a live service, and the detection and rate-limiting measures such sites deploy are precisely what the retry code was written to work around.

If the goal is learning browser automation, apply the same techniques to a site you own or to a public sandbox. The technical lessons about waits, retries and response checks transfer without the policy problem.

## FAQ

- **What is a Puppeteer voting bot?** It is a Node.js script that controls headless Chrome through Puppeteer and repeats clicks on a page's vote control. The 2020 demo adds a stealth plugin and a parallel runner, and most of its code handles waiting and retries rather than the click itself.

- **Does Puppeteer run without a visible browser window?** Yes. Puppeteer launches Chrome with a headless flag so no window appears, and the demo sets a 1366 by 768 viewport to present a desktop page size to the server.

- **Is the stealth plugin reliable?** No guarantee exists. The stealth plugin's own documentation describes detection as an ongoing contest and does not promise that automation stays hidden. A 2020 workaround says nothing about what a site checks in 2026.

- **Why does the script wait three seconds after loading a page?** The narrator picks three seconds as a generous wait for a slow page load and adds a one-second pause before retrying clicks. Those values are choices made on one machine in 2020, not measured defaults.

- **What confirms that a vote was counted?** The script waits for the vote request URL and checks the response status, and the demo shows a 200. A 200 response confirms an answer, not that the site counted the vote, deduplicated the session, or accepted a repeat.

- **Can this be rewritten in TypeScript?** Yes, and the Crazystack typescript material at crazystack.com.br covers the language side. Puppeteer ships type definitions, so the automation logic stays the same while the build step changes.

- **What did the demo get wrong or leave out?** It shows no success rate, no server response breakdown beyond one 200, and no handling of accounts or cookies. It also runs 16 browsers on a local machine, which the narrator admits is too slow to demonstrate comfortably.

- **Is the 2020 code still current?** No. Puppeteer's installation, default browser download and API details have changed since December 2020. Use the current Puppeteer documentation for setup and keep the 2020 video as a structural example.

- **Is vote automation legal?** The demo does not discuss terms of service or program rules, and nothing in it establishes permission. Automating votes typically conflicts with a site's terms, and the author does not recommend running it against a live service.

## Turning a walkthrough into a written guide

A 10-minute screen recording can explain a retry loop, but the reasoning behind those waits and status checks is easier to follow when it is written down and searchable.

The same applies to your own videos. If you have explained a workflow, an interview, or a technical decision on YouTube, [Skala Blog](https://skalablog.com) turns that video into a written article you can review and publish.

[Source video](https://www.youtube.com/watch?v=i0G8XBfWV8I)
