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

@yofix/browser

v1.0.11

Published

Intelligent browser automation for visual regression testing of route changes

Readme

@yofix/browser

Intelligent browser automation for visual regression testing of route changes. Powered by Playwright and Claude AI.

Features

  • 🚀 Framework-agnostic - Works with any frontend framework
  • 🔐 Smart authentication - AI-powered login flow detection using Claude AI
  • 📱 Multi-viewport - Capture screenshots at different screen sizes with custom device scale factors
  • 💾 Flexible storage - Local file system or GitHub Actions artifacts
  • Cache-first - Fast subsequent runs with cached login configs (30-day TTL)
  • 🎯 Type-safe - Full TypeScript support with comprehensive type definitions
  • 🔧 Dual interface - CLI + programmatic API
  • 🎨 Customizable - Configurable viewports, timeouts, wait conditions, and browser options
  • 📝 Routes from file - Support for reading routes from files or CLI arguments
  • 🔄 Smart login - Skip login if already authenticated, force refresh detection

Installation

npm install @yofix/browser

Or use directly with npx:

npx @yofix/browser capture --help

Quick Start

Basic Usage (No Authentication)

route-impact-browser capture \
  --codebase ./my-app \
  --base-url https://example.com \
  --routes / /about /pricing \
  --viewports "1920x1080:desktop,768x1024:tablet,375x667:mobile"

With Authentication

route-impact-browser capture \
  --codebase ./my-app \
  --base-url https://preview.example.com \
  --routes /dashboard /settings \
  --enable-auth \
  --auth-email [email protected] \
  --auth-password "password" \
  --llm-api-key sk-ant-api03-... \
  --viewports "1920x1080:desktop"

Programmatic API

import { captureRouteScreenshots } from '@yofix/browser'

const result = await captureRouteScreenshots({
  codebase: { path: './my-app' },
  routes: ['/dashboard', '/settings'],
  baseUrl: 'https://preview.example.com',
  loginUrl: '/login/password', // Optional: custom login URL (default: '/login')
  credentials: {
    email: '[email protected]',
    password: 'password'
  },
  options: {
    viewports: [
      { width: 1920, height: 1080, name: 'desktop' }
    ],
    llm: {
      provider: 'anthropic',
      apiKey: process.env.CLAUDE_API_KEY, // or CLAUDE_API_KEY
      model: 'claude-sonnet-4-5-20250929'
    },
    auth: {
      enabled: true,
      forceRefresh: false, // Use cached login config
      skipLoginIfAuthenticated: true, // Skip if already logged in
      cache: {
        enabled: true,
        ttl: 30 * 24 * 60 * 60 * 1000 // 30 days
      }
    },
    browser: {
      headless: true,
      timeout: 30000,
      waitUntil: 'networkidle' // 'load' | 'domcontentloaded' | 'networkidle'
    },
    storage: {
      provider: 'local', // 'local' | 'github-actions-artifact'
      artifactName: 'screenshots' // For GitHub Actions
    },
    verbose: false
  }
})

console.log(`Captured ${result.metadata.totalScreenshots} screenshots`)

GitHub Actions Integration

name: Visual Regression Testing

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  screenshot:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Capture route screenshots
        uses: ./.github/actions/screenshot-routes
        with:
          codebase-path: '.'
          base-url: ${{ needs.deploy-preview.outputs.url }}
          routes: '/,/dashboard,/settings'
          viewports: '1920x1080:desktop,768x1024:tablet'
          enable-auth: 'true'
          auth-email: ${{ secrets.TEST_EMAIL }}
          auth-password: ${{ secrets.TEST_PASSWORD }}
          claude-api-key: ${{ secrets.CLAUDE_API_KEY }}
          artifact-name: 'screenshots-${{ github.event.pull_request.number }}'

CLI Commands

Capture Screenshots

route-impact-browser capture [options]

Required Options:

  • --codebase <path> - Path to codebase directory
  • --base-url <url> - Base URL of the running application
  • --routes <routes...> - Routes to capture (space-separated)
  • --routes-file <path> - File containing routes (one per line)

Authentication Options:

  • --enable-auth - Enable authentication
  • --auth-email <email> - Authentication email (or use AUTH_EMAIL env var)
  • --auth-password <password> - Authentication password (or use AUTH_PASSWORD env var)
  • --llm-api-key <key> - Claude API key for login detection (or use CLAUDE_API_KEY env var)
  • --llm-model <model> - Claude model to use (default: claude-sonnet-4-5-20250929)
  • --force-refresh-login - Force re-detection of login flow (ignore cache)
  • --skip-login-if-authenticated - Skip login if already authenticated

Browser Options:

  • --viewports <viewports> - Viewport dimensions (default: "1920x1080:desktop")
  • --headless / --no-headless - Run browser in headless mode
  • --timeout <ms> - Navigation timeout (default: 30000)

Storage Options:

  • --output-dir <path> - Output directory for screenshots
  • --storage <provider> - Storage provider: local | github-actions-artifact
  • --artifact-name <name> - GitHub Actions artifact name

Other Options:

  • --verbose - Verbose output

Cache Management

