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

@ytspar/sweetlink

v1.24.3

Published

Autonomous development toolkit for AI agents - screenshots, DOM queries, console logs, and JavaScript execution via WebSocket and Chrome DevTools Protocol

Readme

@ytspar/sweetlink

npm

Autonomous development toolkit for Claude AI agents - screenshots, DOM queries, console logs, and JavaScript execution via WebSocket and Chrome DevTools Protocol

Overview

Sweetlink enables Claude AI agents to autonomously debug, test, and iterate on web applications through real-time browser interaction. It provides a WebSocket bridge between your development server and CLI tools, allowing AI assistants to take screenshots, inspect DOM, capture console logs, and execute JavaScript - all without human intervention.

Inspired by: Peter Steinberger's autonomous debugging implementation - "Now my agent can debug everything completely autonomous e2e."

Features

  • 📸 Screenshots - Capture full page or element-specific screenshots (html2canvas + CDP)
  • 🧭 Inspect Context - One command for screenshot paths, refs, console/network deltas, a11y, vitals, and next actions
  • 🖱️ Screenshot Button - One-click screenshot capture with console logs from browser UI
  • 🔍 DOM Queries - Query and inspect DOM elements with CSS selectors
  • 📊 Console Logs - Capture and filter browser console output with JSON/summary formats
  • ⚡ JavaScript Execution - Run arbitrary JavaScript in browser context
  • 🖱️ Click Elements - Click elements by selector, text content, or both
  • 🌐 Network Inspection - Monitor network requests (CDP only)
  • 🔄 Page Refresh - Soft or hard refresh the browser from CLI
  • 🔄 Auto Reconnection - Browser client automatically reconnects on disconnect
  • 🎯 Token Efficient - ~1000 tokens/screenshot vs ~5000 for MCP tools
  • 📝 LLM-Optimized Output - Summary format with deduplication for context efficiency
  • 🚀 Zero Setup - Works immediately with any web app
  • 🖥️ Persistent Daemon - Playwright daemon stays alive between commands (~150ms screenshots)
  • 🏷️ @Ref System - Accessibility tree refs for click/fill without CSS selectors
  • 📊 Ring Buffers - Always-on console/network/dialog capture (50K entries)
  • 🎬 Session Recording - Record actions with screenshots, generate interactive viewer
  • 🔍 Snapshot Diffing - Text diff of accessibility tree after actions
  • 📱 Device Emulation - Named presets (iPhone 14, Pixel 7, iPad Pro) for batch screenshots

Screenshot Button

The browser UI includes a convenient screenshot button (📸) that allows developers and AI agents to instantly capture the current page state along with console logs. When clicked:

  1. Captures full page screenshot using html2canvas
  2. Saves screenshot to .tmp/sweetlink-screenshots/screenshot-[timestamp].png
  3. Saves console logs to .tmp/sweetlink-screenshots/screenshot-[timestamp]-logs.txt
  4. Logs include: timestamp, URL, dimensions, and all console messages

This provides AI agents with easy access to visual state and debugging information without requiring CLI commands.

File Location Rationale: Files are saved to .tmp/sweetlink-screenshots/ (relative to project root) for easy agent access - keeps screenshots with the project and is typically gitignored via .tmp/ patterns.

Requirements

This package is ESM-only. It requires "type": "module" in your package.json or an ESM-capable bundler (Vite, webpack, esbuild, etc.).

Installation

npm install @ytspar/sweetlink
# or
pnpm add @ytspar/sweetlink
# or
yarn add @ytspar/sweetlink

# Install canary (latest from main)
pnpm add @ytspar/sweetlink@canary

Claude Code Integration

If you use Claude Code, run the setup command to install the screenshot skill and context files:

pnpm sweetlink setup

This creates symlinks in your .claude/ directory so Claude can use the /screenshot skill automatically. Re-run after upgrading sweetlink to pick up any skill updates.

Quick Start

For Vite Apps (Recommended)

Just add the plugin - zero configuration needed:

// vite.config.ts
import { defineConfig } from 'vite';
import { sweetlink } from '@ytspar/sweetlink/vite';

export default defineConfig({
  plugins: [sweetlink()]
});

