<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Puppeteer on KnightLi Blog</title>
        <link>https://knightli.com/en/tags/puppeteer/</link>
        <description>Recent content in Puppeteer on KnightLi Blog</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en</language>
        <lastBuildDate>Sun, 24 May 2026 17:51:28 +0800</lastBuildDate><atom:link href="https://knightli.com/en/tags/puppeteer/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>browser-harness, Playwright, and Puppeteer: which browser automation tool should you choose?</title>
        <link>https://knightli.com/en/2026/05/24/browser-harness-playwright-puppeteer-comparison/</link>
        <pubDate>Sun, 24 May 2026 17:51:28 +0800</pubDate>
        
        <guid>https://knightli.com/en/2026/05/24/browser-harness-playwright-puppeteer-comparison/</guid>
        <description>&lt;p&gt;In browser automation and automated testing, &lt;code&gt;Playwright&lt;/code&gt; and &lt;code&gt;Puppeteer&lt;/code&gt; are two of the most commonly compared tools. Both can control browsers, click pages, extract content, generate screenshots or PDFs, and both are closely related to Chrome DevTools Protocol.&lt;/p&gt;
&lt;p&gt;Once &lt;code&gt;browser-use/browser-harness&lt;/code&gt; is added to the picture, the question is no longer simply “which testing framework is stronger.” It becomes a comparison between two kinds of tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Playwright&lt;/code&gt; / &lt;code&gt;Puppeteer&lt;/code&gt;: tools for engineers to write deterministic scripts.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;browser-harness&lt;/code&gt;: a tool for AI agents to operate real browsers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first group fits testing, scraping, and engineered automation. The second is closer to a browser control layer for agents such as Claude Code, Codex CLI, and Gemini.&lt;/p&gt;
&lt;h2 id=&#34;the-relationship-between-playwright-and-puppeteer&#34;&gt;The relationship between Playwright and Puppeteer
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Puppeteer&lt;/code&gt; was originally launched by the Google Chrome team and naturally focuses on Chromium and Chrome automation. Its API is concise, the ecosystem is mature, and it is especially convenient for screenshots, PDF generation, page scraping, and lightweight automation around Chrome.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Playwright&lt;/code&gt; is maintained by Microsoft, and its team has deep historical links to early Puppeteer work. It absorbed many lessons from Puppeteer and added stronger cross-browser support, auto-waiting, context isolation, test reports, and debugging tools.&lt;/p&gt;
&lt;p&gt;In short:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you only need lightweight Chrome-based tasks, &lt;code&gt;Puppeteer&lt;/code&gt; is still very pleasant to use.&lt;/li&gt;
&lt;li&gt;If you are doing cross-browser E2E tests, complex SPA automation, or team-level test engineering, &lt;code&gt;Playwright&lt;/code&gt; is usually the better fit.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;core-differences&#34;&gt;Core differences
&lt;/h2&gt;&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Dimension&lt;/th&gt;
          &lt;th&gt;Puppeteer&lt;/th&gt;
          &lt;th&gt;Playwright&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Maintainer&lt;/td&gt;
          &lt;td&gt;Google&lt;/td&gt;
          &lt;td&gt;Microsoft&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Browser support&lt;/td&gt;
          &lt;td&gt;Mainly Chrome / Chromium&lt;/td&gt;
          &lt;td&gt;Chromium, Firefox, WebKit&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Language support&lt;/td&gt;
          &lt;td&gt;Mainly JavaScript / TypeScript&lt;/td&gt;
          &lt;td&gt;JavaScript / TypeScript, Python, Java, .NET&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Auto-waiting&lt;/td&gt;
          &lt;td&gt;More explicit waiting&lt;/td&gt;
          &lt;td&gt;Strong Locator and auto-waiting&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Context isolation&lt;/td&gt;
          &lt;td&gt;Supported, but less central&lt;/td&gt;
          &lt;td&gt;Excellent BrowserContext workflow&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Tooling&lt;/td&gt;
          &lt;td&gt;Simple, mature, foundational&lt;/td&gt;
          &lt;td&gt;Codegen, Trace Viewer, reports&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Typical use&lt;/td&gt;
          &lt;td&gt;Chrome automation, screenshots, PDF, lightweight scraping&lt;/td&gt;
          &lt;td&gt;Cross-browser E2E tests, complex frontend automation&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;browser-support&#34;&gt;Browser support
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Puppeteer&lt;/code&gt; is strongest with Chrome. It integrates tightly with Chromium. If your goal is to control Chrome, generate PDFs, take screenshots, or run simple scraping tasks, Puppeteer has a low mental overhead.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Playwright&lt;/code&gt; is stronger for cross-browser work. It natively supports Chromium, Firefox, and WebKit. WebKit is especially important because many Safari-related issues cannot be detected through Chrome alone. For applications that need coverage across desktop, mobile, and multiple browser engines, Playwright is the better main tool.&lt;/p&gt;
&lt;p&gt;This is the first decision boundary: if you only care about Chrome, Puppeteer is fine. If you are serious about cross-browser testing, choose Playwright first.&lt;/p&gt;
&lt;h2 id=&#34;auto-waiting-and-stability&#34;&gt;Auto-waiting and stability
&lt;/h2&gt;&lt;p&gt;The most annoying part of browser automation is often not “how to click,” but whether the page is ready. An element may not be attached to the DOM, may be covered, may still be animating, or may still be disabled.&lt;/p&gt;
&lt;p&gt;In Puppeteer, you often write:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;waitForSelector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;#submit-btn&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;click&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;#submit-btn&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This works, but engineers must think through the waiting logic themselves. The more complex the page, the more likely the script will accumulate &lt;code&gt;waitForSelector&lt;/code&gt;, &lt;code&gt;waitForTimeout&lt;/code&gt;, and retry logic.&lt;/p&gt;
&lt;p&gt;Playwright’s Locator and auto-waiting mechanism is more complete:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;locator&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;#submit-btn&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;click&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Before clicking, Playwright checks whether the element is visible, actionable, stable, and not covered, then retries within a reasonable time. This matters a lot for modern React, Vue, and Next.js applications with heavy asynchronous rendering, and it reduces flaky tests.&lt;/p&gt;
&lt;h2 id=&#34;multi-account-workflows-and-context-isolation&#34;&gt;Multi-account workflows and context isolation
&lt;/h2&gt;&lt;p&gt;If you need to simulate multiple users, or let many tasks share one browser process while isolating Cookie, LocalStorage, and Session, &lt;code&gt;BrowserContext&lt;/code&gt; matters.&lt;/p&gt;
&lt;p&gt;Puppeteer also supports context isolation, but Playwright makes it a core capability. You can quickly create multiple independent contexts inside one browser instance. Each context behaves like a clean browser environment without repeatedly starting full browser processes.&lt;/p&gt;
&lt;p&gt;This is useful for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Multi-account concurrent tests.&lt;/li&gt;
&lt;li&gt;Multi-role workflow tests.&lt;/li&gt;
&lt;li&gt;Ecommerce, messaging, and collaborative document scenarios.&lt;/li&gt;
&lt;li&gt;Scraping tasks that need isolated Cookie and login state.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;tooling-differences&#34;&gt;Tooling differences
&lt;/h2&gt;&lt;p&gt;Playwright is the more engineering-oriented option. It includes many tools used in test development:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;codegen&lt;/code&gt;: operate on a webpage and generate scripts automatically.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Trace Viewer&lt;/code&gt;: replay screenshots, DOM snapshots, network requests, and console logs after failures.&lt;/li&gt;
&lt;li&gt;Test Runner: assertions, parallelism, retries, reports, and project matrices.&lt;/li&gt;
&lt;li&gt;Locator: element selection by text, role, label, test id, and CSS.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Puppeteer is more like a lightweight browser control library. It is not bloated, its API is direct, and it is easy to embed in scripts, server-side jobs, and custom automation flows.&lt;/p&gt;
&lt;p&gt;If you are building an enterprise-grade test system, Playwright’s tooling saves a lot of work. If you only need a Node.js script to convert webpages to PDFs or take scheduled screenshots, Puppeteer may be cleaner.&lt;/p&gt;
&lt;h2 id=&#34;where-browser-harness-fits&#34;&gt;Where browser-harness fits
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;browser-harness&lt;/code&gt; is not the same kind of tool as Playwright or Puppeteer.&lt;/p&gt;
&lt;p&gt;Playwright and Puppeteer mostly assume that humans write scripts. Engineers choose selectors, waiting conditions, assertions, and exception handling. They pursue determinism: the same script should produce the same result under the same page state.&lt;/p&gt;
&lt;p&gt;browser-harness mostly assumes that an AI agent operates the browser. Its goal is not to provide a huge high-level API, but to connect to real Chrome through CDP and expose screenshots, coordinate clicks, DOM, network requests, and helpers to the agent. The agent can observe the page, decide the next step, add helpers when capabilities are missing, and turn site experience into skills.&lt;/p&gt;
&lt;p&gt;That makes it better for open-ended tasks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Log in to a backend and download invoices.&lt;/li&gt;
&lt;li&gt;Fill a group of forms in an internal system.&lt;/li&gt;
&lt;li&gt;Handle OA or SaaS pages that change often.&lt;/li&gt;
&lt;li&gt;Explore a page according to a user goal instead of running a fixed script.&lt;/li&gt;
&lt;li&gt;Give tools such as Claude Code and Codex CLI browser operation capability.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;three-way-comparison&#34;&gt;Three-way comparison
&lt;/h2&gt;&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Dimension&lt;/th&gt;
          &lt;th&gt;Puppeteer&lt;/th&gt;
          &lt;th&gt;Playwright&lt;/th&gt;
          &lt;th&gt;browser-harness&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Target user&lt;/td&gt;
          &lt;td&gt;Engineers&lt;/td&gt;
          &lt;td&gt;Engineers and test teams&lt;/td&gt;
          &lt;td&gt;AI Agent&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Main goal&lt;/td&gt;
          &lt;td&gt;Control Chrome&lt;/td&gt;
          &lt;td&gt;Stable cross-browser automation&lt;/td&gt;
          &lt;td&gt;Let agents operate real browsers&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Script style&lt;/td&gt;
          &lt;td&gt;Hand-written JS/TS automation&lt;/td&gt;
          &lt;td&gt;Scripts plus test framework&lt;/td&gt;
          &lt;td&gt;User gives a goal, agent executes steps&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Element targeting&lt;/td&gt;
          &lt;td&gt;CSS, XPath, DOM API&lt;/td&gt;
          &lt;td&gt;Locator, text, role, CSS&lt;/td&gt;
          &lt;td&gt;Screenshots, coordinates, DOM, CDP&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Waiting&lt;/td&gt;
          &lt;td&gt;More manual control&lt;/td&gt;
          &lt;td&gt;Strong auto-waiting&lt;/td&gt;
          &lt;td&gt;Agent observes and adjusts&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Browser environment&lt;/td&gt;
          &lt;td&gt;Usually automated browser&lt;/td&gt;
          &lt;td&gt;Usually test browser&lt;/td&gt;
          &lt;td&gt;Often real Chrome&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Best fit&lt;/td&gt;
          &lt;td&gt;Chrome scripts, screenshots, PDF, lightweight scraping&lt;/td&gt;
          &lt;td&gt;E2E tests, cross-browser validation, complex SPA&lt;/td&gt;
          &lt;td&gt;AI assistants, open web tasks, real-account workflows&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;code-feel&#34;&gt;Code feel