# Clear cached login flow
route-impact-browser clear-cache --codebase ./my-app

# View cache statistics
route-impact-browser cache-stats --codebase ./my-app

How It Works

1. Login Flow Detection (First Run)

On the first run with authentication enabled, the tool:

  1. Analyzes your codebase structure (package.json, file structure, dependencies)
  2. Uses Claude AI (Sonnet 4.5) to intelligently identify:
    • Login page URL (or uses custom loginUrl if provided)
    • Email/password input selectors
    • Submit button selector
    • Success indicator (post-login element for authentication verification)
    • Wait conditions (navigation, selectors, timeouts)
    • Framework detection (NextAuth.js, Firebase Auth, Custom, etc.)
  3. Caches the configuration for 30 days (configurable TTL)
  4. Provides confidence levels (high, medium, low) with reasoning

Example detected config:

{
  "loginUrl": "/login",
  "selectors": {
    "emailInput": "input[type='email']",
    "passwordInput": "input[type='password']",
    "submitButton": "button[type='submit']",
    "successIndicator": "[data-testid='user-menu']"
  },
  "waitConditions": {
    "waitForNavigation": true,
    "waitForSelector": "[data-testid='user-menu']",
    "timeout": 30000
  },
  "confidence": "high",
  "framework": "NextAuth.js",
  "reasoning": "Detected NextAuth.js patterns in codebase..."
}

2. Screenshot Capture

For each route:

  1. Navigates to the full URL (baseUrl + route)
  2. Waits for page load (configurable: load, domcontentloaded, or networkidle)
  3. Captures screenshots at each configured viewport with proper device scale factors
  4. Saves with naming: {output-dir}/{route-slug}/{viewport-name}.png
  5. Tracks timing metrics (navigation time, screenshot time, total time)
  6. Handles errors gracefully with detailed error reporting

3. Storage

Local: Screenshots saved to directory (default: screenshots-{datetime})

GitHub Actions: Uploaded as artifacts (available for 90 days)

Viewport Configuration

Format

WIDTHxHEIGHT[:NAME[:SCALE]]

Examples

# Single viewport
--viewports "1920x1080"

# With custom name
--viewports "1920x1080:desktop"

# Multiple viewports
--viewports "1920x1080:desktop,768x1024:tablet,375x667:mobile"

# With device scale factor (for retina displays)
--viewports "1920x1080:desktop:2"

Programmatic API

viewports: [
  { width: 1920, height: 1080, name: 'desktop' },
  { width: 768, height: 1024, name: 'tablet', deviceScaleFactor: 2 },
  { width: 375, height: 667, name: 'mobile', deviceScaleFactor: 3 }
]

Environment Variables

The following environment variables can be used as alternatives to CLI options:

  • AUTH_EMAIL - Authentication email (alternative to --auth-email)
  • AUTH_PASSWORD - Authentication password (alternative to --auth-password)
  • CLAUDE_API_KEY or CLAUDE_API_KEY - Claude API key (alternative to --llm-api-key)
  • GITHUB_ACTIONS - Auto-detected when running in GitHub Actions (enables artifact upload)

Output Structure

screenshots-20240115_120530/
├── dashboard/
│   ├── desktop.png
│   ├── tablet.png
│   └── mobile.png
├── settings/
│   ├── desktop.png
│   ├── tablet.png
│   └── mobile.png
└── guard-trends/
    └── desktop.png

Result Object

{
  success: boolean
  metadata: {
    timestamp: number
    totalRoutes: number
    totalScreenshots: number
    successfulRoutes: number
    failedRoutes: number
    outputDirectory: string
    authUsed: boolean
    loginFlowDetected: boolean
    totalDuration: number
    baseUrl: string
  }
  screenshots: [
    {
      route: string
      fullUrl: string
      screenshots: [
        {
          viewport: string
          path: string
          destination: string
          width: number
          height: number
          size: number
          duration: number
          contentType: string
          metadata: {
            route: string
            fullUrl: string
            viewport: string
            width: string
            height: string
          }
        }
      ]
      timing: {
        navigationTime: number
        screenshotTime: number
        totalTime: number
      }
      success: boolean
      error?: string
    }
  ]
  errors?: [
    {
      code: string
      message: string
      route?: string
      phase?: 'login' | 'navigation' | 'screenshot' | 'storage'
      details?: unknown
    }
  ]
  artifactInfo?: {
    uploaded: boolean
    artifactName: string
    artifactId?: number
    size: number
  }
}

Troubleshooting

Login Detection Fails

  • Ensure Claude API key is provided
  • Check that your codebase has login-related files
  • Use --force-refresh-login to re-detect
  • Manually verify the detected selectors work

Screenshots Fail

  • Increase timeout: --timeout 60000
  • Run non-headless to debug: --no-headless
  • Check routes are valid and accessible
  • Ensure authentication succeeded

Cache Issues

  • Clear cache: route-impact-browser clear-cache --codebase ./my-app
  • Use --force-refresh-login to regenerate
  • Check cache stats: route-impact-browser cache-stats --codebase ./my-app

License

MIT

GitHub Repository

Related Projects