1. 概要
Actions on Google は、Google アシスタントのバーチャル パーソナル アシスタント機能を拡張してソフトウェアを作成できるデベロッパー プラットフォームです。スマート スピーカー、スマートフォン、自動車、テレビ、ヘッドフォンなど 10 億以上のデバイスに対応しています。ユーザーは、Google アシスタントとの会話を通じて、食料品の購入から乗車の予約までさまざまなタスクを実行できます。(可能なことの完全なリストについては、アクション ディレクトリをご覧ください)。Actions on Google を使用することで、サードパーティ サービスを開発し、ユーザーとの快適かつ効果的な会話型エクスペリエンスを簡単に作成、管理できます。
この Codelab は、Google アシスタントのアクションを構築した経験がある方を対象とする上級者向けのモジュールです。Actions on Google での開発経験がない場合は、入門編の Codelab(レベル 1、レベル 2、レベル 3)で、プラットフォームの使い方を習得することを強くおすすめします。これらの高度なモジュールでは、アクションの機能を拡張するためのさまざまな機能について説明しています。魅力的なアクションを構築し、新たなユーザーの獲得に役立ててください。
アクションの成功を測定する重要な方法の 1 つは、ユーザー エンゲージメント、つまり初回操作後にユーザーを呼び戻すアクションの有効性です。ユーザーが会話に戻りやすくするために、アクションにいくつかの機能を実装して、会話に戻るパスを提供できます。
この Codelab では、Actions on Google のユーザー エンゲージメント機能とベスト プラクティスについて説明します。

作成するアプリの概要
すでに構築されている機能を強化し、次のことを可能にします。
- ユーザーがタップしてアクションと会話できる毎日の通知を送信する
- アクションにリンクするプッシュ通知をユーザーに送信する
- モバイルウェブ ブラウザからアクションにユーザーを誘導するリンクを作成する
学習内容
- ユーザー エンゲージメントとは何か、アクションの成功にユーザー エンゲージメントが重要な理由
- アクションを変更してユーザー エンゲージメントを改善する方法
- さまざまな種類のアクションでどのユーザー エンゲージメント機能を使用するか
- Actions API を使用してアシスタント経由で通知を送信する方法
必要なもの
次のツールが必要です。
- 任意の IDE またはテキスト エディタ(WebStorm、Atom、Sublime など)
- シェルコマンドを実行するためのターミナル(Node.js、npm、git がインストールされていること)
- ウェブブラウザ(Google Chrome など)
- Firebase コマンドライン インターフェースを備えたローカル開発環境
- アシスタントが搭載されたモバイル デバイス(Android または iOS)(このプロジェクトの作成に使用する Google アカウントと同じアカウントでアシスタントにログインする必要があります)。
Webhook コードを理解するうえで、JavaScript(ES6)に精通していることを強く推奨しますが、必須ではありません。
2. プロジェクトをセットアップする
このセクションでは、以前に作成した完成済みのアクションにユーザー エンゲージメント機能を追加する方法について説明します。
サンプルについて
この Codelab のサンプルは、「Action Gym」という架空のジムのシンプルな Action です。このアクションは、毎日変わるクラスのリストなど、ジムに関する情報を提供します。このような情報提供型のアクションは、ローテーションするクラスリストによって毎日異なる有用な情報が提供されるため、すべてのユーザー エンゲージメント機能の候補として適しています。
次の図は、Action Gym サンプルの会話フローを示しています。

追加するエンゲージメント機能に合わせて、ダイアログを少し変更します。ただし、会話の全体的な設計はあまり変わりません。
ベースファイルをダウンロードする
次のコマンドを実行して、Codelab の GitHub リポジトリのクローンを作成します。
git clone https://github.com/actions-on-google/user-engagement-codelab-nodejs
プロジェクトとエージェントを設定する
Actions プロジェクトと Dialogflow エージェントを設定する手順は次のとおりです。
- Actions Console を開きます。
- [New project](新しいプロジェクト)をクリックします。
- [Project Name](プロジェクト名)に名前を入力します(例:
engagement-codelab)。 - [プロジェクトの作成] をクリックします。
- カテゴリを選択するのではなく、[その他のオプション] セクションまで下にスクロールして、[会話] カードをクリックします。
- [Build your Action](アクションのビルド)をクリックしてオプションを展開し、[Add Action(s)](アクションを追加)を選択します。
- [Add Your First Action](最初のアクションを追加)をクリックします。
- [アクションを作成] ダイアログで [カスタム インテント] を選択し、[ビルド] をクリックして Dialogflow コンソールを起動します。
- Dialogflow コンソールのエージェント作成ページで、[作成] をクリックします。
- 左側のナビゲーションにある
(歯車アイコン)をクリックします。 - [Export and Import](エクスポートとインポート)、[Restore From Zip](Zip から復元)の順にクリックします。
- 先ほどダウンロードした
/user-engagement-codelab-nodejs/start/ディレクトリからagent.zipファイルをアップロードします。 - 「
RESTORE」と入力して [復元] をクリックします。 - [完了] をクリックします。
フルフィルメントをデプロイする
Actions プロジェクトと Dialogflow エージェントの準備が整ったら、Firebase Functions CLI を使用してローカルの index.js ファイルをデプロイします。
ベースファイルのクローンの /user-engagement-codelab-nodejs/start/functions/ ディレクトリから、次のコマンドを実行します。
firebase use <PROJECT_ID>
npm install
firebase deploy
数分後、「Deploy complete!」(デプロイが完了しました)と表示されます。これは Webhook が Firebase に正常にデプロイされたことを示します。
デプロイ URL を取得する
Dialogflow にクラウド関数の URL を指定する必要があります。この URL を取得する手順は次のとおりです。
- Firebase コンソールを開きます。
- 該当する Actions プロジェクトを一覧から選択します。
- 左側のナビゲーション バーで [Develop] > [Functions] に移動します。[データ共有設定を選択] というメッセージが表示された場合は、[後で行う] をクリックしてこのオプションを無視できます。
- [ダッシュボード] タブに、[トリガー] の下に URL が表示された「fulfillment」というエントリが表示されます。この URL を保存します。次のセクションで Dialogflow にコピーする必要があります。

