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

@browsertotal/scanner

v1.0.9

Published

Scan URLs and extensions using BrowserTotal.com

Readme


Why BrowserTotal Scanner?

Real Browser Analysis - Unlike static analysis tools, BrowserTotal Scanner launches a real browser instance to analyze URLs and extensions exactly as they would execute in a user's environment. This catches threats that only activate in actual browser contexts.

Dynamic Behavior Tracing - Every network request, DOM manipulation, cookie access, and API call is traced and recorded. See what extensions and websites actually do, not just what their code looks like.

Sandboxed Execution - All analysis runs in an isolated, sandboxed browser environment. Test suspicious URLs and extensions safely without risking your system.

AI-Powered Threat Detection - Combines runtime behavior analysis with LLM-powered code review to identify obfuscated malware, data exfiltration, and sophisticated supply chain attacks.

Multi-Platform Coverage - Scan browser extensions (Chrome, Firefox, Edge, Safari, Opera, Brave), IDE plugins (VS Code, JetBrains), and packages (npm, PyPI, WordPress) - all through a unified API.


This package uses Puppeteer to automate browser interactions with BrowserTotal's analysis tools. It leverages a custom event system (#automationEvent=true) to receive complete scan results including AI/LLM analysis.

Supported Platforms

| Platform | Method | Description | |----------|--------|-------------| | URLs | scanUrl() | Scan any URL for security threats | | Chrome | scanExtension() | Chrome Web Store extensions | | Firefox | scanExtension() | Firefox Add-ons | | Edge | scanExtension() | Microsoft Edge Add-ons | | Opera | scanExtension() | Opera Add-ons | | Safari | scanExtension() | Safari Extensions | | Brave | scanExtension() | Brave Extensions | | VS Code | scanVSCodeExtension() | Visual Studio Marketplace extensions | | Open VSX | scanOpenVSXExtension() | Open VSX Registry extensions | | JetBrains | scanJetBrainsPlugin() | IntelliJ, PyCharm, WebStorm plugins | | npm | scanNpmPackage() | npm packages | | PyPI | scanPyPIPackage() | Python packages | | WordPress | scanWordPressPlugin() | WordPress plugins | | Hugging Face | scanHuggingFace() | Hugging Face models/spaces | | AppSource | scanAppSourceAddin() | Microsoft AppSource add-ins | | PowerShell | scanPowerShellModule() | PowerShell Gallery modules | | Salesforce | scanSalesforceApp() | Salesforce AppExchange apps |

Installation

npm install @browsertotal/scanner

Usage

Scanning URLs

import { BrowserTotalScanner } from '@browsertotal/scanner';

const scanner = new BrowserTotalScanner();

const result = await scanner.scanUrl('https://example.com');
console.log(result.status); // 'safe' | 'suspicious' | 'malicious' | 'unknown' | 'error'
console.log(result.threats);
console.log(result.raw); // Full analysis data including LLM results

await scanner.close();

Scanning Browser Extensions

import { BrowserTotalScanner } from '@browsertotal/scanner';

const scanner = new BrowserTotalScanner();

// Chrome extension
const chromeResult = await scanner.scanExtension('cjpalhdlnbpafiamejdnhcphjbkeiagm', 'chrome');

// Firefox add-on
const firefoxResult = await scanner.scanExtension('ublock-origin', 'firefox');

// Edge extension
const edgeResult = await scanner.scanExtension('extension-id', 'edge');

await scanner.close();

Scanning VS Code Extensions

import { BrowserTotalScanner } from '@browsertotal/scanner';

const scanner = new BrowserTotalScanner();

// VS Code Marketplace extension (publisher.extension-name format)
const result = await scanner.scanVSCodeExtension('ms-python.python');
console.log(result.name);
console.log(result.status);
console.log(result.permissions);

await scanner.close();

Scanning JetBrains Plugins

import { BrowserTotalScanner } from '@browsertotal/scanner';

const scanner = new BrowserTotalScanner();

// JetBrains plugin by ID
const result = await scanner.scanJetBrainsPlugin('7495'); // Rainbow Brackets
console.log(result.status);

await scanner.close();

Scanning npm Packages

import { BrowserTotalScanner } from '@browsertotal/scanner';

const scanner = new BrowserTotalScanner();

const result = await scanner.scanNpmPackage('lodash');
console.log(result.status);
console.log(result.version);
console.log(result.dependencies);

await scanner.close();

Scanning PyPI Packages

import { BrowserTotalScanner } from '@browsertotal/scanner';

const scanner = new BrowserTotalScanner();

const result = await scanner.scanPyPIPackage('requests');
console.log(result.status);
console.log(result.version);

await scanner.close();

Scanning WordPress Plugins

import { BrowserTotalScanner } from '@browsertotal/scanner';

const scanner = new BrowserTotalScanner();

const result = await scanner.scanWordPressPlugin('akismet');
console.log(result.status);

await scanner.close();

Generic Platform Scanning

Use scanByPlatform() for dynamic platform selection:

import { BrowserTotalScanner } from '@browsertotal/scanner';

const scanner = new BrowserTotalScanner();

// Scan any platform dynamically
const result = await scanner.scanByPlatform('lodash', 'npmjs');
const result2 = await scanner.scanByPlatform('extension-id', 'chrome');
const result3 = await scanner.scanByPlatform('ms-python.python', 'vscode');

await scanner.close();

Convenience Functions

For one-off scans without managing the scanner lifecycle:

import {
  scanUrl,
  scanExtension,
  scanVSCodeExtension,
  scanJetBrainsPlugin,
  scanNpmPackage,
  scanPyPIPackage,
  scanWordPressPlugin
} from '@browsertotal/scanner';