That's it! The plugin automatically:

  • Starts the Sweetlink server when Vite starts
  • Detects Vite's port and configures everything
  • DevBar connects automatically
  • Exposes a same-origin WebSocket endpoint at /__sweetlink for Portless and other local HTTPS proxies

For Next.js (Recommended)

Wrap your Next.js config - zero configuration needed:

// next.config.mjs
import { withSweetlink } from '@ytspar/sweetlink/next';

const nextConfig = { /* your config */ };
export default withSweetlink(nextConfig);

That's it! The plugin automatically:

  • Detects the port from --port argv (e.g., next dev --port 3002)
  • Falls back to process.env.PORT, then 3000
  • Starts the WebSocket server on appPort + 6223
  • Injects public Sweetlink port hints for proxied local URLs such as Portless
  • No-ops in production

Works with other wrappers too:

// With Sentry, MDX, etc.
export default withSentryConfig(withSweetlink(withMDX(nextConfig)), sentryOptions);

For Any Node.js App (Express, Remix, etc.)

Add one line at the top of your server file:

// server.ts, app.ts, or entry point
import '@ytspar/sweetlink/auto';

// Your app code...

This automatically:

  • Starts Sweetlink in development mode only
  • Reads port from process.env.PORT (or defaults to 3000)
  • DevBar connects automatically

With Explicit Configuration

import { startSweetlink } from '@ytspar/sweetlink/auto';

startSweetlink({ appPort: 3000 });

Using DevBar (Browser UI)

Add DevBar to your app for the screenshot button and dev toolbar:

// app/root.tsx, _app.tsx, or App.tsx
import { initGlobalDevBar } from '@ytspar/devbar';

if (process.env.NODE_ENV === 'development') {
  initGlobalDevBar();
}

DevBar automatically connects to Sweetlink - no configuration needed.

CLI Usage

Add to your package.json for CLI access:

{
  "scripts": {
    "sweetlink": "sweetlink"
  }
}

Then use:

pnpm sweetlink inspect --url http://localhost:3000
pnpm sweetlink screenshot
pnpm sweetlink logs
pnpm sweetlink query --selector "h1"

Agent Protocol

For LLM-driven frontend work, prefer a repeatable evidence loop:

# Inspect: generate the state bundle an agent should reason from
pnpm sweetlink inspect --url http://localhost:3000 --label "initial state" --json

# Act: use @e refs from snapshot.md/context.json, not brittle CSS selectors
pnpm sweetlink click @e2 --url http://localhost:3000 --json

# Verify: rerun inspect after the DOM or visual state changes
pnpm sweetlink inspect --url http://localhost:3000 --label "after action" --expected "Menu opens" --json

# Record: when evidence needs to travel with a PR
pnpm sweetlink record start --url http://localhost:3000
pnpm sweetlink record stop

inspect creates .sweetlink/inspect/<timestamp-label>/SUMMARY.md, context.json, screenshot.png, snapshot.md, console.txt, network.txt, and a11y.json. Agents should read SUMMARY.md first, use @e refs for click, fill, and press, retry stale refs by rerunning inspect, and attach the summary plus screenshot or recording artifacts to handoffs and PRs.

CLI Usage

Inspect Context

# Human-readable summary with artifact paths
pnpm sweetlink inspect --url http://localhost:3000 --label "checkout review"

# Stable JSON schema for agents
pnpm sweetlink inspect --url http://localhost:3000 --json

# Add expected outcome and action transcript to the evidence bundle
pnpm sweetlink inspect --url http://localhost:3000 \
  --expected "Save button remains enabled" \
  --action "clicked promo warning"

The context alias is equivalent to inspect.

Screenshots

# Full page screenshot (html2canvas, fast)
pnpm sweetlink screenshot

# Element screenshot
pnpm sweetlink screenshot --selector ".company-card"

# Capture app UI without DevBar chrome
pnpm sweetlink screenshot --hide-devbar
pnpm sweetlink screenshot --hifi --hide-devbar

# Full page with custom output
pnpm sweetlink screenshot --full-page --output page.png

# Navigate to URL before capturing
pnpm sweetlink screenshot --url http://localhost:3000/about

