chase-travel について
Chase Travel ポータルで航空券とホテルを検索するコマンドラインスキルです。現金・ポイント価格、Points Boost、Chase Edit の特典を取得します。ポータル予約と現金運賃、航空会社へのポイント移行を比較する用途向けで、Patchright とヘッド付きブラウザーが必要です。
主な機能
- 01航空券とホテルの検索
- 02現金・ポイント・併用価格の表示
- 03Points Boost オファーの検索
- 04Chase Edit ホテル特典の確認
- 05SMS とアプリ承認の二要素認証
- 06JSON 形式での結果出力
活用シーン
- 01ポータル価格と現金運賃の比較
- 02ポイント利用と移行の価値評価
- 03Edit 特典付きホテルの検索
- 04予約前の航空券候補の確認
MCP 対応
入力では旅行検索スキルと説明されていますが、MCP 連携については記載されていません。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ borski/ travel-hacking-toolkit --skill chase-travelインストール後、Claude Code で/chase-travelを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
Dockerfilescripts/record_search.pysearch_flights.pytests/test_2fa_method.py詳細
Chase Travel Portal の検索
Patchright を使用して、Chase Ultimate Rewards の旅行ポータルでフライトやホテルを検索します。現金価格、UR ポイントでの価格、Points Boost の特典、Chase Edit のホテル特典を取得します。
Patchright が必要です(検出回避機能を備えた Playwright のフォーク)。Chase は標準の Playwright と agent-browser をブロックします。
ヘッド付き(headless=False)で実行する必要があります。 Chase はヘッドレスブラウザーを検出します。macOS では Chrome のウィンドウが一時的に表示されます。バックグラウンドで実行する場合は、Docker を使用してください。
前提条件
pip install patchright && patchright install chromium
または、Docker を使用します(ローカルへのインストールは不要です)。
docker pull ghcr.io/borski/chase-travel:latest
# or build locally:
docker build -t chase-travel skills/chase-travel/
使用する場面
- UR ポータルの価格を現金価格や特典航空券の価格と比較する
- Points Boost の特典を確認する(一部の予約で cpp が 1.5 倍から 2.0 倍)
- 100 ドル分の施設クレジットと毎日の朝食が付く Chase Edit のホテルを探す
- ポイント払いと航空会社へのポイント移行の価値を比較する
使用しない場面
- 購入の完了。 フライトとホテルを探す場合に限ります。予約しないでください。
- Chase 以外のカード。 このスキルには Sapphire Reserve または Sapphire Preferred のカードが必要です。
カードの選択
スクリプトはアカウントセレクターから Sapphire Reserve カードを自動的に選択します(旅行予約では Points Boost の倍率が変動し、CSR では通常約 1.5~2.0 cpp ですが、最低倍率が保証されているわけではありません。Edit のホテル特典も利用できます)。Reserve が見つからない場合は、Sapphire Preferred にフォールバックします。Edit のホテル特典と旅行ポータルの価格が表示されるのは、これらのカードのみです。
使用方法
フライト検索
# Local (opens a Chrome window briefly)
python3 scripts/search_flights.py --origin SFO --dest CDG --depart 2026-08-11
# Round-trip business
python3 scripts/search_flights.py --origin SFO --dest CDG --depart 2026-08-11 --return 2026-09-02 --cabin business
# JSON output
python3 scripts/search_flights.py --origin SFO --dest CDG --depart 2026-08-11 --json
# Docker
docker run --rm \
-v ~/.chase-travel-profiles:/profiles \
-v /tmp:/tmp/host \
-e CHASE_USERNAME -e CHASE_PASSWORD \
ghcr.io/borski/chase-travel script /scripts/search_flights.py \
--origin SFO --dest CDG --depart 2026-08-11 --cabin business --json
ホテル検索
# Local
python3 scripts/search_flights.py --hotel --dest "Paris" --checkin 2026-08-11 --checkout 2026-08-15
# Docker
docker run --rm \
-v ~/.chase-travel-profiles:/profiles \
-v /tmp:/tmp/host \
-e CHASE_USERNAME -e CHASE_PASSWORD \
ghcr.io/borski/chase-travel script /scripts/search_flights.py \
--hotel --dest "Oslo" --checkin 2026-08-13 --checkout 2026-08-15 --json
記録モード(API の調査)
手動検索中のネットワークトラフィックを記録します。デバッグや新しい API エンドポイントの発見に役立ちます。
# Local only (needs interactive browser)
python3 scripts/record_search.py
2FA のフロー
Chase の 2FA では、SMS またはモバイルアプリのプッシュ通知が使用されます(アカウントによってはプッシュ通知のみの場合があります)。初回ログイン時は、手動で 2FA を完了する必要があります。その後はデバイスの信頼状態が維持され、同じプロファイルから次回以降に実行する際は 2FA がスキップされます。スクリプトはアカウントで利用できる方式を自動検出し、該当するフローを実行します。
仕組み: 2FA が開始されると、スクリプトは stdout に次のいずれかのセンチネルを出力し、その後、最長 3 分間ポーリングします。
2FA_CODE_NEEDED— SMS。Chase からコードが送信されました。下記の手順でコードを入力してください。MOBILE_APP_APPROVAL_NEEDED— モバイルアプリのプッシュ通知。コードはありません。ユーザーが Chase モバイルアプリでサインインを承認すると、ページが先に進んだ時点でスクリプトが続行します。
エージェント向け(SMS): 2FA_CODE_NEEDED が表示されたら、Chase から携帯電話に届いた SMS コードをユーザーに尋ねてください。コードを受け取ったら、コードファイルに書き込みます。
echo "12345678" > /tmp/chase-2fa-code.txt
スクリプトはファイルを自動的に検出し、ログインを続行します。
エージェント向け(モバイルプッシュ): MOBILE_APP_APPROVAL_NEEDED が表示されたら、Chase モバイルアプリでサインインを承認するようユーザーに伝えてください。入力するコードはありません。スクリプトは最長 3 分間、承認が届くまでポーリングしてから続行します。
コマンドフック(任意、完全自動化向け): CHASE_2FA_COMMAND に、コードを取得するまで処理をブロックし、その後 stdout にコードを出力するコマンドを設定します。スクリプトはファイルのポーリングの代わりに、このコマンドを実行します(SMS のフローのみが対象です)。
Docker: 一時ディレクトリを共有するには、-v /tmp:/tmp/host を使用します。スクリプトは /tmp/host/chase-2fa-code.txt と /tmp/chase-2fa-code.txt の両方を確認します。
初回ログインが成功してデバイスが信頼済みになると、次回以降の実行では 2FA がスキップされます。
認証情報は解決済みの値を指定してください
CHASE_USERNAME/CHASE_PASSWORDには、このスクリプトに渡す時点で実際のユーザー名とパスワードを設定する必要があります。シークレットをシークレットマネージャーに保管している場合は、起動前に参照先を環境変数に解決してください(ほとんどのマネージャーには、まさにその用途のexec/runラッパーが用意されています)。
解決されていない参照(scheme://vault/itemという文字列のままのプレースホルダー)はログインフォームに入力され、Chaseから「そのユーザー名とパスワードが見つかりません。もう一度お試しください。」と返されます。これはボット検出と誤解されやすいエラーです(ボット検出ではありません。Dockerからの新しい自動ログインは、実際の認証情報を使えば問題なく動作します。保存済みのCookieが期限切れの場合も含め、2026年7月にライブ環境で確認済みです)。
このような間違いは、どちらの場合もスクリプトが即座に検知して停止します。認証情報がまだシークレット参照のように見える場合、またはChaseからユーザー名/パスワードが見つからないと通知された場合、標準出力に**CHASE_BAD_CREDENTIALS**を出力し、2FAステータスファイルにBAD_CREDENTIALSを書き込みます。**エージェント向け:**このセンチネルを受け取った場合は再試行しないでください。認証情報の注入方法を修正してから、再実行してください。
動作の仕組み
フライト検索アーキテクチャ
- **認証:**Patchrightがログイン、2FA、Cookieの永続化、カード選択を処理します。アカウント識別子はポータルURLから自動抽出されます。
- セッション:
v1/session/createへのPOSTでCXL旅行セッションを確立します。識別子はCookieから自動抽出されます。 - **検索API:**Chaseの内部CTE APIに
POSTし、フライト検索セッションを作成します(sessionIdを返します)。 - **結果:**ブラウザーで
travelsecure.chase.com/results/flights/outbound?ssid={sessionId}&cnxtoken={redirectionToken}に移動します。スクリプトはpage.on('response')でAPIレスポンスをインターセプトし、legwiseResultsのJSONを取得します。 - **ページネーション:**JavaScriptでShadow DOMの「さらに表示」ボタン(
<orxe-button>)をクリックし、すべてのフライトを読み込みます(1回に10件)。 - **Points Boost:**Shadow DOMのトグル(
<orxe-toggle class="points-offer">)を有効にします。ブーストカードのカルーセルを解析し、割引後のポイント価格を取得します。
ホテル検索アーキテクチャ
- **検索API:**Chaseのホテル検索エンドポイントに
POSTし、セッションを作成します。 - **結果:**ブラウザーで結果ページに移動します。スクリプトは
hotel/v1.0/search/resultsのAPIレスポンスをインターセプトします。 - Editの検出:
prm[].c == "Signature Amenities"のホテルはEdit対象施設です。特典は埋め込みJSONから取得します。 - Boostの検出:
rwd[].rdp.rcm.t.ofr.d == "Points offer applied"のホテルにはPoints Boostが適用されています。 - **ページネーション:**フライトと同じShadow DOMのパターンを使います。
データ構造
フライトの結果には、次の情報が含まれます。
- 現金価格、ポイント価格、現金とポイントを組み合わせた価格
- 元のポイント数とブースト後のポイント数を示すPoints Boostのオファー
- 運賃クラス(エコノミー、ベーシックエコノミー、ビジネススタンダード、ビジネスフレックスなど)
- 航空会社、時刻、所要時間、乗り継ぎ、機材を含むフライト区間
- 払い戻しの可否と変更ポリシー
ホテルの結果には、次の情報が含まれます。
- 1泊あたりの現金価格と合計金額
- ポイント価格
- 特典(朝食、クレジット、アップグレードなど)を含むEditプログラムの会員特典
- Points Boostの利用可否と適用レート
- 星評価、住所、アメニティ、払い戻しの可否
出力形式
必ずMarkdownの表を使用してください。
フライト
| # | 航空会社 | ルート | 乗り継ぎ | 所要時間 | 現金 | ポイント | Boost | CPP |
|---|---|---|---|---|---|---|---|---|
| 1 | Air France | SFO-CDG | 直行 | 10h 40m | $5,397 | 539,683 | 269,841 | 2.0 |
ホテル
| # | ホテル | プログラム | 1泊あたり | 合計 | ポイント | 特典 |
|---|---|---|---|---|---|---|
| 1 | Sommerro | EDIT, BOOST | $408 | $816 | 81,600 | 朝食、$100のクレジット、アップグレード |
表の後に
- Edit対象のホテルを特典とあわせて記載します
- ポイントでの特典交換におけるCPPを計算します
- Points Boostのオファーには実質cppを示します
- 可能であれば、直接予約価格と比較します
- チェックアウト時に実際のPoints Boostの見積もりを取得します。CSRの価格設定は変動制で、固定倍率ではありません。
ポータルの料金に関する注意事項
- CSR の Chase ポータルの料金は、動的な Points Boost 方式です。従来の固定 1.5 倍の倍率は廃止されています。予約ごとに必要なポイント数が提示されます。CSR では実質的な cpp は通常 1.5〜2.0 cpp の範囲ですが、すべての予約で保証される最低値ではありません。
- Points Boost のオファーは、割引後のポイント価格が表示された個別のカードとして表示されます(実質的には通常 1.5〜2.0 cpp)。
cash_plus_points料金では、利用可能な UR ポイントをすべて使い、残額を現金で支払います。- Chase のセッションはブラウザーを閉じると保持されません。Docker を実行するたびに新たにログインする必要があります(デバイスが信頼済みの場合、2FA は省略されます)。
環境変数
| 変数 | 必須 | 説明 |
|---|---|---|
CHASE_USERNAME | はい | Chase オンラインバンキングのユーザー名 |
CHASE_PASSWORD | はい | Chase オンラインバンキングのパスワード |
CHASE_2FA_COMMAND | いいえ | SMS コードを受信するまでブロックし、標準出力に表示するコマンド |
CHASE_PROFILE | いいえ | ブラウザープロファイルのディレクトリ(デフォルト:~/.chase-travel-profiles/default) |
トラブルシューティング
- Docker のログインページで「Access Denied」と表示される: Chase は Docker からの
secure01ea.chase.comへのアクセスをブロックします。スクリプトは代わりにchase.comのホームページからログインします(認証エンドポイントが異なり、Docker で動作します)。 - 動画のモーダルによってクリックできない: スクリプトには、モーダルを自動的に削除する MutationObserver が含まれています。モーダルが表示され続ける場合は、オブザーバーが再レンダリングを処理します。
- API を直接呼び出すと CSRF エラーが発生する:
travelsecure.chase.comの検索結果 API には、React アプリが管理する CSRF トークンが必要です。スクリプトは API を直接呼び出す代わりにレスポンスのインターセプトを使うため、CSRF を完全に回避できます。 - フライトが見つからない: Chase が検索結果をまだ読み込んでいない可能性があります。スクリプトはインターセプトによって API レスポンスを待機するため、この問題は発生しないはずです。ログインが成功したか確認してください。
制限事項
- ヘッド付きモードが必須です。 Chase はヘッドレスモードを検出します。回避策として Docker と xvfb を使用します。
- 検索あたり約 30 秒かかります。 ログイン、ポータルの移動、検索、結果の読み込みが含まれます。
- ブラウザーを閉じるとセッションが終了します。 セッションは保持されません。実行のたびにログインが必要です(初回の信頼済み設定後は 2FA が省略されます)。
- React の制御対象入力フィールド: フォームの自動操作は不安定です。スクリプトはフォーム入力ではなく、検索の作成に API 呼び出しを使用します。