// One-off URL scan
const urlResult = await scanUrl('https://example.com');

// One-off browser extension scan
const extResult = await scanExtension('extension-id', 'chrome');

// One-off VS Code extension scan
const vscodeResult = await scanVSCodeExtension('ms-python.python');

// One-off npm package scan
const npmResult = await scanNpmPackage('express');

// One-off PyPI package scan
const pypiResult = await scanPyPIPackage('django');

Progress Tracking

import { BrowserTotalScanner } from '@browsertotal/scanner';

const scanner = new BrowserTotalScanner();

const result = await scanner.scanNpmPackage('express', (progress) => {
  console.log(`[${progress.phase}] ${progress.message}`);
});

await scanner.close();

Configuration Options

import { BrowserTotalScanner } from '@browsertotal/scanner';

const scanner = new BrowserTotalScanner({
  headless: true,        // Run browser in headless mode (default: true)
  timeout: 120000,       // Timeout in milliseconds (default: 420000)
  waitForResults: true,  // Wait for scan to complete (default: true)
  disableAI: true,       // Skip AI/LLM analysis for faster scans (default: true)
  userDataDir: '/tmp/browser', // Custom browser profile directory
});

How It Works

The scanner uses a special automation mode that:

  1. Appends #automationEvent=true to scan URLs
  2. BrowserTotal's UI detects this parameter and dispatches a scan_result custom event when analysis completes
  3. Puppeteer captures this event to get the full scan results

This approach ensures you get the complete analysis data, including:

  • Static analysis results
  • LLM/AI analysis results
  • Risk scores and threat assessments
  • Permission analysis (for extensions)
  • Dependency analysis (for packages)
  • Vulnerability findings

API Reference

BrowserTotalScanner

Constructor Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | headless | boolean | true | Run browser in headless mode | | timeout | number | 420000 | Timeout in milliseconds | | waitForResults | boolean | true | Wait for scan results before returning | | disableAI | boolean | true | Skip AI/LLM analysis for faster scans | | userDataDir | string | undefined | Custom browser profile directory |

Methods

URL Scanning
  • scanUrl(url: string, onProgress?: ProgressCallback): Promise<UrlScanResult>
Browser Extensions
  • scanExtension(extensionId: string, store?: BrowserStore, onProgress?: ProgressCallback): Promise<ExtensionScanResult>
IDE Extensions
  • scanVSCodeExtension(extensionId: string, onProgress?: ProgressCallback): Promise<ExtensionScanResult>
  • scanOpenVSXExtension(extensionId: string, onProgress?: ProgressCallback): Promise<ExtensionScanResult>
  • scanJetBrainsPlugin(pluginId: string, onProgress?: ProgressCallback): Promise<ExtensionScanResult>
Package Managers
  • scanNpmPackage(packageName: string, onProgress?: ProgressCallback): Promise<PackageScanResult>
  • scanPyPIPackage(packageName: string, onProgress?: ProgressCallback): Promise<PackageScanResult>
  • scanPowerShellModule(moduleName: string, onProgress?: ProgressCallback): Promise<PackageScanResult>
Other Platforms
  • scanWordPressPlugin(pluginSlug: string, onProgress?: ProgressCallback): Promise<ExtensionScanResult>
  • scanHuggingFace(modelId: string, onProgress?: ProgressCallback): Promise<ExtensionScanResult>
  • scanAppSourceAddin(addinId: string, onProgress?: ProgressCallback): Promise<ExtensionScanResult>
  • scanSalesforceApp(appId: string, onProgress?: ProgressCallback): Promise<ExtensionScanResult>
Generic
  • scanByPlatform(identifier: string, platform: Platform | BrowserStore, onProgress?: ProgressCallback): Promise<ExtensionScanResult | PackageScanResult>
Lifecycle
  • close(): Promise<void> - Closes the browser instance

Types

BrowserStore

type BrowserStore = 'chrome' | 'firefox' | 'edge' | 'opera' | 'safari' | 'brave';

Platform

type Platform =
  | 'vscode'
  | 'openvsx'
  | 'jetbrains'
  | 'npmjs'
  | 'pypi'
  | 'wordpress'
  | 'huggingface'
  | 'appsource'
  | 'powershellgallery'
  | 'salesforce';

UrlScanResult

interface UrlScanResult {
  url: string;
  status: 'safe' | 'suspicious' | 'malicious' | 'unknown' | 'error';
  score?: number;
  threats?: ThreatInfo[];
  categories?: string[];
  scanUrl: string;
  timestamp: Date;
  raw?: Record<string, unknown>; // Full scan data including LLM results
}

ExtensionScanResult

interface ExtensionScanResult {
  extensionId: string;
  name?: string;
  status: 'safe' | 'suspicious' | 'malicious' | 'unknown' | 'error';
  score?: number;
  permissions?: string[];
  threats?: ThreatInfo[];
  scanUrl: string;
  timestamp: Date;
  raw?: Record<string, unknown>; // Full scan data including LLM results
}

PackageScanResult

interface PackageScanResult {
  packageName: string;
  platform: string;
  name?: string;
  version?: string;
  status: 'safe' | 'suspicious' | 'malicious' | 'unknown' | 'error';
  score?: number;
  dependencies?: Record<string, string>;
  threats?: ThreatInfo[];
  scanUrl: string;
  timestamp: Date;
  raw?: Record<string, unknown>; // Full scan data including LLM results
}

Requirements

  • Node.js 18+
  • Puppeteer (installed automatically)