&lt;/h2&gt;&lt;p&gt;Puppeteer feels closer to directly controlling Chrome:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;puppeteer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;puppeteer&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;browser&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;puppeteer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;launch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;page&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;browser&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;newPage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;goto&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;waitForSelector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;#submit-btn&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;click&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;#submit-btn&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;browser&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;})();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Playwright emphasizes Locator and auto-waiting:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;chromium&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;playwright&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;browser&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;chromium&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;launch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;page&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;browser&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;newPage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;goto&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;locator&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;#submit-btn&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;click&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;browser&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;})();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;browser-harness feels completely different. You usually do not write a full script. You give a goal inside an agent environment:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Open the admin panel, download last month’s invoice, and organize it for reimbursement.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The agent then repeatedly uses browser-harness to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Take screenshots and understand the current page.&lt;/li&gt;
&lt;li&gt;Click a coordinate or locate an element.&lt;/li&gt;
&lt;li&gt;Enter text, upload files, and download files.&lt;/li&gt;
&lt;li&gt;Decide how to close popups.&lt;/li&gt;
&lt;li&gt;Add helper code when something is missing.&lt;/li&gt;
&lt;li&gt;Turn reusable flows into domain skills.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is not the style of traditional test scripts. It is the workflow of a browser agent.&lt;/p&gt;
&lt;h2 id=&#34;how-to-choose&#34;&gt;How to choose
&lt;/h2&gt;&lt;p&gt;Choose &lt;code&gt;Puppeteer&lt;/code&gt; when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The project mainly runs in Node.js.&lt;/li&gt;
&lt;li&gt;You only need Chrome or Chromium.&lt;/li&gt;
&lt;li&gt;The task is screenshot, PDF generation, simple page scraping, or lightweight automation.&lt;/li&gt;
&lt;li&gt;You want a simple API, fewer dependencies, and more manual control.&lt;/li&gt;
&lt;li&gt;You rely deeply on Chrome DevTools Protocol.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Choose &lt;code&gt;Playwright&lt;/code&gt; when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You are building standard UI automation or E2E tests.&lt;/li&gt;
&lt;li&gt;You need Chromium, Firefox, and WebKit coverage.&lt;/li&gt;
&lt;li&gt;Your team’s main language may be Python, Java, or C#.&lt;/li&gt;
&lt;li&gt;The page is a complex SPA with many asynchronous states and potential flaky tests.&lt;/li&gt;
&lt;li&gt;You need codegen, Trace Viewer, test reports, and parallel testing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Choose &lt;code&gt;browser-harness&lt;/code&gt; when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You are building or using AI agents.&lt;/li&gt;
&lt;li&gt;You want the model to operate a real browser like a human.&lt;/li&gt;
&lt;li&gt;The task steps are not fixed and require page-by-page judgment.&lt;/li&gt;
&lt;li&gt;The target site changes often, or has many popups, iframes, and shadow DOM.&lt;/li&gt;
&lt;li&gt;You want real web workflows handled by Claude Code, Codex CLI, or similar tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Playwright&lt;/code&gt; and &lt;code&gt;Puppeteer&lt;/code&gt; are browser automation tools whose core goal is to let humans write reliable scripts. Puppeteer is lighter and closer to Chrome. Playwright is more complete and better for cross-browser testing and complex frontend applications.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;browser-harness&lt;/code&gt; is a different direction. It is not designed to replace Playwright or Puppeteer for tests. It is designed to let AI agents control real browsers. It gives up some traditional script determinism in exchange for stronger adaptability in open-ended tasks.&lt;/p&gt;
&lt;p&gt;So the answer is not to pick only one. Choose by task layer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Test engineering: prefer Playwright.&lt;/li&gt;
&lt;li&gt;Lightweight Chrome scripts: Puppeteer fits well.&lt;/li&gt;
&lt;li&gt;AI agents doing work on the web: look at browser-harness.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;References:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;browser-use/browser-harness: &lt;a class=&#34;link&#34; href=&#34;https://github.com/browser-use/browser-harness&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://github.com/browser-use/browser-harness&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Playwright documentation: &lt;a class=&#34;link&#34; href=&#34;https://playwright.dev/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://playwright.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Puppeteer documentation: &lt;a class=&#34;link&#34; href=&#34;https://pptr.dev/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://pptr.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Chrome DevTools Protocol: &lt;a class=&#34;link&#34; href=&#34;https://chromedevtools.github.io/devtools-protocol/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://chromedevtools.github.io/devtools-protocol/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        
    </channel>
</rss>