# Custom viewport dimensions
pnpm sweetlink screenshot --force-cdp --width 375 --height 667
pnpm sweetlink screenshot --force-cdp --viewport mobile

# Pixel-perfect via daemon (see Persistent Daemon section)
pnpm sweetlink screenshot --hifi
pnpm sweetlink screenshot --responsive

# Skip server readiness check
pnpm sweetlink screenshot --no-wait

# Force specific method
pnpm sweetlink screenshot --force-cdp   # Playwright/CDP
pnpm sweetlink screenshot --force-ws    # WebSocket/html2canvas

Hide DevBar for screenshots

Use --hide-devbar when the toolbar should not appear in captured evidence. The flag works with the default WebSocket/html2canvas path, Playwright/CDP fallback, --hifi, and --responsive.

pnpm sweetlink screenshot --hide-devbar --output app.png
pnpm sweetlink screenshot --hifi --hide-devbar --full-page
pnpm sweetlink screenshot --responsive --hide-devbar

JavaScript and Playwright callers can use the same behavior:

import {
  installAutoHideDevbarScreenshots,
  installAutoHideDevbarScreenshotsForContext,
  screenshotViaPlaywright,
  withHiddenDevbarForScreenshot,
} from '@ytspar/sweetlink/playwright';

await screenshotViaPlaywright({
  url: 'http://localhost:5173',
  output: 'app.png',
  hideDevbar: true,
});

await withHiddenDevbarForScreenshot(page, () =>
  page.screenshot({ path: 'app-without-devbar.png', fullPage: true })
);

// Patch one page so every page.screenshot() hides DevBar automatically.
const cleanupPageScreenshots = installAutoHideDevbarScreenshots(page);
await page.screenshot({ path: 'app-without-devbar.png', fullPage: true });
cleanupPageScreenshots();

// Or patch every current/future page in a Playwright context.
const cleanupContextScreenshots = installAutoHideDevbarScreenshotsForContext(context);

Playwright fixture example:

import { test as base } from '@playwright/test';
import { installAutoHideDevbarScreenshots } from '@ytspar/sweetlink/playwright';

export const test = base.extend({
  page: async ({ page }, use) => {
    const cleanup = installAutoHideDevbarScreenshots(page);
    try {
      await use(page);
    } finally {
      cleanup();
    }
  },
});

Browser-side capture code can use the shared preparation helper:

import { prepareForCapture } from '@ytspar/sweetlink/browser/screenshotUtils';

const cleanup = prepareForCapture({ hideDevbar: true });
try {
  // Run html2canvas or another DOM-based capture here.
} finally {
  cleanup();
}

DOM Queries

# Query elements
pnpm sweetlink query --selector "h1"

# Get element property
pnpm sweetlink query --selector ".card" --property "offsetWidth"

# Wait for element to exist before querying (handles hydration)
pnpm sweetlink query --selector "img" --wait-for "img[src*='hero']"

Console Logs

# Get all logs
pnpm sweetlink logs

# Filter by error
pnpm sweetlink logs --filter "error"

# JSON output (full array)
pnpm sweetlink logs --format json

# LLM-optimized summary (deduplicated, sorted by severity)
pnpm sweetlink logs --format summary

# Text format with deduplication
pnpm sweetlink logs --dedupe

Log Output Formats

| Format | Description | Best For | |--------|-------------|----------| | text (default) | Human-readable timestamped lines | Manual debugging | | json | Full JSON array with all entries | Programmatic access | | summary | Compact JSON with deduplication | LLM context optimization |

Summary format example:

{
  "url": "http://localhost:3000",
  "capturedAt": "2025-01-27T...",
  "totalLogs": 47,
  "uniqueLogs": 3,
  "byLevel": { "error": 2, "warn": 0, "log": 1 },
  "logs": [
    { "level": "error", "message": "...", "count": 25 },
    { "level": "log", "message": "...", "count": 22 }
  ]
}

Page Refresh

# Soft refresh (reload page)
pnpm sweetlink refresh

# Hard refresh (clear cache and reload)
pnpm sweetlink refresh --hard

JavaScript Execution

# Execute JavaScript expression
pnpm sweetlink exec --code "document.title"

# Count elements
pnpm sweetlink exec --code "document.querySelectorAll('.card').length"