Dialogflow で Webhook URL を設定する
次に、フルフィルメントに Webhook を使用するように Dialogflow エージェントを更新する必要があります。そのための手順は以下のとおりです。
- Dialogflow コンソールを開きます(必要に応じて Firebase コンソールを閉じることができます)。
- 左側のナビゲーションで [フルフィルメント] をクリックします。
- [Webhook] を有効にします。
- Firebase ダッシュボードからコピーした URL を貼り付けます(まだ表示されていない場合)。
- [保存] をクリックします。
プロジェクトが正しく設定されていることを確認する
ユーザーは、Action Gym に関する情報を取得するためにアクションを呼び出すことができる必要があります。これには、営業時間を含むハードコードされたテキスト レスポンスと、曜日ごとのクラス スケジュールを一覧表示するテキスト レスポンスが含まれます。
Actions シミュレータでアクションをテストするには:
- Dialogflow コンソールの左側のナビゲーションで、[統合] > [Google アシスタント] をクリックします。
- [変更の自動プレビュー] が有効になっていることを確認し、[テスト] をクリックしてアクション プロジェクトを更新します。
- Actions シミュレータが Actions プロジェクトを読み込みます。アクションをテストするには、入力欄に「
Talk to my test app」と入力して Enter キーを押します。 - Action Gym へようこそというレスポンスが表示されます。プロンプトに沿って会話を続け、フルフィルメントが各入力に対して応答していることを確認してください。

3. 毎日の更新情報の定期購入を追加する
ユーザーのエンゲージメントを高める一般的な方法として、ユーザーにとって最も有用なタイミングで情報を提供することが挙げられます。これは、インテントの毎日の通知を登録するオプションをユーザーに提供することで実現されます。これにより、そのインテントのフルフィルメントに直接リンクするアシスタント通知がユーザーに送信されます。
このステップでは、毎日の通知の登録について学習し、アクションの Class List インテントに追加します。これらの手順に沿って操作すると、アクションの会話は次の図のようになります。

ユーザーのエンゲージメントをどのように高めますか?
スマートフォン ユーザーは、アプリ固有の情報や更新情報を提供するプッシュ通知に慣れているでしょう。毎日の通知の登録は、アシスタント以外のモバイル デバイスでユーザーにアクセスするための簡単な方法です。ただし、更新を送信するインテントが毎日ユーザーに価値を提供し続けることが前提となります。
毎日の通知はエンゲージメント ツールとして役立ちますが、すべてのアクションに組み込むべきではありません。毎日の通知の登録機能をアクションに追加するかどうかは、次のヒントを参考にして判断してください。
- 毎日の通知を受け取ることで、ユーザーが毎日異なる有益な情報を得られるかどうかを確認します。毎日の通知をタップしたときに毎回同じ情報しか得られないのでは、おそらく数日で登録は解除されます。
- 毎日の通知のインテントに直接ジャンプする場合は、ユーザーに対話の意味が通じることを確認します。必ずしも会話を最初から始める必要はなく、それほど多くのコンテキストは期待されていません。
- 毎日の通知を登録するよう促す前に、そのアクションのメリットをユーザーに示します。ユーザーは登録オプションを提示されたときに、「このコンテンツは毎日必要だろうか?」と考えます。
- ユーザーに何度も繰り返し購読をすすめないでください。毎日の通知の登録をすすめるタイミングはユーザーにそのコンテンツを示した直後とし、その他のコンテキストで提案を繰り返さないようにします。
- 更新インテントがトリガーされた後の会話は短くします。通常はユーザーに入力を求めず、1 回のレスポンスのみで終了させます。
毎日の通知をオンにする
毎日の更新の定期購入は、ユーザーを会話の開始地点に置くウェルカム インテントに追加することも、会話内の特定の場所にディープリンクするためのより具体的なインテントに追加することもできます。この Codelab では、ダイアログが毎日変更され、利用可能なクラスをリマインドする機能がユーザーにとって有用である可能性があるため、クラスリスト インテントが最も適しています。
クラスリスト インテントの毎日の更新を有効にする手順は次のとおりです。
- Actions Console で、[Develop](開発)タブをクリックし、左側のナビゲーション バーで [Actions](アクション)を選択します。
- [操作] リストの [クラスリスト] をクリックします。
- [User engagement](ユーザー エンゲージメント)セクションで、[Would you like to offer daily updates to users](ユーザーに毎日の通知を提供する)オプションを切り替えます。
- 毎日配信される更新情報を説明するわかりやすいコンテンツのタイトルを設定します。コンテキストは「毎日何時に送りますか?」になるため、タイトルは説明的で、声に出して読んだときに正しく聞こえるようにしてください。この例では、[Content title](コンテンツのタイトル)を
list of upcoming Action Gym classesに設定します。 - ページの上部にある [保存] をクリックします。

