# 放棄されたカートを回復する Checkout でのカート離脱を回復して、収益を向上させる方法をご紹介します。 # ホスト型ページ > This is a ホスト型ページ for when payment-ui is stripe-hosted. View the full page at https://docs.stripe.com/payments/checkout/abandoned-carts?payment-ui=stripe-hosted. E コマースでは、[カゴ落ち](https://docs.stripe.com/payments/checkout/compliant-promotional-emails.md)とは、顧客が購入の完了前に決済フローを離れる場合のことです。顧客を Checkout に戻すには、リカバリーフローを作成して、購入を完了するようメールで顧客に連絡をします。 カゴ落ちのメールは、広義では顧客に新製品について知らせたり、クーポンや割引を提供したりするための「プロモーションメール」カテゴリーに分類されます。顧客にメールを送信するには、顧客がプロモーションメールの受信に同意している必要があります。Checkout は以下に役立ちます。 1. プロモーションメールを送信できるように顧客からの同意を収集します。 1. 顧客が Checkout を破棄したときに通知を受け取り、カートの破棄に関するメールを送信できるようにします。 ## プロモーションへの同意を収集する [プロモーション用コンテンツへの同意を収集](https://docs.stripe.com/payments/checkout/promotional-emails-consent.md)するように Checkout を設定します。顧客のメールアドレスを収集して、Checkout にリダイレクトされる前にプロモーション用コンテンツへの同意をリクエストする場合、`consent_collection[promotions]` をスキップできます。 > #### Accounts v2 API を使用した顧客の表現 > > Accounts v2 API は、Connect ユーザー向けには GA、その他の Stripe ユーザー向けには公開プレビューとして提供されています。すべての Stripe ユーザーは [Dashboard](https://dashboard.stripe.com/settings/connect/platform-setup) で Accounts v2 を有効にできます。ただし、Accounts v2 API の呼び出し時には、プレビューユーザーは[プレビューバージョンを指定](https://docs.stripe.com/api-v2-overview.md#sdk-and-api-versioning)する必要があります。 > > ほとんどのユースケースでは、[Customer](https://docs.stripe.com/api/customers.md) オブジェクトを使用するのではなく、[顧客を顧客設定の Account オブジェクトとしてモデル化する](https://docs.stripe.com/connect/use-accounts-as-customers.md)ことをお勧めします。 #### Accounts v2 ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ -d "customer_account={{CUSTOMERACCOUNT_ID}}" \ -d mode=payment \ --data-urlencode "success_url=https://example.com/success" \ -d "consent_collection[promotions]=auto" ``` #### Customers v1 ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ -d "customer={{CUSTOMER_ID}}" \ -d mode=payment \ --data-urlencode "success_url=https://example.com/success" \ -d "consent_collection[promotions]=auto" ``` ## リカバリーを設定する Checkout セッションは、その [expires_at](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-expires_at) タイムスタンプに達すると、顧客が購入していなくても破棄されます。この場合、セッションにアクセスできなくなり、Stripe が `checkout.session.expired` *Webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) を起動します。この Webhook をリッスンすることで、顧客を新しい Checkout セッションに戻して購入を完了してもらう機会を作ることができます。この機能を使用するには、セッションの作成時に `after_expiration.recovery` を有効にします。 #### Accounts v2 ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ -d mode=payment \ --data-urlencode "success_url=https://example.com/success" \ -d "customer_account={{CUSTOMERACCOUNT_ID}}" \ -d "consent_collection[promotions]=auto" \ -d "after_expiration[recovery][enabled]=true" \ -d "after_expiration[recovery][allow_promotion_codes]=true" ``` #### Customers v1 ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ -d mode=payment \ --data-urlencode "success_url=https://example.com/success" \ -d "customer={{CUSTOMER_ID}}" \ -d "consent_collection[promotions]=auto" \ -d "after_expiration[recovery][enabled]=true" \ -d "after_expiration[recovery][allow_promotion_codes]=true" ``` ## カート放棄についての通知を受ける `checkout.session.expired` Webhook をリッスンすると、顧客が Checkout を破棄してセッションの有効期限が切れたときに通知が届きます。リカバリーが有効な状態でセッションの有効期限が切れた場合、Webhook ペイロードに [after_expiration](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-after_expiration-recovery) が含まれます。これには、カゴ落ち通知メールに埋め込み可能な URL (`after_expiration.recovery.url`) が記載されます。顧客がこの URL を開くと、**期限切れの元のセッションをコピーした新しい Checkout セッションが作成されます**。顧客は、このコピーセッションで購入を完了します。 > セキュリティ上の理由により、セッションのリカバリー URL の有効期間は 30 日に設定され、`after_expiration.recovery.expires_at` の日付をもって期限切れになります。 ```json { "id": "evt_123456789", "object": "event", "type": "checkout.session.expired", // ...other webhook attributes "data": { "object": { "id": "cs_12356789", "object": "checkout.session", // ...other Checkout Session attributes"consent_collection": { "promotions": "auto", }, "consent": { "promotions": "opt_in" }, "after_expiration": { "recovery": { "enabled": true, "url": "https://buy.stripe.com/r/live_asAb1724", "allow_promotion_code": true, "expires_at": 1622908282, } } } } } ``` ## リカバリーメールを送信する リカバリーメールを送信する場合、期限切れセッション用の Webhook ハンドラを作成して、セッションのリカバリー URL を記載したメールを送信します。顧客が複数の Checkout セッションを破棄し、それぞれの `checkout.session.expired` イベントが一斉にトリガーされることがあります。顧客にリカバリーメールを送信する際はその記録を残し、スパムメールと誤解されないよう配慮してください。 #### Node.js ```javascript // Find your endpoint's secret in your Dashboard's webhook settings const endpointSecret = 'whsec_...'; // Using Express const app = require('express')(); // Use body-parser to retrieve the raw body as a buffer const bodyParser = require('body-parser');const sendRecoveryEmail = (email, recoveryUrl) => { // TODO: fill me in console.log("Sending recovery email", email, recoveryUrl); } app.post('/webhook', bodyParser.raw({type: 'application/json'}), (request, response) => { const payload = request.body; const sig = request.headers['stripe-signature']; let event; try { event = stripe.webhooks.constructEvent(payload, sig, endpointSecret); } catch (err) { return response.status(400).send(`Webhook Error: ${err.message}`); }// Handle the checkout.session.expired event if (event.type === 'checkout.session.expired') { const session = event.data.object; // When a Checkout Session expires, the customer's email isn't returned in // the webhook payload unless they give consent for promotional content const email = session.customer_details?.email const recoveryUrl = session.after_expiration?.recovery?.url // Do nothing if the Checkout Session has no email or recovery URL if (!email || !recoveryUrl) { return response.status(200).end(); } // Check if the customer has consented to promotional emails and // avoid spamming people who abandon Checkout multiple times if ( session.consent?.promotions === 'opt_in' && !hasSentRecoveryEmailToCustomer(email) ) { sendRecoveryEmail(email, recoveryUrl) } } response.status(200).end(); }); ``` ## Optional: セッションの有効期限を調整する デフォルトでは、Checkout セッションは作成後 24 時間で期限が切れますが、`expires_at` を設定して有効期限を短縮し、より早いタイミングでカート放棄について通知を受けることができます。`expires_at` には、セッション作成の 30 分後以降を設定できます。 #### Accounts v2 #### cURL ```bash curl https://api.stripe.com/v1/checkout/sessions \ -u <>: \ -d customer_account='{{CUSTOMER_ACCOUNT_ID}}' \ -d "line_items[0][price]"='{{PRICE_ID}}' \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ -d success_url="https://example.com/success" \-d expires_at="{{NOW_PLUS_TWO_HOURS}}" ``` #### Customers v1 #### cURL ```bash curl https://api.stripe.com/v1/checkout/sessions \ -u <>: \ -d customer='{{CUSTOMER_ID}}' \ -d "line_items[0][price]"='{{PRICE_ID}}' \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ -d success_url="https://example.com/success" \-d expires_at="{{NOW_PLUS_TWO_HOURS}}" ``` ## Optional: コンバージョン率を追跡する 顧客が期限が切れた Checkout セッションのリカバリー URL を開くと、破棄されたセッションのコピーである新しい Checkout セッションが作成されます。 リカバリーメールがコンバージョンの成功に寄与したかどうかを確認するには、新しい Checkout セッションの `checkout.session.completed` Webhook で [recovered_from](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-recovered_from) 属性を確認します。この属性は、期限が切れた元のセッションを参照します。 #### Node.js ```javascript // Find your endpoint's secret in your Dashboard's webhook settings const endpointSecret = 'whsec_...'; // Using Express const app = require('express')(); // Use body-parser to retrieve the raw body as a buffer const bodyParser = require('body-parser');const logRecoveredCart = (sessionId, recoveredFromSessionId) => { // TODO: fill me in console.log("Recording recovered session", sessionId, recoveredFromSessionId); } app.post('/webhook', bodyParser.raw({type: 'application/json'}), (request, response) => { const payload = request.body; const sig = request.headers['stripe-signature']; let event; try { event = stripe.webhooks.constructEvent(payload, sig, endpointSecret); } catch (err) { return response.status(400).send(`Webhook Error: ${err.message}`); }// Handle the checkout.session.completed event if (event.type === 'checkout.session.completed') { const session = event.data.object; const recoveryFromSessionId = session.recovered_from if (recoveryFromSessionId) { // Log relationship between successfully completed session and abandoned session logRecoveredCart(session.id, recoveryFromSessionId) } // Handle order fulfillment } response.status(200).end(); }); ``` ## Optional: リカバリーメールでプロモーションコードを提供する カートを破棄した顧客向けに[割引](https://docs.stripe.com/payments/checkout/discounts.md)を提供すると、購入を完了する動機付けになります。`after_expiration.recovery.allow_promotion_code` を設定することで、リカバリー URL を指定して作成された Checkout セッションに、プロモーションコードのオプションを含めるかどうかを設定できます。 #### Accounts v2 ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ -d mode=payment \ --data-urlencode "success_url=https://example.com/success" \ -d "customer_account={{CUSTOMERACCOUNT_ID}}" \ -d "consent_collection[promotions]=auto" \ -d "after_expiration[recovery][enabled]=true" \ -d "after_expiration[recovery][allow_promotion_codes]=true" ``` #### Customers v1 ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ -d mode=payment \ --data-urlencode "success_url=https://example.com/success" \ -d "customer={{CUSTOMER_ID}}" \ -d "consent_collection[promotions]=auto" \ -d "after_expiration[recovery][enabled]=true" \ -d "after_expiration[recovery][allow_promotion_codes]=true" ``` # 埋め込みページ > This is a 埋め込みページ for when payment-ui is embedded-form. View the full page at https://docs.stripe.com/payments/checkout/abandoned-carts?payment-ui=embedded-form. E コマースでは、[カゴ落ち](https://docs.stripe.com/payments/checkout/compliant-promotional-emails.md)とは、顧客が購入の完了前に決済フローを離れる場合のことです。顧客を Checkout に戻すには、リカバリーフローを作成して、購入を完了するようメールで顧客に連絡をします。 カゴ落ちのメールは、広義では顧客に新製品について知らせたり、クーポンや割引を提供したりするための「プロモーションメール」カテゴリーに分類されます。顧客にメールを送信するには、顧客がプロモーションメールの受信に同意している必要があります。Checkout は以下に役立ちます。 1. プロモーションメールを送信できるように顧客からの同意を収集します。 1. 顧客が Checkout を破棄したときに通知を受け取り、カートの破棄に関するメールを送信できるようにします。 ## プロモーションへの同意を収集する [プロモーション用コンテンツへの同意を収集](https://docs.stripe.com/payments/checkout/promotional-emails-consent.md)するように Checkout を設定します。顧客のメールアドレスを収集して、オンラインフォームが表示される前にプロモーション用コンテンツへの同意をリクエストする場合、`consent_collection[promotions]` をスキップできます。 > #### Accounts v2 API を使用した顧客の表現 > > Accounts v2 API は、Connect ユーザー向けには GA、その他の Stripe ユーザー向けには公開プレビューとして提供されています。すべての Stripe ユーザーは [Dashboard](https://dashboard.stripe.com/settings/connect/platform-setup) で Accounts v2 を有効にできます。ただし、Accounts v2 API の呼び出し時には、プレビューユーザーは[プレビューバージョンを指定](https://docs.stripe.com/api-v2-overview.md#sdk-and-api-versioning)する必要があります。 > > ほとんどのユースケースでは、[Customer](https://docs.stripe.com/api/customers.md) オブジェクトを使用するのではなく、[顧客を顧客設定の Account オブジェクトとしてモデル化する](https://docs.stripe.com/connect/use-accounts-as-customers.md)ことをお勧めします。 #### Accounts v2 ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ -d "customer_account={{CUSTOMERACCOUNT_ID}}" \ -d mode=payment \ -d ui_mode=embedded_page \ --data-urlencode "return_url=https://example.com/return" \ -d "consent_collection[promotions]=auto" ``` #### Customers v1 ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ -d "customer={{CUSTOMER_ID}}" \ -d mode=payment \ -d ui_mode=embedded_page \ --data-urlencode "return_url=https://example.com/return" \ -d "consent_collection[promotions]=auto" ``` ## リカバリーを設定する Checkout セッションは、その [expires_at](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-expires_at) タイムスタンプに達すると、買い手が購入していなくても破棄されます。この場合、セッションにアクセスできなくなり、Stripe が `checkout.session.expired` *Webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) を起動します。この Webhook をリッスンすることで、顧客を新しい Checkout セッションに戻して購入を完了してもらう機会を作ることができます。この機能を使用するには、セッションの作成時に `after_expiration.recovery` を有効にします。 #### Accounts v2 ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ -d mode=payment \ -d ui_mode=embedded_page \ --data-urlencode "return_url=https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}" \ -d "customer_account={{CUSTOMERACCOUNT_ID}}" \ -d "consent_collection[promotions]=auto" \ -d "after_expiration[recovery][enabled]=true" \ -d "after_expiration[recovery][allow_promotion_codes]=true" ``` #### Customers v1 ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ -d mode=payment \ -d ui_mode=embedded_page \ --data-urlencode "return_url=https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}" \ -d "customer={{CUSTOMER_ID}}" \ -d "consent_collection[promotions]=auto" \ -d "after_expiration[recovery][enabled]=true" \ -d "after_expiration[recovery][allow_promotion_codes]=true" ``` ## カート放棄についての通知を受ける `checkout.session.expired` Webhook をリッスンすると、顧客が Checkout を破棄してセッションの有効期限が切れたときに通知が届きます。リカバリーが有効な状態でセッションの有効期限が切れた場合、Webhook ペイロードに [after_expiration](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-after_expiration-recovery) が含まれます。これには、カゴ落ち通知メールに埋め込み可能な URL (`after_expiration.recovery.url`) が記載されます。顧客がこの URL を開くと、**期限切れの元のセッションをコピーした新しい Checkout セッションが作成されます**。顧客は、このコピーセッションで購入を完了します。 > セキュリティ上の理由により、セッションのリカバリー URL の有効期間は 30 日に設定され、`after_expiration.recovery.expires_at` の日付をもって期限切れになります。 ```json { "id": "evt_123456789", "object": "event", "type": "checkout.session.expired", // ...other webhook attributes "data": { "object": { "id": "cs_12356789", "object": "checkout.session", // ...other Checkout Session attributes"consent_collection": { "promotions": "auto", }, "consent": { "promotions": "opt_in" }, "after_expiration": { "recovery": { "enabled": true, "url": "https://buy.stripe.com/r/live_asAb1724", "allow_promotion_code": true, "expires_at": 1622908282, } } } } } ``` ## リカバリーメールを送信する リカバリーメールを送信する場合、期限切れセッション用の Webhook ハンドラを作成して、セッションのリカバリー URL を記載したメールを送信します。顧客が複数の Checkout セッションを破棄し、それぞれの `checkout.session.expired` イベントが一斉にトリガーされることがあります。顧客にリカバリーメールを送信する際はその記録を残し、スパムメールと誤解されないよう配慮してください。 #### Node.js ```javascript // Find your endpoint's secret in your Dashboard's webhook settings const endpointSecret = 'whsec_...'; // Using Express const app = require('express')(); // Use body-parser to retrieve the raw body as a buffer const bodyParser = require('body-parser');const sendRecoveryEmail = (email, recoveryUrl) => { // TODO: fill me in console.log("Sending recovery email", email, recoveryUrl); } app.post('/webhook', bodyParser.raw({type: 'application/json'}), (request, response) => { const payload = request.body; const sig = request.headers['stripe-signature']; let event; try { event = stripe.webhooks.constructEvent(payload, sig, endpointSecret); } catch (err) { return response.status(400).send(`Webhook Error: ${err.message}`); }// Handle the checkout.session.expired event if (event.type === 'checkout.session.expired') { const session = event.data.object; // When a Checkout Session expires, the customer's email isn't returned in // the webhook payload unless they give consent for promotional content const email = session.customer_details?.email const recoveryUrl = session.after_expiration?.recovery?.url // Do nothing if the Checkout Session has no email or recovery URL if (!email || !recoveryUrl) { return response.status(200).end(); } // Check if the customer has consented to promotional emails and // avoid spamming people who abandon Checkout multiple times if ( session.consent?.promotions === 'opt_in' && !hasSentRecoveryEmailToCustomer(email) ) { sendRecoveryEmail(email, recoveryUrl) } } response.status(200).end(); }); ``` ## Optional: セッションの有効期限を調整する デフォルトでは、Checkout セッションは作成後 24 時間で期限が切れますが、`expires_at` を設定して有効期限を短縮し、より早いタイミングでカート放棄について通知を受けることができます。`expires_at` には、セッション作成の 30 分後以降を設定できます。 #### cURL ```bash curl https://api.stripe.com/v1/checkout/sessions \ -u <>: \ -d customer='{{CUSTOMER_ID}}' \ -d "line_items[0][price]"='{{PRICE_ID}}' \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ -d ui_mode=embedded_page \ -d return_url="https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}" \-d expires_at="{{NOW_PLUS_TWO_HOURS}}" ``` ## Optional: コンバージョン率を追跡する 顧客が期限が切れた Checkout セッションのリカバリー URL を開くと、破棄されたセッションのコピーである新しい Checkout セッションが作成されます。 リカバリーメールがコンバージョンの成功に寄与したかどうかを確認するには、新しい Checkout セッションの `checkout.session.completed` Webhook で [recovered_from](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-recovered_from) 属性を確認します。この属性は、期限が切れた元のセッションを参照します。 #### Node.js ```javascript // Find your endpoint's secret in your Dashboard's webhook settings const endpointSecret = 'whsec_...'; // Using Express const app = require('express')(); // Use body-parser to retrieve the raw body as a buffer const bodyParser = require('body-parser');const logRecoveredCart = (sessionId, recoveredFromSessionId) => { // TODO: fill me in console.log("Recording recovered session", sessionId, recoveredFromSessionId); } app.post('/webhook', bodyParser.raw({type: 'application/json'}), (request, response) => { const payload = request.body; const sig = request.headers['stripe-signature']; let event; try { event = stripe.webhooks.constructEvent(payload, sig, endpointSecret); } catch (err) { return response.status(400).send(`Webhook Error: ${err.message}`); }// Handle the checkout.session.completed event if (event.type === 'checkout.session.completed') { const session = event.data.object; const recoveryFromSessionId = session.recovered_from if (recoveryFromSessionId) { // Log relationship between successfully completed session and abandoned session logRecoveredCart(session.id, recoveryFromSessionId) } // Handle order fulfillment } response.status(200).end(); }); ``` ## Optional: リカバリーメールでプロモーションコードを提供する カートを破棄した顧客向けに[割引](https://docs.stripe.com/payments/checkout/discounts.md)を提供すると、購入を完了する動機付けになります。`after_expiration.recovery.allow_promotion_code` を設定することで、リカバリー URL を指定して作成された Checkout セッションに、プロモーションコードのオプションを含めるかどうかを設定できます。 #### Accounts v2 ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ -d mode=payment \ -d ui_mode=embedded_page \ --data-urlencode "return_url=https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}" \ -d "customer_account={{CUSTOMERACCOUNT_ID}}" \ -d "consent_collection[promotions]=auto" \ -d "after_expiration[recovery][enabled]=true" \ -d "after_expiration[recovery][allow_promotion_codes]=true" ``` #### Customers v1 ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ -d mode=payment \ -d ui_mode=embedded_page \ --data-urlencode "return_url=https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}" \ -d "customer={{CUSTOMER_ID}}" \ -d "consent_collection[promotions]=auto" \ -d "after_expiration[recovery][enabled]=true" \ -d "after_expiration[recovery][allow_promotion_codes]=true" ```