# Bare return statements are auto-wrapped in an IIFE
pnpm sweetlink exec --code "const x = 1 + 2; return x;"

# Promises are automatically awaited (10s timeout)
pnpm sweetlink exec --code "fetch('/api/health').then(r => r.status)"

# Wait for element to exist before executing
pnpm sweetlink exec --code "document.querySelectorAll('img').length" --wait-for "img[src*='hero']"

Framework hydration note: With Next.js App Router, Vite, and other frameworks that hydrate incrementally, DOM elements may exist in the HTML but not be queryable immediately after page load. Use --wait-for to poll until the target element is present.

Click Elements

# Click by CSS selector
pnpm sweetlink click --selector "button.submit"

# Click by text content
pnpm sweetlink click --text "Submit"

# Combine selector + text for precise matching
pnpm sweetlink click --selector "th" --text "Rank"
pnpm sweetlink click --selector "a" --text "BACK TO LIST"

# Select nth match (0-based index)
pnpm sweetlink click --selector ".tab" --index 2

Options: | Option | Description | |--------|-------------| | --selector | CSS selector to find elements | | --text | Find element by text content | | --index | Select nth match when multiple found (default: 0) |

Debugging: Use DEBUG=1 pnpm sweetlink click ... to see generated JavaScript.

Network Requests

# Get all network requests (via WebSocket bridge)
pnpm sweetlink network

# Filter by URL
pnpm sweetlink network --filter "/api/"

# Failed requests only (via daemon ring buffer)
pnpm sweetlink network --failed
pnpm sweetlink network --failed --last 10

Schema, Outline, Accessibility

# Page schema (JSON-LD, meta tags, Open Graph)
pnpm sweetlink schema

# Document outline (heading structure)
pnpm sweetlink outline

# Accessibility audit (axe-core)
pnpm sweetlink a11y

# Web Vitals (FCP, LCP, CLS, INP)
pnpm sweetlink vitals

Server Management

# Wait for dev server to be ready (useful in scripts)
pnpm sweetlink wait --url http://localhost:3000
pnpm sweetlink wait --url http://localhost:3000 --wait-timeout 60000

# Check server health
pnpm sweetlink status

# Clean up Sweetlink processes
pnpm sweetlink cleanup
pnpm sweetlink cleanup --force

# Target specific app in monorepo (by branch or app name)
pnpm sweetlink screenshot --app my-app

Persistent Daemon (v2)

Sweetlink v2 adds a persistent Playwright daemon for high-fidelity operations. The daemon auto-starts on first use and auto-stops after 30min idle.

Auto-Start with Vite

Add daemon: true to your Vite plugin config — the daemon starts/stops with your dev server:

// vite.config.ts
import { sweetlink } from '@ytspar/sweetlink/vite';

export default defineConfig({
  plugins: [sweetlink({ daemon: true })]
  // Or with visible browser: sweetlink({ daemon: true, headed: true })
});

Auto-Start with Dev Script

Add a dev script that starts both your app and the daemon:

{
  "scripts": {
    "dev": "vite",
    "dev:daemon": "concurrently 'vite' 'sweetlink daemon start --url http://localhost:5173'"
  }
}

Multiple Apps (Monorepo)

Each daemon is scoped by app port. Running two apps on different ports creates separate daemons:

# Terminal 1: App A on port 3000
sweetlink daemon start --url http://localhost:3000
# State: .sweetlink/daemon-3000.json

# Terminal 2: App B on port 5173
sweetlink daemon start --url http://localhost:5173
# State: .sweetlink/daemon-5173.json

# Commands target specific apps via --url
sweetlink screenshot --hifi --url http://localhost:3000
sweetlink screenshot --hifi --url http://localhost:5173

Manual Lifecycle

# Start manually (auto-starts on first --hifi command if not running)
pnpm sweetlink daemon start --url http://localhost:5173
pnpm sweetlink daemon start --url http://localhost:5173 --headed  # visible browser

# Check status
pnpm sweetlink daemon status

# Stop (or wait for 30min idle auto-stop)
pnpm sweetlink daemon stop

CLI Quick Reference