Dialogflow を設定する
Dialogflow コンソールで次の手順に沿って、毎日の更新の定期購入フローのインテントを作成します。
ユーザーに登録を促す
- ユーザーが毎日の通知の登録をリクエストしたときに処理する新しいインテントを設定します。Dialogflow コンソールで、左側のナビゲーションにある [Intents] の横にある + ボタンをクリックして、新しいインテントを作成します。
- この新しいインテントに
Setup Updatesという名前を付けます。 - [Training phrases] セクションに、次のユーザー表現を追加します。
Send daily remindersReminderRemind meUpdatesUpcoming classes
- [Fulfillment] セクションで、[Enable webhook call for this intent] オプションを切り替えます。
- ページの上部にある [保存] をクリックします。

ユーザーの決定を処理する
- 毎日の通知の登録プロンプトに対するユーザーの応答を処理する新しいインテントを設定します。左側のナビゲーションで [Intents] の横にある [+] ボタンをクリックして、新しいインテントを作成します。
- この新しいインテントに
Confirm Updatesという名前を付けます。 - [Events] セクションに
actions_intent_REGISTER_UPDATEを追加します。この Dialogflow イベントは、ユーザーが毎日の通知の登録フローを完了したときにトリガーされます。登録したかどうかは関係ありません。 - [Fulfillment] セクションで、[Enable webhook call for this intent] オプションを切り替えます。
- ページの上部にある [保存] をクリックします。

フルフィルメントを実装する
Webhook でフルフィルメントを実装する手順は次のとおりです。
依存関係を読み込む
index.js ファイルで、require() 関数を更新して actions-on-google パッケージから RegisterUpdate パッケージを追加します。インポートは次のようになります。
index.js
const {
dialogflow,
Suggestions,
RegisterUpdate,
} = require('actions-on-google');
候補ワードを更新する
index.js ファイルで、候補チップのタイトルのリストに DAILY エントリを追加します。Suggestion 定義は次のようになります。
index.js
// Suggestion chip titles
const Suggestion = {
HOURS: 'Ask about hours',
CLASSES: 'Learn about classes',
DAILY: 'Send daily reminders',
};
新しいインテントのフルフィルメントを追加する
ユーザーが定期購入を希望した場合は、更新のターゲット インテント(クラスリスト)とタイプ(DAILY)を指定して RegisterUpdate ヘルパーを呼び出し、毎日の更新の定期購入フローを開始します。定期購入フローが完了すると、アシスタントは status 引数(定期購入が成功したかどうかを示す)を指定して actions_intent_REGISTER_UPDATE イベントをトリガーします。定期購入のステータスに応じて変化するフォローアップ プロンプトをユーザーに提供します。
index.js ファイルに、次のコードを追加します。
index.js
// Start opt-in flow for daily updates
app.intent('Setup Updates', (conv) => {
conv.ask(new RegisterUpdate({
intent: 'Class List',
frequency: 'DAILY',
}));
});
// Confirm outcome of opt-in for daily updates
app.intent('Confirm Updates', (conv, params, registered) => {
if (registered && registered.status === 'OK') {
conv.ask(`Gotcha, I'll send you an update everyday with the ` +
'list of classes. Can I help you with anything else?');
} else {
conv.ask(` I won't send you daily reminders. Can I help you with anything else?`);
}
if (conv.screen) {
conv.ask(new Suggestions([Suggestion.HOURS, Suggestion.CLASSES]));
}
});
ユーザーに代替プロンプトを提案する
クラスリストのレスポンスの最後に、毎日の更新の定期購入が提示されますが、これには問題があります。ユーザーが毎日の通知をタップしたときにも同じレスポンスがトリガーされるため、ユーザーは毎日の通知から来たばかりであるにもかかわらず、毎日の通知の登録を求められることになります。ユーザーが再登録する必要があると思わないようにするにはどうすればよいですか?
幸いなことに、conv オブジェクトの引数には、ユーザーが会話を開始した場所に関する情報が含まれています。conv 引数を確認して UPDATES セクションが含まれているかどうかを調べ、ユーザーが毎日の通知から会話を開始したかどうかを判断し、それに応じてレスポンスを変更できます。この会話ブランチを使用して、クラスのリストを提供した直後にダイアログを閉じることもできます。これは、毎日の更新を短くするというベスト プラクティスに沿ったものです。
index.js ファイルで、次のコードを置き換えます。
index.js
// Class list intent handler
app.intent('Class List', (conv, {day}) => {
if (!day) {
day = DAYS[new Date().getDay()];
}
const classes =
[...new Set(schedule.days[day].map((d) => `${d.name} at ${d.startTime}`))]
.join(', ');
const classesMessage =
`On ${day} we offer the following classes: ${classes}. ` +
`Can I help you with anything else?`;
conv.ask(classesMessage);
if (conv.screen) {
conv.ask(new Suggestions([Suggestion.HOURS]));
}
});
次のように変更します。
index.js
// Class list intent handler
app.intent('Class List', (conv, {day}) => {
if (!day) {
day = DAYS[new Date().getDay()];
}
const classes =
[...new Set(schedule.days[day].map((d) => `${d.name} at ${d.startTime}`))]
.join(', ');
let classesMessage = `On ${day} we offer the following classes: ${classes}. `;
// If the user started the conversation from the context of a daily update,
// the conv's arguments will contain an 'UPDATES' section.
let engagement = conv.arguments.get('UPDATES');
// Check the conv arguments to tailor the conversation based on the context.
if (engagement) {
classesMessage += `Hope to see you soon at Action Gym!`;
conv.close(classesMessage);
} else {
classesMessage += `Would you like me to send you daily reminders of upcoming classes, or can I help you with anything else?`;
conv.ask(classesMessage);
if (conv.screen) {
conv.ask(new Suggestions([Suggestion.DAILY, Suggestion.HOURS]));
};
};
});
毎日の通知をテストする
ターミナルで次のコマンドを実行して、更新した Webhook コードを Firebase にデプロイします。
firebase deploy
Actions シミュレータでカスタム再プロンプトをテストする手順は次のとおりです。
- Actions Console で、[Test] に移動します。
- 入力欄に「
Talk to my test app」と入力し、Enter キーを押します。 - 「
Learn about classes」と入力して Enter キーを押します。アクションのレスポンスで、毎日のリマインダーを送信する提案が表示されるようになります。 - 「
Send daily reminders」と入力して Enter キーを押します。 - 更新を確認する時刻を入力して、Enter キーを押します。テストでは、現在時刻より 3 ~ 5 分遅れて応答してみてください。

