本文へスキップ
ブログ

ブログ

Shopify公式デモストアにAIエージェントを走らせたら、会員登録で止まった

13アクション・$0.53・スコア20/100。Shopifyが自社で公開しているデモストアで、この結果でした。

公開 更新 computer-useshopifyplaywrightagentic-commerce

【2026-09-02 注記】この記事が根拠にしている公開デモ(hydrogen.shop)の停止について、内部監査を受けて再検証しました。当社の検知記録は実在します(recaptcha / hcaptcha / g-recaptcha の3パターンに反応)。一方でこの走行は画面の証拠を保存しておらず、今日の hydrogen.shop では同じ検知が再現しません。つまり第三者が検算できない結果です。数字はそのまま残しますが、参考値として読んでください。検証できる形で計測できていなかったことは、当社の落ち度です。

3行で

  • Shopify公式のデモストア hydrogen.shop に、Claude computer-use で実際にブラウザ操作させた
  • 会員登録フォームでCAPTCHAに阻まれて停止(13アクション・$0.53・スコア 20/100)
  • AI経由のEC注文はグローバルで前年比15倍。なのに「エージェントが実際に買えるか」を測る手段がほぼ無い

なぜ測ろうと思ったか

数字から入ります。

  • AI検索経由の注文数は、2025年1月→2026年1月の1年でグローバル15倍Shopify Japan
  • 日本の20〜60代で「商品を探す際にAI検索を使ったことがある」は64.0%(2025年12月時点。2025年4月調査の47.1%から急伸)(SEMリサーチ
  • AI経由セッションのCVRはオーガニック検索比 +49%(同上)

つまり「AIエージェント経由の客」は、来る量も質も上がっている。一方で、自分のサイトがエージェントから実際に操作できるのかを確かめる手段が見当たりませんでした。

「llms.txt があるか」「JSON-LD が入っているか」を静的に採点するツールは既にいくつもあります。ただそれは *発見されやすさ* の話であって、*実際にフォームを埋めてカートに入れて決済直前まで行けるか* は別問題です。

なので、実際に走らせるものを作りました。

作ったもの

  • Playwright で実ブラウザを起動し、スクリーンショットを Claude computer-use API に渡して、返ってきた座標でクリック・入力する
  • サイトごとの手順はハードコードしない。自然言語のゴールだけ渡して、UIの探索はエージェントに任せる(そうしないと「エージェントの実力」ではなく「私が書いたスクリプトの精度」を測ることになる)
  • ステップごとにスクリーンショットを保存し、どこで何が起きたかを残す

測っている6ステップ

ステップ配点
トップページ到達・主要CTA発見20
会員登録フォーム到達・全項目の自動入力20
ログイン成功15
商品検索・閲覧15
カート投入15
決済直前画面到達15

安全側の設計(ここが本題かもしれない)

他人のサイトに自動化エージェントを走らせるツールなので、ここは妥協していません。

1. 購入確定は、コードで機械的に拒否する

エージェントへのプロンプトに「購入確定ボタンは押さないでください」と書くだけでは不十分です。LLMの指示追従は確率的なので、必ず破る日が来ます。

なので、ハーネス側でクリック実行の直前に対象要素のテキストを禁止語リスト(注文する 今すぐ購入 Place order Pay now 等)と照合し、一致したらエージェントの判断に関わらずクリックを捨てます。そしてその時点を「決済直前画面に到達=成功」として記録し、セッションを正常終了させます。

// クリック実行の直前。LLMの意図は無視する。
const guard = evaluateClickText(elementText);
if (!guard.allowed && guard.treatAsCheckoutReached) {
  // クリックせずに「決済直前まで到達」として正常終了
}

2. CAPTCHAは突破しない

検知したら即座に captcha_block として記録して停止します。突破してしまうと、そもそも測定対象そのものを壊すことになります(後述)。

3. 同意が無いと型レベルで実行できない

consent_confirmed_byconsent_date を持つブランド型 ValidConsent を作り、それ以外では実行関数を呼べないようにしています。バリデーションで弾くのではなく、呼び出しの型が通らない設計です。

const ConsentBrand: unique symbol = Symbol("ValidConsent");
export type ValidConsent = {
  readonly [ConsentBrand]: true;
  readonly consent_confirmed_by: string;
  readonly consent_date: string;
};
// createConsentToken() だけがこの型を作れる
export async function runAgentQaSession(consent: ValidConsent, ...)

4. 名乗る

AgentQA-Bot/1.0 (+連絡先URL) という専用 User-Agent で動きます。一般ブラウザのふりはしません。相手のサーバーログを見た人が「これは何だ」を追える状態にしておくべきだと考えています。

実行結果

Shopify が開発者向けに公開しているデモストア hydrogen.shop に対して実行しました。

Score:   20/100
Status:  stopped
Tags:    captcha_block
Actions: 13
Cost:    $0.5372
ステップ結果
トップページ到達・主要CTA発見
会員登録フォーム到達× ロボット確認(CAPTCHA)で停止
以降未到達

トップページは問題なく認識し、会員登録の導線も見つけました。フォームに到達して入力を進めた段階で、CAPTCHA が出て止まりました。

実測レポートの実物(スクリーンショット付き)はこちらです: https://www.agentrix.biz/ja/reports/a0fa49ca-52d3-4e2c-b03f-3242a2c471d8

この結果の読み方

「Shopify のデモストアがダメ」という話ではありません。むしろ逆で、CAPTCHA は人間に対しては正しく機能しています。問題は非対称性のほうです。

  • 人間がCAPTCHAで詰まった場合 → 苛立ち、離脱率として観測される
  • エージェントがCAPTCHAで詰まった場合 → エラーも出さず、ただ消える

サイト側のアクセス解析には「来なかった客」として一切残りません。CVRも下がらない(そもそもセッションが成立しない)。だから気づけない。

ここで止まったCAPTCHAは、Shopifyストアの店主が管理画面から消せるものではありません。店で直せる行と、Shopify側に投げるしかない基盤残差の切り分けはShopifyのプレイブックに表で並べてあります。

これが「AIエージェントは決済の手前で静かに離脱している」と考えている理由です。

実装でハマったところ

実サイトに走らせて初めて出たバグを2つ挙げます。どちらもローカルのfixtureテストでは絶対に出ませんでした。

1. キー名の方言

Claude computer-use が返すキー名は xdotool 系(ctrl, super, Return, prior)ですが、Playwright が期待するのは独自の名前(Control, Meta, Enter, PageUp)です。ctrl を1回押そうとしただけで keyboard.press: Unknown key: "ctrl" が飛び、セッションが丸ごと落ちました。

const KEY_ALIASES: Record<string, string> = {
  ctrl: "Control", super: "Meta", cmd: "Meta",
  return: "Enter", prior: "PageUp", next: "PageDown",
  up: "ArrowUp", down: "ArrowDown", /* ... */
};

export function normalizeKey(key: string): string {
  return key.split("+").map(normalizeKeyPart).filter(Boolean).join("+");
}

ctrl+a のような組み合わせもあるので、+ で分割してパーツごとに変換します。

2. 1アクションの失敗で全体が死ぬ

上のバグの本当の問題は、キー名そのものより「1つのアクションが例外を投げるとセッション全体が failed で終わる」構造のほうでした。実サイトでは、クリックしようとした要素が直前に消える、想定外のモーダルが出る、といったことが普通に起きます。1手ミスるたびに診断ごと落ちていたら使い物になりません。

let actionError: string | null = null;
try {
  await executeComputerAction(page, action);
} catch (err) {
  actionError = err instanceof Error ? err.message : String(err);
}
// 失敗はタイムラインに記録して、ループは続行する。
// エージェントは変化しなかった画面を観測して、別の手を試せる。

失敗をタイムラインに残したうえで続行するようにしました。エージェントは次のターンで「画面が変わっていない」ことを観測できるので、別のアプローチを試せます。

まとめ

  • AI経由のEC流入は実際に伸びているが、エージェントが本当に操作を完遂できるかを測る手段は手薄
  • 静的スコアリングではなく実際に走らせると、CAPTCHA・ラベル欠落・強制ログインといった具体的な停止点が出る
  • 他人のサイトに対して走らせる以上、同意ゲート・購入確定の機械的拒否・CAPTCHA非突破は、プロンプトではなくコードで担保すべき

同意をいただいたサイトに限り、無料で診断しています。初回と、直したあとの再診断1回。自社サイトを診断する

自分のサイトでも試す

同意をいただいたサイトに限り、無料で1本診断します。勝手なスキャンはしません。購入確定は押さず、CAPTCHAも突破しません。