Using puppeteer-humanize for Web Scraping: 2025 Guide

Explore why puppeteer-humanize enhances web scraping by mimicking human actions to bypass user behavior analytics.
11 min read
Puppeteer humanize web scraping

In this article, you will learn:

  • Why vanilla Puppeteer is not enough against user behavior analytics.
  • What puppeteer-humanize is and how it helps overcome those limitations.
  • How to use it for web scraping in a step-by-step tutorial section.
  • The remaining challenges with this approach to scraping web data.

Let’s dive in!

User Behavior Analytics: Why Standard Puppeteer Falls Short

User behavior analytics (UBA) is the process of collecting and analyzing data on how users interact with a web page. In web scraping, its primary goal is to spot anomalous or suspicious behavior to identify bots.

This sophisticated anti-bot technique is gaining popularity. The reason is that modern AI-powered bots are continuously evolving to become more human-like. Thus, traditional bot-detection methods may no longer be effective against them.

To counter UBA, some automation libraries attempt to mimic human behavior more realistically. For example, they simulate mouse movements using heuristics or even machine learning. Yet, typing still tends to appear robotic in most cases, which is a problem.

Now, assume that your Puppeteer script needs to fill out a form. Even if you add a small delay between keystrokes using the type() function, that interaction would not appear natural.

Take the login form at Quotes to Scrape as an example:

import puppeteer from "puppeteer";

(async () => {
  // set up a new browser instance in headful mode
  const browser = await puppeteer.launch({
    headless: false, // set to false so you can watch the interaction
    defaultViewport: null,
  });
  const page = await browser.newPage();

  // connect to the target page
  await page.goto("https://quotes.toscrape.com/login");

  // simulate typing with a delay of 200ms between each character
  await page.type("input[name=\"username\"]", "username", { delay: 200 });
  await page.type("input[name=\"password\"]", "password", { delay: 200 });

  // ...

  // close the browser and release its resources
  await browser.close();
})();

This is what the interaction would look like:

The Puppeteer bot-like interaction

Even though the above approach is more realistic than simply setting the value of the input fields directly, it still does not look human. The problem is that the typing appears too smooth, consistent, and error-free. Ask yourself—what real user types every character at the exact same interval, without hesitation or typos?

As you can imagine, advanced UBA systems can easily spot such scripts. This is where tools like puppeteer-humanize come into play!

What Is puppeteer-humanize?

puppeteer-humanize is a Node.js library that makes Puppeteer automation more human-like, specifically when interacting with text input fields. It helps bypass common bot detection methods that analyze user behavior, which often flag unrealistic or overly precise actions.

To achieve that, puppeteer-humanize injects realistic imperfections into regular Puppeteer interactions by:

  1. Simulating typographical errors.
  2. Mimicking the use of the backspace key to correct those mistakes.
  3. Retyping deleted text with random delays.
  4. Introducing random delays between keystrokes to vary typing speed.

This makes automated typing appear more natural and less mechanical. However, it is important to note that the library focuses only on humanizing typing behavior and form inputs. So, it is not a comprehensive anti-bot bypass solution.

Also, keep in mind that its last commit was in 2021, and it does not yet support advanced features like GAN-based mouse movement simulation. Therefore, its scope remains limited to typing behavior only.

How to Use puppeteer-humanize for Web Scraping

Follow the steps below to learn how to use puppeteer-humanize to build a more human-like scraping bot. This reduces the chances of being detected by UBA systems, especially when your script needs to type data into forms.

The target will be the login form at Quotes to Scrape:

This example will purely be for demonstrating how to simulate realistic form filling. In real-world scraping scenarios, avoid scraping content behind login forms unless you have explicit permission, as that may raise legal concerns.

Now, let’s see how to use puppeteer-humanize for web scraping!

Step #1: Project Setup

If you do not already have a Node.js project set up, you can create one in your project folder with npm init:

npm init -y

The above command will generate a package.json file in your project directory. Inside the project folder, create a script.js file, which is where you will place your JavaScript scraping logic:

your-project-folder/
├── package.json
└── script.js