モバイル デバイスに、更新の指定時刻にアシスタントから通知が届きます。この通知が表示されるまでに数分かかることがあります。通知をタップすると、アシスタントの Class List インテントに直接ディープリンクされ、今後のクラスの一覧が表示されます。

4. プッシュ通知を追加する
アクション外でユーザーにアプローチする別の方法として、Actions API を呼び出してユーザーにプッシュ通知を送信できます。毎日の更新とは異なり、これらの通知はアシスタントによって自動的にスケジュール設定されないため、いつでも送信できます。
このステップでは、新しい Class Canceled インテントを追加し、クラスのキャンセルをユーザーに通知する通知を送信して、アクションにプッシュ通知を実装する方法を学びます。また、通知の送信に必要な次の 3 つのコンポーネントも設定します。
- Actions API アカウント - API に
POSTリクエストを送信してユーザーに通知を送信するため、この API とのインターフェースとなるサービス アカウントと認証情報を設定する必要があります。 - 権限ヘルパー - プッシュ通知を送信するために必要なユーザー ID にアクセスするには、ユーザーの権限が必要です。この例では、クライアント ライブラリ関数を使用して権限ヘルパーを呼び出し、この ID をリクエストします。
- ストレージ - 会話外のユーザーにプッシュ通知を送信するには、ユーザー ID をいつでも呼び出せる場所に保存する必要があります。この例では、各ユーザーの情報を保存する Firestore データベースを設定します。
この手順に沿って設定すると、アクションの会話に次のダイアログが追加されます。

ユーザーのエンゲージメントをどのように高めますか?
スマートフォン ユーザーは、アプリ固有の情報や更新情報を提供するプッシュ通知に慣れているでしょう。プッシュ通知は、ユーザーが有効にする理由を十分に理解していれば、アシスタント以外でモバイル デバイスのユーザーにアクセスできる柔軟な方法です。毎日の通知の場合、ユーザーは毎日通知が届くことをすでに認識しています。しかし、プッシュ通知の場合、ユーザーは通知を頻繁に受け取るのか、1 日に何度も通知が届くのかを把握できません。
プッシュ通知はエンゲージメント ツールとして役立ちますが、すべてのアクションに組み込む必要はありません。アクションにプッシュ通知を追加するかどうかは、次のヒントを参考にして判断してください。
- プッシュ通知のスケジュール例をいくつか計画します。1 日に 1 回だけプッシュ通知を送信する予定の場合は、代わりに毎日の更新を使用することを検討してください。
- プッシュ通知を受け取るたびに、有益な情報が提供されるようにします。通知はアクションのインテントの 1 つにディープリンクすることもできるため、インテントが有用で関連性の高いものになるようにしてください。
- プッシュ通知の登録をユーザーに求める場合は、明確に伝えます。ユーザーは、各プッシュ通知で何が起こるのかを理解し、通知がどのくらいの頻度で送信されるのかを把握している必要があります。
Actions API を有効にする
- Google Cloud コンソールを開き、プルダウンで Actions プロジェクト名を選択します。

- ナビゲーション メニュー(☰)で、[API とサービス] > [ライブラリ] に移動します。
- Actions API を検索し、[有効にする] をクリックします。