# Pixel-perfect screenshot via persistent daemon (~150ms after startup)
pnpm sweetlink screenshot --hifi

# Responsive screenshots at 3 breakpoints (375/768/1280)
pnpm sweetlink screenshot --responsive

Accessibility Snapshots & Refs

# List interactive elements with @refs
pnpm sweetlink snapshot -i
#   @e1 [link] "Home"
#   @e2 [button] "Submit"
#   @e3 [textbox] "Email"

# Click/fill by ref (no CSS selector needed)
pnpm sweetlink click @e2
pnpm sweetlink fill @e3 "[email protected]"

# Diff against previous snapshot
pnpm sweetlink snapshot -D

# Annotated screenshot with red ref labels
pnpm sweetlink snapshot -a -o annotated.png

Console & Network (Ring Buffers)

Always-on capture from daemon start — no "start watching" needed.

# Console messages (captured since daemon start)
pnpm sweetlink console
pnpm sweetlink console --errors
pnpm sweetlink console --last 20

# Failed network requests
pnpm sweetlink network --failed

Session Recording

pnpm sweetlink record start
# ... do actions (click, fill, snapshot) ...
pnpm sweetlink record stop
# Generates .sweetlink/<session-id>/viewer.html

Demo Documents

Build a Markdown tutorial/proof document step-by-step (inspired by Showboat):

# Start a new demo
pnpm sweetlink demo init "How to use the search feature"

# Add narrative prose
pnpm sweetlink demo note "First, run the tests to see them pass."

# Run a command and capture output inline
pnpm sweetlink demo exec "pnpm test -- --grep search"

# Take a screenshot and embed it
pnpm sweetlink demo screenshot --url http://localhost:5173 --caption "Search results"

# Capture accessibility tree
pnpm sweetlink demo snapshot --url http://localhost:5173

# Remove last section if it's wrong
pnpm sweetlink demo pop

# Re-run all commands to verify outputs haven't changed
pnpm sweetlink demo verify

# Check status
pnpm sweetlink demo status

Result: a DEMO.md with embedded command outputs and screenshots that serves as both documentation and a regression test.

PR Evidence

pnpm sweetlink proof --pr 123

Chrome DevTools Protocol (CDP) Setup

For native Chrome rendering and network inspection:

# macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222

# Linux
google-chrome --remote-debugging-port=9222

# Windows
"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222

Set environment variable (optional):

export CHROME_CDP_PORT=9222

Programmatic API

Server

import { initSweetlink, closeSweetlink } from '@ytspar/sweetlink/server';

// Start server
const wss = await initSweetlink({ port: 9223 });

// Close server
await closeSweetlink();

CDP Integration

import {
  detectCDP,
  getCDPBrowser,
  screenshotViaCDP,
  getNetworkRequestsViaCDP
} from '@ytspar/sweetlink/cdp';

// Check if CDP is available
const hasCDP = await detectCDP();

// Take screenshot via CDP
const result = await screenshotViaCDP({
  output: 'screenshot.png',
  fullPage: true
});

// Get network requests
const requests = await getNetworkRequestsViaCDP({
  filter: '/api/'
});

Browser Bridge (Vanilla JS)

The browser bridge is a vanilla JS class (not a React component). For most setups, use the Vite plugin or auto-import instead of initializing manually.

import { initSweetlinkBridge } from '@ytspar/sweetlink/browser';

// Initialize with defaults (auto-detects port from devbar)
initSweetlinkBridge();

// Or with explicit config
initSweetlinkBridge({
  basePort: 9223,
  debug: true,
});

SweetlinkBridgeConfig

| Option | Type | Default | Description | |--------|------|---------|-------------| | basePort | number | Auto-detected | WebSocket server port | | maxPortRetries | number | 10 | Max port scan attempts | | hmrScreenshots | boolean | false | Auto-capture on HMR updates | | debug | boolean | false | Enable verbose connection logging |

Environment Variables

| Variable | Default | Description | |----------|---------|-------------| | SWEETLINK_WS_PORT | 9223 | WebSocket server port | | SWEETLINK_WS_URL | ws://localhost:9223 | WebSocket URL (CLI) | | CHROME_CDP_PORT | 9222 | Chrome DevTools Protocol port | | CHROME_CDP_URL | http://127.0.0.1:9222 | CDP URL |