Next, open the folder in your favorite JavaScript IDE. Visual Studio Code will work perfectly.

In your IDE, modify the package.json file to include the following line:

"type": "module"

This sets your project to use ESM (ECMAScript Modules), which is generally recommended for modern Node.js projects over the standard CommonJS format.

Great! You are now ready to take advantage of puppeteer-humanize to simulate realistic interactions in your scraping scripts.

Step #2: Install and Get Started with puppeteer-humanize

While puppeteer-humanize was originally a plugin for Puppeteer Extra, that is no longer the case. So, to use it, you just need to install:

Install them both with the following command:

npm install @forad/puppeteer-humanize puppeteer

Next, open your script.js file and initialize a basic Puppeteer script like this:

import puppeteer from "puppeteer";

(async () => {
  // set up a new browser instance in headful mode
  const browser = await puppeteer.launch({
    headless: false, // set to false so you can watch the interaction
    defaultViewport: null,
  });
  const page = await browser.newPage();

  // ...

  // close the browser and release its resources
  await browser.close();
})();

Fantastic! You can now start implementing your human-looking scraping interactions.

Step #3: Connect to the Target Page and Select the Input Elements

Use Puppeteer to navigate to the target page:

await page.goto("https://quotes.toscrape.com/login");

Now, open the same page in your browser, right-click on the login form, and select “Inspect” to examine the form elements:

You will notice that the form contains:

  • A username input field you can select with input[name="username"]
  • A password input field you can select with input[name="password"]

To select these input elements in your script, use Puppeteer’s $() method:

const usernameInput = await page.$("input[name=\"username\"]");
const passwordInput = await page.$("input[name=\"password\"]");

⚠️ Important: puppeteer-humanize does not work with locators. That means you must use $() or $$() to retrieve element handles directly.

If both inputs are found on the page, prepare to interact with them just like a real user would:

if (usernameInput && passwordInput) {
  // interaction...
}

Wonderful! It is time to fill in those inputs as if you were a real user.

Step #4: Configure the puppeteer-humanize Typing Function

First, import the typeInto function from puppeteer-humanize:

import { typeInto } from "@forad/puppeteer-humanize";

Then, use it to configure a human-like form-filling interaction, as shown below:

const typingConfig = {
  mistakes: {
    chance: 10, // 10% chance of introducing a typo that gets corrected
    delay: {
      min: 100, // minimum delay before correcting a mistake (in ms)
      max: 500, // maximum delay before correcting a mistake (in ms)
    },
  },
  delays: {
    all: {
      chance: 100, // 100% chance to add delay between each keystroke
      min: 100, // minimum delay between characters (in ms)
      max: 200, // maximum delay between characters (in ms)
    },
  },
};

// strings to fill into the input elements
const username = "username";
const password = "password";

// apply the human-like typing logic to both inputs
await typeInto(usernameInput, username, typingConfig);
await typeInto(passwordInput, password, typingConfig);

The above typing config:

  • Occasionally introduces typos, followed by realistic corrections—just like a real user would do.
  • Adds random delays between each keystroke, mimicking natural typing speed variation.

That behavior makes your automation look far more human, limiting the chances of detection by UBA technologies.

Terrific! Your Puppeteer script should now behave much more like a real human.

Step #5: Fill Out the Form and Get Ready for Web Scraping

You can now fill out the form using the code below:

const submitButton = page.locator("input[type=\"submit\"]");
await submitButton.click();

Keep in mind that the login form on Quotes to Scrape is just a test page. In detail, you can access it with the username and password credentials. Once you submit the form, you will be redirected to a page containing the data you might want to scrape:

Submitting the login form

At that point, you can use the regular Puppeteer API to implement the actual scraping logic:

// wait for the page to load
await page.waitForNavigation();

// scraping logic...

Now, the focus of this article is puppeteer-humanize. So, we will not cover the scraping part here.
If you are interested in scraping data from Quotes to Scrape and exporting it to CSV, read our full tutorial on web scraping with Puppeteer.

Step #6: Put It All Together

Your script.js should now contain:

import puppeteer from "puppeteer";
import { typeInto } from "@forad/puppeteer-humanize";