サービス アカウントを作成する
Actions API では認証が必要なため、リクエストを送信するにはサービス アカウントを作成する必要があります。Actions API のサービス アカウント キーを作成してインストールする手順は次のとおりです。
- Google Cloud コンソールのナビゲーション メニュー (☰)で、[API とサービス] > [認証情報] に移動します。
- [認証情報を作成] > [サービス アカウント キー] をクリックします。
- [サービス アカウント] プルダウン メニューで、[新しいサービス アカウント] を選択します。
- 次の情報を入力します。
- サービス アカウント名:
service-account - ロール: プロジェクト > オーナー
- サービス アカウント ID:
service-account(常に @<project_id>.iam.gserviceaccount.com が続きます) - キータイプ: JSON
- [作成] をクリックします。
- ダウンロードした JSON ファイルをプロジェクトの /user-engagement-codelab/start/functions/ ディレクトリに移動します。
- JSON ファイルの名前を
service-account.jsonに変更します。

Firestore を有効にする
会話外で通知を送信するには、通知コードから参照できるユーザー ID を保存する方法が必要です。この例では、Firestore データベースを使用して、定期購入しているユーザーのユーザー ID を保存します。
次の手順に沿って、アクション用の Firestore データベースを作成します。
- Firebase コンソールで、Actions プロジェクト名を選択します。
- 左側のナビゲーションで、[Develop](開発)> [Database](データベース)に移動し、[データベースを作成] をクリックします。
- [テストモードで開始] を選択します。
- [有効にする] をクリックします。

Dialogflow を設定する
Dialogflow コンソールでプッシュ通知のオプトイン フローを作成する手順は次のとおりです。
ユーザーに登録を促す
- キャンセルされたクラスのプッシュ通知の登録をユーザーがリクエストしたときに処理する新しいインテントを設定します。Dialogflow コンソールで、左側のナビゲーションにある [Intents] の横にある + ボタンをクリックして、新しいインテントを作成します。
- この新しいインテントに
Setup Push Notificationsという名前を付けます。 - [Training phrases] セクションに、次のユーザー表現を追加します。
Subscribe to notificationsSend notificationNotify meSend class notificationsCancelled notifications
- [Fulfillment] セクションで、[Enable webhook call for this intent] オプションを切り替えます。
- ページの上部にある [保存] をクリックします。

ユーザーの決定を処理する
- プッシュ通知の登録プロンプトに対するユーザーの応答を処理する新しいインテントを設定します。左側のナビゲーションで [Intents] の横にある [+] ボタンをクリックして、新しいインテントを作成します。
- この新しいインテントに
Confirm Push Notificationsという名前を付けます。 - [Events] セクションに
actions_intent_PERMISSIONを追加します。この Dialogflow イベントは、プッシュ通知の登録フローをユーザーが完了したときにトリガーされます。登録したかどうかにかかわらずトリガーされます。 - [Fulfillment] セクションで、[Enable webhook call for this intent] オプションを切り替えます。
- ページの上部にある [保存] をクリックします。

プッシュ通知を処理する
プッシュ通知を特定のインテントにリンクできます。これにより、プッシュ通知をタップしたユーザーは、アクション内のそのインテントに直接ディープリンクされます。この例では、クラスのキャンセルに関する詳細を提供するプッシュ通知用の新しいインテントを追加します。
ユーザーがプッシュ通知をタップしたときにトリガーされるインテントを追加する手順は次のとおりです。
- Dialogflow コンソールで、左側のナビゲーションにある [Intents] の横にある + ボタンをクリックして、新しいインテントを作成します。
- この新しいインテントに
Class Canceledという名前を付けます。 - [Training phrases] セクションで、
Cancelationsをユーザー表現として追加します。 - [Fulfillment] セクションで、[Enable webhook call for this intent] オプションを切り替えます。
- ページの上部にある [保存] をクリックします。

会話中にテスト通知を送信する
本番環境では、プッシュ通知を送信するスクリプトを、Action のフルフィルメント コードとは別に用意する必要があります。この例では、アクションとの会話中にプッシュ通知を送信するために呼び出すことができるインテントを作成します。このインテントはデバッグ専用です。実際には、プッシュ通知はフルフィルメントで処理したり、アクションの会話の一部としてトリガーしたりしないでください。
プッシュ通知をテストするためのインテントを作成する手順は次のとおりです。
- テストとデバッグの目的で、登録ユーザーにプッシュ通知を送信できる新しいインテントを設定します。Dialogflow コンソールで、左側のナビゲーションにある [Intents] の横にある + ボタンをクリックして、新しいインテントを作成します。
- この新しいインテントに
Test Notificationという名前を付けます。 - [Training phrases] セクションで、
Test notificationをユーザー表現として追加します。 - [Fulfillment] セクションで、[Enable webhook call for this intent] オプションを切り替えます。
- ページの上部にある [保存] をクリックします。

プッシュ通知をオンにする
Class Canceled インテントのプッシュ通知を有効にする手順は次のとおりです。
- Dialogflow コンソールで、ナビゲーション バーの [Integrations] に移動します。
- [Google Assistant](Google アシスタント)カードで、[Integration Settings](統合設定)をクリックします。
- 暗黙的呼び出しインテントとして Class Canceled を追加します。この手順は、ユーザーが Class Canceled インテント(プッシュ通知をタップ)で会話を開始できることを Dialogflow が認識するために必要です。
- [閉じる] をクリックします。

