この記事の結論
playwright-cliは、ログイン済みのChromeで同じ操作を何十回も回す仕事(note下書き100本・社内書類のPDF35通)で、Playwright MCPより向いていました。罠と使い分けも書きます。料金はどちらも無料です。
目次9項目
- playwright-cliとPlaywright MCPの違い:同じPlaywrightを、シェルから打つかツールで呼ぶか
- 僕の会社のplaywright-cliの使い方:ログイン状態を写した専用Chromeにattachする
- 下書き100本の投入で決めた型:fillを使わない・run-codeに集約・やり直しは6回まで
- 別のフォルダから打つと「browser not open」:セッションはワークスペースごと
- 2026年8月21日、社内書類のPDF35通を一括で取った:タブは毎回context.pages()で探す
- 2026年8月6日の記録:50本の投入中にChromeが固まった「残骸のタブ」
- playwright-cliとPlaywright MCPの使い分け:僕の会社の線引き
- まとめ
- よくある質問
【無料・メールだけ】Claude Code 2daysセミナー(第二の脳構築講座)の次回開催の案内を受け取る →
playwright-cliとPlaywright MCPで迷ったとき、僕が選んだのはplaywright-cliでした。ログイン済みの専用Chromeにつないで、同じ操作を何十回も回す仕事だったからです。どちらもPlaywright本体と同じく無料のオープンソースで、差が出るのは料金ではなく、AIへの渡し方でした。
2026年7月11日には、この仕組みでnoteの下書き100本を投入しました。8月21日には、社内書類のPDF35通の一括取得にも使っています。別のフォルダから打つと「browser not open」になる罠も踏みました。
この記事では、2つの違いと料金、僕の会社のつなぎ方、実際に踏んだ罠と直し方を順に書きます。「MCPを入れたけれど、結局どっちを使えばいいの?」と迷っている方に向けた実録です。
playwright-cliとPlaywright MCPの違い:同じPlaywrightを、シェルから打つかツールで呼ぶか
違いは、AIがブラウザを動かすときの窓口です。playwright-cli はシェルのコマンドで打ち、Playwright MCP はMCPのツールとして呼ばせます。中身はどちらもMicrosoftのPlaywrightです。
ここでいうMCPとは、AIを外部のツールやデータにつなぐための共通の規格です。Playwright MCP は、その規格でブラウザ操作を渡すサーバーにあたります。
MCPの仕組みと接続先の選び方は、MCPとは?MCPサーバーの仕組みと接続先で詳しく書きました。
公式のリポジトリに書かれている範囲で、2つを並べます。比べているのは、入れ方・呼び方・公式が勧める場面の3点です。
| 項目 | playwright-cli | Playwright MCP |
|---|---|---|
| パッケージ | @playwright/cli | @playwright/mcp |
| 入れ方 | npm install -g @playwright/cli@latest | claude mcp add playwright npx @playwright/mcp@latest など |
| 呼び方 | playwright-cli goto などのコマンド | AIがツールとして呼ぶ |
| 公式が勧める場面 | コーディングエージェント | 探りながらの操作・状態を保つ長い自動化 |
| ライセンス | Apache-2.0 | Apache-2.0 |
公式の説明では、CLIは大きなツールの定義やページの構造を丸ごとAIに読ませないので、トークンの効率がよいとされています。MCPは、ブラウザの状態を保つ価値がトークンの費用より大きい場面向けです。
僕なら、手順が決まっている作業はCLI、何が起きるか分からない作業はMCPに分けます。
Playwright MCPの料金は無料、かかるのはAI側の利用料
Playwright MCP にも playwright-cli にも、料金の案内はありません。Playwright本体も含めて、3つとも公式のリポジトリに Apache-2.0 のライセンスと書かれています。
お金がかかるとすれば、操作を指示するAIの利用料のほうです。公式がCLIのトークン効率を強調しているのは、ここに効くからだと読んでいます。なお僕の会社では、2つの使い方でトークンの量を比べた計測はしていません。
僕の会社のplaywright-cliの使い方:ログイン状態を写した専用Chromeにattachする
僕の会社では、普段使いのChromeのログイン状態を写した専用のChromeを立て、そこへ playwright-cli をつないでいます。普段のChromeには手を触れないので、作業中も自分のブラウザはそのまま使えます。
きっかけは2026年6月18日の社内のメモです。Playwright MCP から「CLIとスキル」の組み合わせへの乗り換えを検討すると書きました。いまは接続の担当と、サイトごとの操作の担当を別のスキルに分けています。
つなぐ手順は、社内のスクリプト1本にまとめています。最初の1回だけ普段のChromeを閉じてログイン状態を写し、2回目からは専用のChromeにすぐつなぎます。中でやっていることを短くすると、次の形です。
# 専用のプロファイルで、リモートデバッグのポートを開けてChromeを起動(値は伏せています)
"<Chromeの実行ファイル>" --user-data-dir="<専用のプロファイル>" --remote-debugging-port=<port> &
# そのChromeに playwright-cli をつなぐ
playwright-cli -s=chrome attach --cdp="http://127.0.0.1:<port>"
# あとは同じセッション名で操作する
playwright-cli -s=chrome goto "https://example.com/"
playwright-cli -s=chrome snapshot --filename=snap.yml
公式のドキュメントにも、CDP(Chromeを外から操作する窓口)のURLを渡してつなぐ方法が載っています。起動中のChromeにチャンネル名でつなぐ方法もあり、そちらはChrome側でリモートデバッグを許可しておく必要があります。
終えるときは detach を使います。公式では、detach はつないだブラウザに触れずにセッションだけを終え、close は CLI が自分で起動したブラウザにだけ使う、と分けています。
つないだChromeは全部を操作される
社内のルールでは、つないだChromeは中の保存データも含めて全部を操作できる、と書いています。だから銀行やパスワード管理のタブは、つなぐ前に閉じます。信用できる作業にだけ使う、というのが決まりです。
ログイン状態を写す方式にしたのは、自動のログインの手順を作らずに済むからです。そのぶん、つないでいる間のChromeは「自分のアカウントで何でもできる状態」だと考えて扱っています。
reloadしない・編集画面へ直接のURLで飛び続けない
社内のスキルには、ブラウザ側の禁止事項も2つ書いています。1つ目は reload の禁止です。noteのような離脱の確認を出すエディタは、再読み込みすると確認が出たまま固まる、と書いています。
2つ目は、編集画面へ直接のURLで続けて移るのをやめる点です。続けて飛ぶと前の記事の値が新しいエディタに残る、と記録しています。投入のスクリプトは、同じURLが続いたら自動で止まるようにしています。
並行で別の作業を回したいときは、同じChromeを取り合わせません。接続のスクリプトに別の名前を渡すと、ポートとプロファイルを分けた独立のChromeが立ち、別のセッション名で操作できます。
下書き100本の投入で決めた型:fillを使わない・run-codeに集約・やり直しは6回まで
noteの下書きの投入で、playwright-cli の使い方の型が決まりました。本文に fill を使わない、1記事の作業を1回の run-code にまとめる、離脱の確認が出たら最大6回やり直す、の3つです。
この投入は、2026年7月11日に下書き100本を一度に入れたときのものです。ここでは playwright-cli の側で何を決めたかだけを書きます。
当日の時間・本数・失敗の回数は、note下書き100本をAIで作った日の記録に全部残しました。
本文に fill を使わず、キー入力で段落を分ける
noteのエディタでは、fill で本文を入れると改行がすべて段落になり、行間が均等に開いてしまいました。僕が2回NGを出した仕上がりです。タイトル欄は普通の入力欄なので、fill で問題ありません。
本文は、まとまりの中の改行を Enter キー、まとまりの間を段落の区切りとして、1行ずつ打ち込む形に変えました。打つ前には毎回、ページのJavaScriptで入力位置を本文の一番最後へ置き直しています。
置き直しを足したのは、まとまりの境目で句点が次の段落の頭へずれたからです。キー操作で末尾へ動かすと、最後の1文字の手前で止まることがありました。
1記事の作業を1回の run-code にまとめる
run-code は、Playwright のコードを1つの関数として渡して実行するコマンドです。公式の説明では、関数は今のページを受け取り、返した値がそのまま表示されます。
僕の会社では、タイトル・本文・見出しの変換・下書き保存・URLの取得までを、1回の run-code に詰めています。コマンドを細かく分けると、その隙間に確認の画面が割り込み、次のコマンドが止まったからです。
playwright-cli -s=chrome goto "about:blank"
playwright-cli -s=chrome goto "<新規作成のURL>"
playwright-cli -s=chrome run-code "async page => {
// タイトルを入れる → 本文を1行ずつ打つ → 保存 → URLを返す
return 'DONE|' + page.url();
}"
run-code の中では import も require も使えないと公式に書かれています。ファイルに書き出したいときは、返した値を外で受け取って処理します。
離脱の確認はgotoで抜け、6回までやり直す
noteの編集画面は、離れようとすると「保存されていません」系の確認を出します。これが残ると、run-code も snapshot も「does not handle the modal state」で止まりました。
公式のドキュメントにも、ダイアログを処理するまでほかの操作は進まないと書かれています。僕の環境では、この確認は run-code の中のページ移動では抜けられず、専用の goto コマンドなら抜けられました。
そこで、goto で空のページへ移ってから新規作成の画面を開き、そのあと1回の run-code を流す形にしました。この表示が出たら2秒待って同じ流れをやり直し、6回まで試します。
別のフォルダから打つと「browser not open」:セッションはワークスペースごと
playwright-cli で「browser not open」と出たら、まず実行しているフォルダを確かめます。僕の会社では、attach したときと違うフォルダから打つと、つないだはずのChromeが見えなくなりました。
公式のドキュメントでは、playwright-cli list は今のワークスペースのセッションを表示し、--all ですべてに広がります。プロファイルの置き場所も、ワークスペースとセッション名から決まります。
ワークスペースが何を指すかは、公式のページに定義がありません。僕の記録は「社内ノートのフォルダから実行しないと browser not open になる」で、実行する場所でセッションが分かれると受け止めています。
だから playwright-cli は必ず同じフォルダから実行し、つながっているかを先に playwright-cli list で確かめます。見当たらなければ list --all で、別の場所に残っていないかを見ます。
playwright-cli list # 今のワークスペースのセッション
playwright-cli list --all # すべてのワークスペース
2026年8月21日、社内書類のPDF35通を一括で取った:タブは毎回context.pages()で探す
2026年8月21日に、Webの業務サービスにある社内書類のPDFを、2か月分で計35通まとめて取りました。内訳は19通と16通です。使ったのは、ログイン済みの専用Chromeと playwright-cli でした。
画面で1通ずつ保存するのではなく、ログイン済みのタブの中から書類のデータを直接取りにいく形です。ページ内の fetch に credentials: 'include' を付けると、ログイン状態のまま取れました。
アクティブなタブは、いつの間にか切り替わる
この作業で決めたのは、対象のタブを毎回 context.pages() から探す運用です。専用のChromeは、ほかのセッションや僕自身の操作で、前に出ているタブが入れ替わることがあります。
run-code が受け取る page は、その時点のタブです。前に出ているタブを信じて操作すると、別のサービスの画面で動いてしまうおそれがあります。だからURLで目的のタブを特定してから、その中で処理を走らせます。
playwright-cli -s=chrome run-code "async page => {
const tab = page.context().pages()
.find(p => p.url().startsWith('https://<サービスのドメイン>/'));
if (!tab) return 'NO_TAB';
return await tab.evaluate(async (url) => {
const res = await fetch(url, { credentials: 'include' });
const bytes = new Uint8Array(await res.arrayBuffer());
let bin = '';
for (const b of bytes) bin += String.fromCharCode(b);
return btoa(bin);
}, '<書類のURL>');
}" > out.txt
run-code の中ではファイルを書けないので、PDFは文字列(base64)にして返し、出力をファイルに受けました。そのあと Python で中身を取り出して、PDFに戻しています。
保管先へのアップロードは2段構えにした
取ったPDFを共有のクラウドストレージに画面からアップロードすると、開いているフォルダではなく、一番上の階層に落ちました。目的のフォルダを開いた状態でも同じでした。
そこで、画面からのアップロードは複数のファイルをまとめて上げるところまでにしました。正しいフォルダへの移動は、ストレージのAPIで行う2段構えです。
2026年8月6日の記録:50本の投入中にChromeが固まった「残骸のタブ」
2026年8月6日に記録した50本の投入では、途中でChrome全体が固まり、あとの投入がすべて止まる罠がありました。離脱の確認を抱えたまま空のページへ移った編集画面が、タブの残骸として残っていたのが原因です。
残骸のタブは、URLだけが about:blank で、タイトルは記事の編集画面のままでした。これが残ると modal-blocked-or-no-url の失敗が続き、安全装置が働いて投入が止まりました。
直すのにChromeの再起動は要りませんでした。Chromeの開発者向けの窓口でタブの一覧を取り、残骸の1枚だけを閉じて、もう一度 attach すると戻ります。記録では、12本に1回ほどの割合で起きています。
curl http://127.0.0.1:<port>/json/list # タブの一覧(idとURL・タイトル)
curl http://127.0.0.1:<port>/json/close/<タブのid> # 残骸の1枚だけを閉じる
成功のログでも、画像は付いていなかった
同じ50本では、アイキャッチ画像が付いていない記事が24本ありました。画像を付ける処理の失敗を、投入のスクリプトが握りつぶしていたため、ログは成功のままでした。
未設定の記事を拾って付け直す処理を回すと、1回目で24本中18本、2回目で3本、3回目で2本が直りました。最後の1本は3回とも失敗し、手で付けています。いまは、投入と画像の確認までを1セットにしています。
1本あたりの時間も、7月の100本のときは約1分、このときは約5分でした。記事の長さとタブの数で変わるので、50本なら3時間強を見込むようにしています。
playwright-cliとPlaywright MCPの使い分け:僕の会社の線引き
僕の会社では、両方を入れたまま、作業の性質で分けています。Playwright MCP は2026年6月14日に、LPの死活の確認とフォームの送信テストに使う用途でプラグインとして入れました。
プラグインの選び方と、そのとき入れた7個の内訳はClaudeのmarketplacesとプラグイン導入の実録に書きました。
いまの線引きを、作業ごとに並べます。基準は「ログイン状態が要るか」と「同じ手順を何回回すか」の2つです。
| 作業 | 使う道具 | 理由 |
|---|---|---|
| ページを読む・ちょっと確かめる | Claude Code のアプリ内のブラウザ | 自分のChromeに触れずに済む |
| LPの死活の確認・フォームの送信テスト | Playwright MCP | 手順が短く、ログインが要らない |
| ログインが要る画面で同じ手順を何十回も回す | playwright-cli+専用のChrome | ログイン状態を使い回せて、1回の run-code にまとめられる |
| ログインが要る画面のデータをまとめて取る | playwright-cli+専用のChrome | 対象のタブの中から直接取りにいける |
迷ったら、まずアプリ内のブラウザで済むかを考えます。2026年8月21日からは、ブラウザの作業は原則アプリ内で行い、実際のChromeを動かすときは僕の明示のOKを取る決まりです。
この決まりの経緯は、Claude Codeのアプリ内ブラウザでログインする方法に書いています。
接続の台帳でも、Playwright MCP は許可の確認が毎回出る設定の対象で、使うたびに明示のOKが要る扱いにしています。
まとめ
- playwright-cli と Playwright MCP は、同じPlaywrightを「シェルのコマンド」で動かすか「MCPのツール」で動かすかの違い
- 料金はどちらも無料(Apache-2.0)。かかるのはAI側の利用料で、公式はCLIのほうがトークンの効率がよいとしている
- 本文に
fillを使わない・1記事を1回のrun-codeにまとめる・確認はgotoで抜けて6回までやり直す、が下書き投入で決めた型 - 「browser not open」はまず実行フォルダを疑い、
playwright-cli listで確かめる。対象のタブは毎回context.pages()から探す - 僕なら、ログインが要る画面で同じ手順を何回も回す作業から playwright-cli を試し、それ以外はアプリ内のブラウザかMCPで済ませます
よくある質問
Playwright MCPを使うのに料金はかかりますか?
Playwright MCP自体の料金はかかりません。公式のリポジトリは Apache-2.0 のオープンソースで、料金の案内もありません。playwright-cli も同じです。かかるのは、操作を指示するAI側の利用料です。
playwright-cliとPlaywright MCPはどちらを使えばいいですか?
決まった手順を何十回も回すならplaywright-cliです。公式も、コーディングエージェントにはCLIのほうがトークンの効率がよいとしています。画面を見ながら探る作業や、ブラウザの状態を保ったまま長く動かす作業は、MCPが向いています。
playwright-cliで「browser not open」と出るのはなぜですか?
別のフォルダから実行している可能性があります。セッションはワークスペースごとに管理され、僕の環境では attach したときと違うフォルダから打つとこの表示になりました。いつも同じフォルダから実行し、`playwright-cli list` で確かめます。
playwright-cliで普段のChromeのログイン状態は使えますか?
使えます。`attach --cdp` で、起動しているChromeにつなげます。僕の会社では、ログイン状態を写した専用のChromeを別に立ててつないでいます。つないだChromeは全部を操作されるので、銀行などのタブは先に閉じます。
