npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@onivoro/server-puppeteer

v24.33.11

Published

A NestJS module providing Puppeteer integration with stealth plugin support for browser automation.

Readme

@onivoro/server-puppeteer

A NestJS module providing Puppeteer integration with stealth plugin support for browser automation.

Installation

npm install @onivoro/server-puppeteer

Overview

This library provides:

  • NestJS module for Puppeteer integration
  • Stealth plugin enabled by default to avoid detection
  • Singleton browser instance management
  • Convenient page usage patterns
  • Mock module for testing

Module Setup

import { ServerPuppeteerModule, ServerPuppeteerConfig } from '@onivoro/server-puppeteer';

const config = new ServerPuppeteerConfig();
config.headless = true;
config.executablePath = '/path/to/chrome'; // optional

@Module({
  imports: [
    ServerPuppeteerModule.configure(config)
  ]
})
export class AppModule {}

Configuration

The ServerPuppeteerConfig class accepts standard Puppeteer launch options:

export class ServerPuppeteerConfig {
  executablePath?: string;    // Path to Chrome/Chromium executable
  headless?: boolean;         // Run in headless mode
  devtools?: boolean;         // Open DevTools automatically
  defaultViewport?: {         // Default viewport size
    width: number;
    height: number;
  };
}

Usage

PuppeteerService

The main service provides methods for browser automation:

import { Injectable } from '@nestjs/common';
import { PuppeteerService } from '@onivoro/server-puppeteer';

@Injectable()
export class WebScraperService {
  constructor(private puppeteerService: PuppeteerService) {}

  async scrapeData(url: string) {
    return this.puppeteerService.usePage(async (page) => {
      // Your automation logic here
      await page.waitForSelector('.data-element');
      const data = await page.$eval('.data-element', el => el.textContent);
      return data;
    }, url);
  }
}

API Reference

PuppeteerService

usePage(fn, url?)

Execute a function with a new page, automatically closing it afterwards:

const result = await puppeteerService.usePage(async (page) => {
  await page.click('#submit-button');
  await page.waitForNavigation();
  return await page.title();
}, 'https://example.com');

Parameters:

  • fn: (page: Page) => Promise<string> - Function to execute with the page
  • url?: string - Optional URL to navigate to before executing the function

Returns: Promise<string> - The result from the function

Protected Methods

These methods are available when extending PuppeteerService:

extractPageBody(url)

Extract the text content of a page's body:

const bodyText = await this.extractPageBody('https://example.com');
extractPageBodyAsObject<T>(url)

Extract and parse JSON from a page's body:

interface ApiResponse {
  data: string[];
}

const response = await this.extractPageBodyAsObject<ApiResponse>('https://api.example.com/data');

Browser Instance

The module provides a singleton Browser instance that can be injected:

import { Injectable } from '@nestjs/common';
import { Browser } from 'puppeteer';

@Injectable()
export class CustomService {
  constructor(private browser: Browser) {}

  async createNewPage() {
    return await this.browser.newPage();
  }
}

launchBrowser Function

Low-level function to launch a browser with stealth plugin:

import { launchBrowser } from '@onivoro/server-puppeteer';

const browser = await launchBrowser({
  headless: true,
  executablePath: '/usr/bin/google-chrome'
});

Testing

Use the mock module for testing:

import { ServerPuppeteerMockModule } from '@onivoro/server-puppeteer';

const module = await Test.createTestingModule({
  imports: [ServerPuppeteerMockModule]
}).compile();

Complete Example

import { Injectable } from '@nestjs/common';
import { PuppeteerService } from '@onivoro/server-puppeteer';

@Injectable()
export class FormAutomationService {
  constructor(private puppeteerService: PuppeteerService) {}

  async submitForm(formData: any) {
    return this.puppeteerService.usePage(async (page) => {
      // Set viewport
      await page.setViewport({ width: 1920, height: 1080 });
      
      // Fill form
      await page.type('#name', formData.name);
      await page.type('#email', formData.email);
      await page.select('#country', formData.country);
      
      // Submit
      await page.click('#submit');
      
      // Wait for confirmation
      await page.waitForSelector('.success-message');
      const message = await page.$eval('.success-message', el => el.textContent);
      
      // Take screenshot
      await page.screenshot({ path: 'confirmation.png' });
      
      return message;
    }, 'https://example.com/form');
  }

  async scrapeProductData(productUrl: string) {
    return this.puppeteerService.usePage(async (page) => {
      // Wait for content to load
      await page.waitForSelector('.product-info');
      
      // Extract data
      const productData = await page.evaluate(() => {
        return {
          title: document.querySelector('.product-title')?.textContent?.trim(),
          price: document.querySelector('.product-price')?.textContent?.trim(),
          description: document.querySelector('.product-description')?.textContent?.trim(),
          images: Array.from(document.querySelectorAll('.product-image img'))
            .map(img => img.getAttribute('src'))
        };
      });
      
      return JSON.stringify(productData);
    }, productUrl);
  }
}

Important Notes

  1. The browser instance is singleton - only one browser is launched per application
  2. Pages are automatically closed after use with usePage() method
  3. Stealth plugin is automatically applied to avoid detection
  4. The extractPageBody method includes a random delay (2-12 seconds) before extraction
  5. Always handle errors appropriately as page operations can fail

License

MIT