- Actions Console で、[Develop](開発)タブをクリックし、左側のナビゲーション バーで [Actions](アクション)を選択します。
- [アクション] リストの [クラスがキャンセルされました] をクリックします。
- [User engagement](ユーザー エンゲージメント)セクションで、[Would you like to send push notifications?](プッシュ通知を送信する)オプションを切り替えます。
- プッシュ通知の内容を説明するわかりやすいコンテンツ タイトルを設定します。コンテキストは「のプッシュ通知を送ってもよろしいですか?」になります。タイトルは説明的で、声に出して読んだときに正しく聞こえるようにしてください。この例では、[Content title](コンテンツのタイトル)を
class cancelationsに設定します。 - ページの上部にある [保存] をクリックします。

フルフィルメントを実装する
Webhook でフルフィルメントを実装する手順は次のとおりです。
依存関係を読み込む
index.js ファイルで、require() 関数を更新して actions-on-google パッケージから UpdatePermission パッケージを追加します。インポートは次のようになります。
index.js
const {
dialogflow,
Suggestions,
RegisterUpdate,
UpdatePermission,
} = require('actions-on-google');
候補ワードを更新する
index.js ファイルで、候補チップのタイトルのリストに NOTIFICATIONS エントリを追加します。Suggestion 定義は次のようになります。
index.js
// Suggestion chip titles
const Suggestion = {
HOURS: 'Ask about hours',
CLASSES: 'Learn about classes',
DAILY: 'Send daily reminders',
NOTIFICATIONS: 'Get notifications',
};
新しいインポートを設定する
Firestore データベースに接続するには、firebase-admin パッケージを追加し、データベースに保存されているフィールドの定数を追加します。また、Actions API への認証とリクエストを処理するために、google-auth-library パッケージと request パッケージもインポートします。
index.js ファイルで、次のコードをインポートに追加します。
index.js
// Firebase admin import
const admin = require('firebase-admin');
// Initialize Firestore
admin.initializeApp();
const db = admin.firestore();
// Firestore constants
const FirestoreNames = {
INTENT: 'intent',
USER_ID: 'userId',
USERS: 'users',
};
// Actions API authentication imports
const {auth} = require('google-auth-library');
const request = require('request');
クラスのキャンセル通知を設定するよう提案する
index.js ファイルで、次のコードを置き換えます。
index.js
// Class list intent handler
app.intent('Class List', (conv, {day}) => {
if (!day) {
day = DAYS[new Date().getDay()];
}
const classes =
[...new Set(schedule.days[day].map((d) => `${d.name} at ${d.startTime}`))]
.join(', ');
let classesMessage = `On ${day} we offer the following classes: ${classes}. `;
// If the user started the conversation from the context of a daily update,
// the conv's arguments will contain an 'UPDATES' section.
let engagement = conv.arguments.get('UPDATES');
// Check the conv arguments to tailor the conversation based on the context.
if (engagement) {
classesMessage += `Hope to see you soon at Action Gym!`;
conv.close(classesMessage);
} else {
classesMessage += `Would you like me to send you daily reminders of upcoming classes, or can I help you with anything else?`;
conv.ask(classesMessage);
if (conv.screen) {
conv.ask(new Suggestions([Suggestion.DAILY, Suggestion.HOURS]));
};
};
});
次のように変更します。
index.js
// Class list intent handler
app.intent('Class List', (conv, {day}) => {
if (!day) {
day = DAYS[new Date().getDay()];
}
const classes =
[...new Set(schedule.days[day].map((d) => `${d.name} at ${d.startTime}`))]
.join(', ');
let classesMessage = `On ${day} we offer the following classes: ${classes}. `;
// If the user started the conversation from the context of a daily update,
// the conv's arguments will contain an 'UPDATES' section.
let engagement = conv.arguments.get('UPDATES');
// Check the conv arguments to tailor the conversation based on the context.
if (engagement) {
classesMessage += `Hope to see you soon at Action Gym!`;
conv.close(classesMessage);
} else {
classesMessage += `Would you like to receive daily reminders of upcoming classes, subscribe to notifications about cancelations, or can I help you with anything else?`;
conv.ask(classesMessage);
if (conv.screen) {
conv.ask(new Suggestions([Suggestion.DAILY, Suggestion.NOTIFICATIONS,
Suggestion.HOURS]));
};
};
});
新しいインテントのフルフィルメントを追加する
ユーザーがプッシュ通知の登録を希望した場合は、UpdatePermission ヘルパーを呼び出してユーザーに権限をリクエストします。成功すると、PERMISSION 引数が conv オブジェクトの引数に追加されます。この引数を確認して、会話をピボットできます。
ユーザーの許可を取得したら、conv オブジェクトの引数からユーザー ID を取得し、データベースに保存します。このユーザー ID は後で Actions API に送信されます。アシスタントは、この ID を使用して通知の受信者を特定します。
最後に、プッシュ通知をタップしたときにトリガーされる Class Canceled インテントのフルフィルメントを追加します。この例では、レスポンスはプレースホルダ文字列ですが、このアクションのリリース準備完了版では、通知スクリプトによって、どのクラスがキャンセルされたかについてのより動的な情報が提供されます。
index.js ファイルに、次のコードを追加します。
index.js
// Call the User Information helper for permission to send push notifications
app.intent('Setup Push Notifications', (conv) => {
conv.ask('Update permission for setting up push notifications');
conv.ask(new UpdatePermission({intent: 'Class Canceled'}));
});
// Handle opt-in or rejection of push notifications
app.intent('Confirm Push Notifications', (conv) => {
if (conv.arguments.get('PERMISSION')) {
let userId = conv.arguments.get('UPDATES_USER_ID');
if (!userId) {
userId = conv.request.conversation.conversationId;
}
// Add the current conversation ID and the notification's
// target intent to the Firestore database.
return db.collection(FirestoreNames.USERS)
.add({
[FirestoreNames.INTENT]: 'Class Canceled',
[FirestoreNames.USER_ID]: userId,
})
.then(() => {
conv.ask(`Great, I'll notify you whenever there's a class cancelation. ` +
'Can I help you with anything else?');
});
} else {
conv.ask(`Okay, I won't send you notifications about class cancelations. ` +
'Can I help you with anything else?');
}
if (conv.screen) {
conv.ask(new Suggestions([Suggestion.CLASSES, Suggestion.HOURS]));
}
});
// Intent triggered by tapping the push notification
app.intent('Class Canceled', (conv) => {
conv.ask('Classname at classtime has been canceled.');
});
テスト通知を追加する
ユーザーにプッシュ通知を送信するには、ユーザー ID、通知のタイトル、ターゲット インテントを指定して、Actions API に POST リクエストを送信します。この例では、テスト通知インテントをトリガーすると、Firestore データベースが反復処理され、通知を登録しているすべてのユーザーにプッシュ通知が送信されます。
この例では、プッシュ通知を送信するコードを Webhook フルフィルメントに含め、会話でテストインテントを呼び出すことでそのコードをトリガーしています。公開する予定のアクションでは、プッシュ通知コードはフルフィルメントとは別のスクリプトに存在する必要があります。
index.js ファイルに、次のコードを追加します。
index.js
// Debug intent to trigger a test push notification
app.intent('Test Notification', (conv) => {
// Use the Actions API to send a Google Assistant push notification.
let client = auth.fromJSON(require('./service-account.json'));
client.scopes = ['https://www.googleapis.com/auth/actions.fulfillment.conversation'];
let notification = {
userNotification: {
title: 'Test Notification from Action Gym',
},
target: {},
};
client.authorize((err, tokens) => {
if (err) {
throw new Error(`Auth error: ${err}`);
}
// Iterate through Firestore and send push notifications to every user
// who's currently opted in to canceled class notifications.
db.collection(FirestoreNames.USERS)
.where(FirestoreNames.INTENT, '==', 'Class Canceled')
.get()
.then((querySnapshot) => {
querySnapshot.forEach((user) => {
notification.target = {
userId: user.get(FirestoreNames.USER_ID),
intent: user.get(FirestoreNames.INTENT),
};
request.post('https://actions.googleapis.com/v2/conversations:send', {
'auth': {
'bearer': tokens.access_token,
},
'json': true,
'body': {'customPushMessage': notification, 'isInSandbox': true},
}, (err, httpResponse, body) => {
if (err) {
throw new Error(`API request error: ${err}`);
}
console.log(`${httpResponse.statusCode}: ` +
`${httpResponse.statusMessage}`);
console.log(JSON.stringify(body));
});
});
})
.catch((error) => {
throw new Error(`Firestore query error: ${error}`);
});
});
conv.ask('A notification has been sent to all subscribed users.');
});
プッシュ通知をテストする
ターミナルで次のコマンドを実行して、更新した Webhook コードを Firebase にデプロイします。
firebase deploy
アクション シミュレータで通知をテストする手順は次のとおりです。
- Actions Console で、[テスト] タブに移動します。
- 入力欄に「
Talk to my test app」と入力し、Enter キーを押します。 - 「
Learn about classes」と入力して Enter キーを押します。 - 「
Get notifications」と入力して Enter キーを押します。 - アクションにプッシュ通知の送信をまだ許可していない場合は、「
yes」と入力して Enter キーを押します。 - 「
yes」と入力して Enter キーを押します。これで、このアクションのプッシュ通知が Google アカウントに登録されます。