Architecture

flowchart TB
    subgraph CLI["Claude AI Agent (CLI)"]
        screenshot["Screenshot"]
        query["DOM Query"]
        logs["Logs"]
        exec["Exec JS"]
    end

    subgraph Server["Sweetlink Server"]
        mux["WebSocket Multiplexer"]
        r1["Routes CLI commands to browser"]
        r2["Routes browser responses to CLI"]
    end

    subgraph Browser["Browser (Your App)"]
        subgraph Bridge["SweetlinkBridge"]
            b1["Captures console logs"]
            b2["Executes commands (screenshot, query, exec)"]
            b3["Auto-reconnects on disconnect"]
        end
        html2canvas["html2canvas (screenshots)"]
    end

    CLI <-->|"WebSocket :9223"| Server
    Server <-->|"WebSocket :9223"| Browser

Use Cases

Autonomous UI Development

while (!designPerfect) {
  // Make UI changes
  await editComponent();

  // Take screenshot
  await exec('pnpm sweetlink screenshot --selector ".component"');

  // Check for console errors
  const logs = await exec('pnpm sweetlink logs --filter error');

  // Iterate until perfect!
}

Automated Testing

# Take baseline screenshot
pnpm sweetlink screenshot --output baseline.png

# Make changes...

# Take comparison screenshot
pnpm sweetlink screenshot --output comparison.png

# Compare screenshots with image diff tool

Debugging Production Issues

# Get console errors
pnpm sweetlink logs --filter error

# Inspect element state
pnpm sweetlink query --selector ".error-component"

# Execute debug code
pnpm sweetlink exec --code "localStorage.getItem('debug')"

Token Efficiency

Sweetlink is designed for token-efficient autonomous loops:

  • html2canvas screenshots: ~131KB (~1,000 tokens)
  • CDP screenshots: ~2.0MB (~15,000 tokens)
  • Default strategy: Use html2canvas first, escalate to CDP only when needed

This 15x token savings enables 10+ autonomous iterations within Claude's budget.

Comparison with Alternatives

Screenshot & Interaction

| Feature | Sweetlink | Playwright CLI | Chrome DevTools MCP | agent-browser | |---------|-----------|----------------|--------------------|--------------| | Setup | Vite/Next plugin | npm install | Chrome flag | npm install | | Token cost/screenshot | ~1,000 | ~5,000 | ~5,000 | ~3,000 | | Fast screenshots (html2canvas) | ✅ | ❌ | ❌ | ❌ | | Pixel-perfect screenshots | ✅ (--hifi) | ✅ | ✅ | ✅ | | Responsive (multi-viewport) | ✅ (--responsive) | Manual | ❌ | ❌ | | Device emulation (iPhone, Pixel) | ✅ (named presets) | ✅ | ❌ | ✅ | | @ref element interaction | ✅ (accessibility tree) | ❌ (CSS selectors) | ❌ | ✅ (Stagehand AI) | | DOM queries | ✅ | ✅ | ✅ | ❌ | | JS execution | ✅ | ✅ | ✅ | ❌ | | Persistent browser sessions | ✅ (daemon) | ❌ (per-run) | ✅ | ✅ |

Evidence & Reporting

| Feature | Sweetlink | ProofShot | Proof | Playwright | |---------|-----------|-----------|-------|------------| | Video recording (WebM) | ✅ | ✅ | ✅ | ✅ (trace) | | Interactive HTML viewer | ✅ (video + overlays) | ✅ | ✅ | ✅ (trace viewer) | | Click ripple overlays | ✅ (canvas) | ✅ | ✅ (FFmpeg) | ❌ | | Console ring buffer | ✅ (always-on, 50K) | ✅ | ❌ | ❌ | | Network ring buffer | ✅ (always-on, 50K) | ❌ | ❌ | ✅ (HAR) | | Multi-language error detection | ✅ (10+ languages) | ✅ | ❌ | ❌ | | Snapshot diffing (a11y tree) | ✅ | ❌ | ❌ | ❌ | | Annotated screenshots | ✅ (@ref labels) | ✅ | ❌ | ❌ | | SUMMARY.md report | ✅ | ✅ | ✅ (3 formats) | ❌ | | Demo documents (Showboat-style) | ✅ | ❌ | ❌ | ❌ | | PR evidence upload | ✅ (proof --pr) | ✅ | ❌ | ❌ | | Webhook sharing | ✅ (any URL) | ❌ | ❌ | ❌ | | Self-contained viewer (offline) | ✅ (base64 video) | ✅ | ✅ | ✅ |