(async () => {
  // set up a new browser instance in headful mode
  const browser = await puppeteer.launch({
    headless: false, // set to false so you can watch the interaction
    defaultViewport: null,
  });
  const page = await browser.newPage();

  // visit the target page
  await page.goto("https://quotes.toscrape.com/login");

  // select the login form inputs
  const usernameInput = await page.$("input[name=\"username\"]");
  const passwordInput = await page.$("input[name=\"password\"]");

  // if they are not both null, interact with them
  if (usernameInput && passwordInput) {
    // configure the typing behavior
    const typingConfig = {
      mistakes: {
        chance: 10, // 10% chance of introducing a typo that gets corrected
        delay: {
          min: 100, // minimum delay before correcting a mistake (in ms)
          max: 500, // maximum delay before correcting a mistake (in ms)
        },
      },
      delays: {
        all: {
          chance: 100, // 100% chance to add delay between each keystroke
          min: 100, // minimum delay between characters (in ms)
          max: 200, // maximum delay between characters (in ms)
        },
      },
    };

    // test strings to fill into the input elements
    const username = "username";
    const password = "password";

    // apply the human-like typing logic to both inputs
    await typeInto(usernameInput, username, typingConfig);
    await typeInto(passwordInput, password, typingConfig);

    // submit the form
    const submitButton = page.locator("input[type=\"submit\"]");
    await submitButton.click();

    // wait for the page to load
    await page.waitForNavigation();

    // scraping logic...
  }

  // close the browser and release its resources
  await browser.close();
})();

Launch the above puppeteer-humanize scraping script with:

node script.js

The result will be:

Note how natural the typing interaction is

As you can see, the Puppeteer bot now interacts with the login form in a much more natural way—just like a real human user would. It types at a realistic speed, occasionally makes typos, and then corrects them. That is the power of puppeteer-humanize!

Challenges to This Approach to Web Scraping

puppeteer-humanize is definitely a great ally to reduce the chances of being detected by technologies that analyze how users interact. Still, anti-scraping and anti-scraping and anti-bot techniques go far beyond just user behavior!

First, remember that Puppeteer must instrument the browser to control it programmatically. That introduces subtle changes and signs that can expose the browser as automated. To reduce these leaks, you should also consider using Puppeteer Stealth.

Even with both puppeteer-humanize and Puppeteer Stealth in place, you might still encounter CAPTCHAs during your interactions. In such cases, take a look at our article on CAPTCHA bypassing with Playwright.

While these tools and guides can help you build a more resilient scraping setup, many of the workarounds they rely on do not last forever. If you are dealing with sites that use highly sophisticated anti-bot solutions, your chances of success diminish significantly. Plus, adding multiple plugins can make your setup heavier on memory and disk usage, and harder to scale.

At that point, the problem is not just Puppeteer itself but rather the limitations of the browser it controls. The real breakthrough comes from integrating Puppeteer with a headful, cloud-based browser built specifically for web scraping. This solution includes built-in support for rotating proxies, advanced CAPTCHA solving, realistic browser fingerprints, and more. That is exactly what Bright Data’s Browser API is all about!

Conclusion

In this tutorial, you learned why vanilla Puppeteer falls short against user behavior analytics and how to address that with puppeteer-humanize. In particular, you saw how to integrate this approach into a web scraping workflow through a step-by-step tutorial.

While this method can help you bypass simple anti-bot systems, it does not guarantee a high success rate. That is especially true when scraping sites that rely on CAPTCHAs, IP bans, or modern, AI-powered anti-bot techniques. On top of that, scaling this setup can be complex.

If your goal is to make your scraping script—or even an AI agent—behave more like a real user, you should consider using a browser purpose-built for this use case: Bright Data’s Agent Browser.

Create a free Bright Data account to access our entire AI-ready scraping infrastructure!

Antonello Zanini

Technical Writer

5.5 years experience

Antonello Zanini is a technical writer, editor, and software engineer with 5M+ views. Expert in technical content strategy, web development, and project management.

Expertise
Web Development Web Scraping AI Integration