- 「
no」と入力して Enter キーを押して終了します。 Talk to my test appと入力して Enter キーを押すと、新しい会話が開始されます。- 「
Test notification」と入力して Enter キーを押します。

数分以内に、モバイル デバイスに「Test Notification from Action Gym」というアシスタントのプッシュ通知が届きます。この通知をタップすると、Action の Class Canceled インテントにディープリンクされます。

5. アシスタント リンクを作成する
ここまで、ユーザーをアクションに復帰させるために実装できるエンゲージメント機能について説明してきましたが、これらの機能は、ユーザーがアクションを見つけて使用することを前提としています。
モバイル デバイスのユーザーをアシスタントのアクションに直接リンクするアシスタント リンクを作成できます。アシスタント リンクは標準のハイパーリンクであるため、ウェブサイトや、ブログやソーシャル メディアの投稿などのウェブ マーケティング資料に追加できます。
このステップでは、アシスタント リンクとは何か、Action のウェルカム インテントのリンクを作成する方法、テスト用にシンプルなウェブサイトに追加する方法について学習します。
ユーザーのエンゲージメントをどのように高めますか?
ユーザーを初めてアクションに誘導するのは難しい場合があります。特に、ユーザーがアシスタントでアクションを明示的に呼び出す必要がある場合はなおさらです。アシスタント リンクを使用すると、ユーザーがアクションに直接アクセスできるため、この摩擦を軽減できます。アシスタント対応デバイスでユーザーがアシスタントのリンクをたどると、ユーザーはアクションに直接移動します。ユーザーがモバイル以外のデバイスやアシスタントをサポートしていないデバイスでリンクを開いた場合でも、アクション ディレクトリの掲載情報(公開されている場合)にリダイレクトされるため、リンクを使ってアクションを宣伝できます。
アシスタント リンクは便利なエンゲージメント ツールなので、ウェブサイトやソーシャル メディアでアクションを宣伝する予定がある場合は、作成することをおすすめします。アシスタント リンクを作成して配布する前に、次のヒントをご確認ください。
- アシスタント リンクは、アクションが公開された後にのみ機能します。プロジェクトが下書き状態の場合、リンクは自分のデバイスでのみ機能します。それ以外のユーザーは、アクション ディレクトリの 404 ページに移動します。
- アルファ環境またはベータ環境でアクションをリリースすることで、公開前にユーザーがアシスタント リンクをテストできるようにすることができます。アシスタント リンクをテストできるのは、アルファ版またはベータ版に参加しているユーザーのみです。
- アシスタント リンクのデスティネーション インテントが、新規ユーザーに良い第一印象を与えるようにしてください。ウェルカム インテントは、アクションの紹介にすでに適しているため、アシスタント リンクのデフォルトの宛先になります。
アシスタント リンクをオンにする
ウェルカム インテントの Assistant リンクを作成する手順は次のとおりです。
- Actions Console で、[Develop](開発)タブをクリックし、左側のナビゲーション バーで [Actions](アクション)を選択します。
- [アクション] リストの [actions.intent.MAIN] をクリックします。
- [リンク] セクションで、[このアクションの URL を有効にしますか?] オプションを切り替えます。
- アクションを説明するわかりやすいリンクのタイトルを設定します。タイトルは、ユーザーがアクションで何ができるかを説明するシンプルな動詞と名詞のペアにします。この例では、[リンクのタイトル] を
learn about Action Gymに設定します。 - このページの下部にある HTML スニペットをコピーして、後で使用できるように保存します。
- ページの上部にある [保存] をクリックします。