Developer Experience

| Feature | Sweetlink | ProofShot | Chrome DevTools MCP | |---------|-----------|-----------|---------------------| | Devbar toolbar UI | ✅ | ❌ | ❌ | | Record button in browser | ✅ | ❌ | ❌ | | Viewer auto-opens on stop | ✅ | ❌ | ❌ | | Copy Report to clipboard | ✅ (CLI + viewer) | ❌ | ❌ | | Serve viewer on network | ✅ (report --serve) | ❌ | ❌ | | Multi-instance (monorepo) | ✅ (per-port daemon) | ❌ | ❌ | | Vite/Next.js auto-start | ✅ (plugin option) | ❌ | ❌ | | Accessibility audit (axe-core) | ✅ | ❌ | ❌ | | Web Vitals | ✅ | ❌ | ❌ | | Ruler/measurement tool | ✅ | ❌ | ❌ |

When to Use Alternatives

Sweetlink vs Agent Browser vs Playwright

Use Sweetlink when:

  • You're debugging/iterating on a running dev server
  • You need lightweight, token-efficient screenshots (~1000 tokens vs ~5000)
  • You want always-on console/network capture without "start watching"
  • You need session recording with interactive video viewer
  • You want demo documents that serve as both tutorials and regression tests
  • You're doing autonomous UI development loops (10+ iterations)
  • You want a toolbar UI in the browser for visual debugging

Use Agent Browser when:

  • You're testing production sites or external URLs where Sweetlink isn't installed
  • You need Stagehand's AI-powered element selection
  • You're building autonomous agents that interact with arbitrary websites

Use Playwright directly when:

  • You're writing structured E2E test suites with assertions
  • You need network interception, request mocking, or multiple browser contexts
  • You want trace viewer for debugging test failures

Agent Browser Quick Start

Agent Browser is Vercel's Stagehand-based browser automation tool. It's ideal as a Sweetlink backup for scenarios requiring full browser control.

# Install globally
npm install -g @anthropic-ai/agent-browser

# Or use npx
npx @anthropic-ai/agent-browser

Basic usage with Claude:

# Take screenshot of any URL
agent-browser screenshot https://example.com

# Navigate and interact
agent-browser navigate https://example.com
agent-browser click "Sign In"
agent-browser type "username" --into "Email field"

# Extract page content
agent-browser extract "main article content"

Key differences from Sweetlink:

| Aspect | Sweetlink | Agent Browser | |--------|-----------|---------------| | Setup | Requires app integration | Works with any URL | | Token cost | ~1,000/screenshot | ~3,000-5,000/screenshot | | Best for | Dev iteration loops | Full browser automation | | AI element selection | No (CSS selectors) | Yes (Stagehand AI) | | Console logs | Real-time capture | Not available | | Requires dev server | Yes | No |

Recommended workflow:

  1. During development: Use Sweetlink for fast, token-efficient iteration
  2. For external sites or full automation: Fall back to Agent Browser
  3. For E2E testing with assertions: Use Playwright directly

Troubleshooting

WebSocket Connection Fails

# Check if port is in use
lsof -i :9223

# Try different port
SWEETLINK_WS_PORT=9224 pnpm dev

Browser Not Connected

  1. Ensure Sweetlink bridge is initialized (Vite plugin, auto-import, or initSweetlinkBridge())
  2. Check browser console for connection errors
  3. Verify WebSocket server is running ([Sweetlink] WebSocket server started...)

CDP Not Available

  1. Start Chrome with debugging: /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222
  2. Verify CDP endpoint: curl http://127.0.0.1:9222/json/version
  3. Check firewall settings

Contributing

Contributions welcome! Please open an issue or PR at https://github.com/ytspar/devbar

License

MIT

Credits