テスト ウェブサイトをデプロイする
アシスタント リンクをテストするには、Firebase ツールを使用して、フルフィルメントとともにテスト ウェブサイトをデプロイします。この例では、シンプルなテスト用ウェブサイトをすでに作成してあります。アシスタント リンクを追加するだけで済みます。
フルフィルメントの /user-engagement-codelab-nodejs/start/public/ ディレクトリに移動し、テキスト エディタで index.html ファイルを開きます。
index.html ファイルで、アシスタント リンクの HTML スニペットを body 要素に貼り付けます。ファイルは次のスニペットのようになります。
index.html
<body>
<p>
<a href="https://assistant.google.com/services/invoke/uid/000000efb5f2fd97">🅖 Ask my test app to learn about Action Gym
</a>
</p>
</body>
アシスタント リンクをテストする
ターミナルで次のコマンドを実行して、テスト ウェブサイトを Firebase にデプロイします。
firebase deploy
deploy コマンドの実行が完了したら、出力のホスティング URL をメモします。

モバイル デバイスのウェブブラウザでこの URL にアクセスすると、テスト ウェブサイトにアシスタントのリンクが表示されます。モバイル デバイスでこのリンクをクリックすると、アシスタントのアクションのウェルカム インテントに移動します。

パソコンのブラウザでホスト URL にアクセスすることもできます。アクションは公開されていないため、アシスタント ディレクトリの 404 ページに移動します。
6. 次のステップ
おめでとうございます!
これで、アクションを開発する際のユーザー エンゲージメントの重要性、プラットフォームで利用可能なユーザー エンゲージメント機能、各機能をアクションに追加する方法について学習しました。
その他の学習リソース
アクションのユーザー エンゲージメントについて詳しくは、以下のリソースをご覧ください。
- ユーザー エンゲージメントと アシスタント リンクのドキュメント: この Codelab で説明する機能と一般的なユーザー エンゲージメントに関する Actions on Google の公式ドキュメントです。
- ユーザー保持率の分析: 公開済みのアクションのユーザー保持率を表示する Actions Console の分析機能に関するドキュメント。
- 会話の設計ガイドライン: ユーザー エンゲージメント機能を設計する方法に関するベスト プラクティスとガイドライン。
- Actions on Google GitHub リポジトリ: サンプルコードとサンプル ライブラリ。
- r/GoogleAssistantDev: アシスタントに取り組むデベロッパーを対象とした Reddit 公式コミュニティ。
Twitter で @ActionsOnGoogle をフォローして最新情報をチェックしてください。また、作成したアクションについて、ハッシュタグ #AoGDevs でツイートしてください。
フィードバック アンケート
最後に、こちらのフォームにご記入いただき、ご意見をお聞かせください。