こんにちは、シンヤです!
本日は「【重要】非同期通信でOptimizeを使いA/Bテストをする方法」というテーマでお話しいたします。
概要
非同期通信の場合Google OptimizeでA/Bテストを行うには、以下のような特殊な設定が必要です。
- 「アクティベーションイベント」を設定する
- テスト有効化のタイミングを「アクティベーションイベント発火後」に設定する
React製のフレームワーク「Next.js」を使ってOptimizeの設定を書き込んでいきます。
Google Optimizeとは
Google Optimizeとは、Googleが提供しているA/Bテストを行えるツールです。
主な特徴として・・・
- 無料
- Google Analyticsとの連携機能
- 過去の測定データの蓄積と分析
- 「多変量テスト」「リダイレクトテスト」も可能
- 簡単にデザインとHTMLを変更できる
があります。
どのテストも行いたいことは、基本的には「仮説検証」です。
考え出した仮説を基にGoogle Optimizeを使い、画面の見た目を変更して、2週間〜1ヶ月程テストします。
やること整理
環境構築〜テスト完了まで、全て解説します。
具体的には以下の順番で解説します。
- 「Node.js」のインストール
- 「Next.js」のプロジェクト作成
- 「_document.js」の設定とテストページの作成
- 「アクティベーションイベント」の書き込み
- 「Google Analytics(GA4)」のアカウント作成
- 「Google Optimize」のアカウント作成
- 「Google Analytics」と「Google Optimize」の連結
- 「Next.js」にGAとOptimizeのIDを書き込む
- 「Netlify」の設定
- 「Google Optimize」でのテスト
1. 「Node.js」のインストール
以下はMacでの環境構築の方法となります。
ご使用中のMacに「Node.js」の環境を構築していきます。
既に環境構築済みの方は、こちらの項目は飛ばして読んでください。
ターミナルを起動する
まずは、ターミナルの起動を行います。
Mac下部の「Launchpad」で、「terminal」と入力して出てきたアイコンを、クリックしてください。
Homebrewのインストール
以下のコマンドを入力して、Homebrewをインストールします。
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
インストール後以下のコマンドを入力して、Homebrewのバージョンが表示されたら、成功しています。
$ brew -v
#> Homebrew 1.2.3
#> Homebrew/homebrew-core (git revision 7212; last commit 2017-07-02)
Nodebrewのインストール
以下のコマンドを入力して、Nodebrewをインストールします。
$ brew install nodebrew
インストール後、以下のコマンドを入力して、Nodebrewのバージョンが表示されたら、成功しています。
$ nodebrew -v
#> nodebrew 1.0.0
Nodebrewを使える様にする
以下のコマンドをターミナル上で入力して、環境変数を追加します。
$ vi ~/.bash_profile
ターミナルの画面が変わったら、
- キーボードの「I」を押す
- 「export PATH=$HOME/.nodebrew/current/bin:$PATH」のコードを追加する。
上記の画像のようになっていれば成功です。 |
コードを追加したら、
- 「esc」キーを押す
- 「:wq」と入力する
- 「Enter」を押す
コードの保存が終わり、エディターが終了します。
Nodebrewのセットアップ
以下のコマンドを入力して、先ほど作ったbash_profile
を反映させます。
$ source ~/.bash_profile
次に以下のコマンドを入力して、Nodebrewをセットアップします。
$ nodebrew setup
Node.jsのインストール
以下のコマンドを入力して「Node.js」をインストールします。
$ nodebrew install-binary v12.13.1
次に以下のコマンドを入力して、インストールした「Node.js」を使える様にします。
$ nodebrew use v12.13.1
インストール後以下のコマンドを入力して、「Node.js」のバージョンが表示されたら、成功しています。
$ node -v
#> v12.13.1
2. 「Next.js」のプロジェクト作成
以下のコマンドを入力して、「Next.js」のプロジェクトを作ります。
$ npx create-next-app
✔ What is your project named? … next-app-optimize
What is your project named?
に好きな名前を入れます。
これがディレクトリ名になります。
上記では仮に「next-app-optimize」を名付けました。
上記の画像のようになっていれば成功です。 |
次に以下のコマンドを入力して、作成した「next-app-optimize」に移動します。
$ cd next-app-optimize
以下のコマンドを入力して、ローカルで「Next.js」を起動させます。
$ yarn dev
実行結果 |
---|
http://localhost:3000 にアクセスして、上記の画面が表示されていれば成功です。 |
「index.js」を書き換える
pages
ディレクトリにあるindex.js
を以下のように書き換えて、不要なものを全て削除します。
import React from "react";
import Head from 'next/head';
import Link from 'next/link';
import styles from '../styles/Home.module.css';
const Home = () => {
return (
<div className={styles.container}>
<Head>
<title>Create Next App</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<h1 className={styles.title}>Top</h1>
<Link href="/lp">
<a style={{ textDecoration:'underline' }} className={styles.title}>LPへのリンク</a>
</Link>
</main>
</div>
)
}
export default Home;
/lp
のページはこれから作成します。
上記の画像のようになっていれば成功です。 |
3. 「_document.js」の設定とテストページの作成
以下のコマンドを入力して、プロジェクトのルートディレクトリにいるか確認します。
$ ls
> README.md node_modules package.json pages public styles yarn.lock
pages
ディレクトリがあればOKです。
以下のコマンドを入力して、pages
ディレクトリに移動します。
$ cd pages
以下のコマンドを入力して、_document.js
ファイルを作成します。
$ touch _document.js
作成した_document.js
ファイルを、以下のように書き換えます。
import React, { Fragment } from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
class MyDocument extends Document {
static async getInitialProps(ctx) {
const isProduction = process.env.NODE_ENV === 'production';
const initialProps = await Document.getInitialProps(ctx);
return { ...initialProps, isProduction };
}
render() {
const { isProduction } = this.props;
return (
<Html>
<Head>
{isProduction && (
<Fragment>
<script async src="https://www.googletagmanager.com/gtag/js?id={{AnalyticsのID}}" />
<script
dangerouslySetInnerHTML={{
__html: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '{{AnalyticsのID}}', { 'optimize_id': '{{OptimizeのID}}'});
`
}}
/>
</Fragment>
)}
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument;
{{AnalyticsのID}}
と{{OptimizeのID}}
は、後ほど書き換えます。
テストページの作成
以下のコマンドを入力して、pages
ディレクトリにいるか確認します。
$ ls
_app.js _document.js api index.js
以下のコマンドを入力して、OptimizeでA/Bテストを行うためのページを作成します。
$ touch lp.js
作成したlp.js
ファイルを、以下のように書き換えます。
import React from "react";
import Head from 'next/head';
import Link from 'next/link';
import styles from '../styles/Home.module.css';
const lp = () => {
return (
<div className={styles.container}>
<Head>
<title>LP</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<h1 className={styles.title}>LP</h1>
<Link href="/">
<a style={{ textDecoration:'underline' }} className={styles.title}>Topへのリンク</a>
</Link>
<span style={{ background: '#222222', color: '#ffffff', padding: '16px', marginTop: '16px', borderRadius: '8px', cursor: 'pointer' }}>
LPのボタン
</span>
</main>
</div>
)
}
export default lp;
上記画像のデザインになっていて、かつトップページからテストページへの遷移が出来る様になっていれば成功です。 |
4. 「アクティベーションイベント」の書き込み
非同期通信の場合、テスト有効化のタイミングをアクティベーションイベント発火後にする必要があります。
なのでまず、テストページでイベントが発火するように設定します。
dataLayer.push({'event': 'optimize.activate'});
上記のコードをlp.js
に書き込みます。
import React, { useEffect } from "react";
import Head from 'next/head';
import Link from 'next/link';
import styles from '../styles/Home.module.css';
const lp = ( location ) => {
useEffect(() => {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({'event': 'optimize.activate'});
}, [location.pathname])
return (
<div className={styles.container}>
<Head>
<title>LP</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<h1 className={styles.title}>LP</h1>
<Link href="/">
<a style={{ textDecoration:'underline' }} className={styles.title}>Topへのリンク</a>
</Link>
<span style={{ background: '#222222', color: '#ffffff', padding: '16px', marginTop: '16px', borderRadius: '8px', cursor: 'pointer' }}>
LPのボタン
</span>
</main>
</div>
)
}
export default lp;
5. 「Google Analytics(GA4)」のアカウント作成
事前にGoogle Analyticsのダッシュボードにログインしてください。
Step1 |
---|
サイドバーの【管理】をクリックし【アカウント作成】をクリックします。 |
Step2 |
---|
「アカウント名」を入力して【次へ】をクリックします。 |
Step3 |
---|
【詳細オプションを表示】をクリックします。 |
Step4 |
---|
「ユニバーサルアナリティクスプロパティの作成」のトグルをONにします。 URLを入力して【次へ】をクリックします。 |
ユニバーサルアナリティクスプロパティでないと、Google Optimizeは使えないので、必ずトグルをONにしてください。
Step5 |
---|
「ビジネスの概要」の入力は任意なので【作成】をクリックします。 |
Step6 |
---|
利用規約を読み、チェックを入れて【同意する】をクリックします。 |
6. 「Google Optimize」のアカウント作成
Step1 |
---|
Google Optimizeの公式ページにアクセスして【無料で利用する】をクリックします。 |
Step2 |
---|
【利用を開始】をクリックします。 |
Step3 |
---|
【次へ】をクリックします。 |
Step4 |
---|
チェックを入れて【完了】をクリックします。 |
Step5 |
---|
【アカウントを作成】をクリックします。 |
Step6 |
---|
「アカウント名」を入力し、チェックを入れて【次へ】をクリックします。 |
Step7 |
---|
「コンテナ名」を入力し【作成】をクリックします。 |
7. 「Google Analytics」と「Google Optimize」の連結
Step1 |
---|
コンテナのダッシュボードにアクセス出来ている事を確認し【設定】をクリックします。 |
Step2 |
---|
【アナリティクスへリンクする】をクリックします。 |
Step3 |
---|
作成したGoogle Analyticsのプロパティを選択します。 |
現状(2020/12/09時点)は、GA4のプロパティは表示されません。
プロパティとリンクさせないとOptimizeは使えないので、ユニバーサルアナリティクスプロパティでないと、Optimizeは使えないことになります。
8. 「Next.js」にGAとOptimizeのIDを書き込む
GAとOptimizeのリンクに成功するとIDが分かるので、これを_document.js
に書き込みます。
import React, { Fragment } from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
class MyDocument extends Document {
static async getInitialProps(ctx) {
const isProduction = process.env.NODE_ENV === 'production';
const initialProps = await Document.getInitialProps(ctx);
return { ...initialProps, isProduction };
}
render() {
const { isProduction } = this.props;
return (
<Html>
<Head>
{isProduction && (
<Fragment>
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-185122844-1" />
<script
dangerouslySetInnerHTML={{
__html: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-185122844-1', { 'optimize_id': 'OPT-MZN2N7K'});
`
}}
/>
</Fragment>
)}
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument;
package.jsonの設定を変更する
後述のNetlifyでのbuildをするため、package.json
のscriptを以下のように変更します。
"scripts": {
"dev": "next",
"build": "next build",
"export": "next export",
"deploy": "npm run build && npm run export",
"start": "next start",
"test": "echo \"No test specified\" && exit 0"
},
RepositoryにPushする
「Next.js」の設定は全て完了したので、
- GitHub
- Bitbucket
- GitLab
いずれかにRepositoryを作り、Pushしておきます。
9. 「Netlify」の設定
事前にNetlifyのダッシュボードにログインしてください。
Step1 |
---|
【New site from Git】をクリックします。 |
Step2 |
---|
PushしたGitのサービスをクリックします。 |
Step3 |
---|
PushしたRepositoryを選択します。 |
Step4 |
---|
Build command → npm run deploy Publish directory → out/ と入力し【Deploy site】をクリックします。 |
Step5 |
---|
Deploy中のログをクリックします。 |
Step6 |
---|
Deployが終了し「Site is live ✨」と表示されるか確認します。 |
Step7 |
---|
【Site overview】をクリックし、URLが表示されていれば成功です。 |
10. 「Google Optimize」でのテスト
- 「エクスペリエンス」の作成
- デザインの変更
- 「パターンの比重」の変更
- 「測定と目標」の変更
- Optimizeの動作確認
- 「アクティベーションイベント」の設定
- テスト開始
の7つに分解して解説します。
1. 「エクスペリエンス」の作成
Step1 |
---|
コンテナを選択して【開始】をクリックして、エクスペリエンスを作成します。 |
Step2 |
---|
テスト名とテストするページのURLを入力し【作成】をクリックします。 |
2. デザインの変更
Step1 |
---|
【パターンを追加】をクリックします。 |
Step2 |
---|
「パターン名」を入力し【完了】をクリックします。 |
Step3 |
---|
【編集】をクリックします。 |
Step4 |
---|
ボタンを選択し【要素を編集】→【HTMLを編集】をクリックします。 |
Step5 |
---|
↑ Before ↑ |
↑ After ↑ |
こちらのソースコードに変更して【適用】をクリックします。 |
以下コピペ用です。
<span style="background: rgb(255, 0, 255); color: rgb(255, 255, 255); padding: 16px; margin-top: 16px; border-radius: 8px; cursor: pointer;">LPのボタンを変更しました</span>
Step6 |
---|
デザインが変更されているのを確認し【保存】→【完了】をクリックします。 |
3. 「パターンの比重」の変更
Optimizeでの動作テストを行いたいので、オリジナルのデザインを表示させないために、追加したパターンの表示比重を100%にします。
実際のA/Bテストでは、オリジナルと変更したデザイン半分ずつ表示させてテストを行うので、比重を変更する必要はございません。
Step1 |
---|
【比重】をクリックします。 |
Step2 |
---|
【カスタムの割合】に変更して、追加したパターンの比重を100%にして【完了】をクリックします。 |
4. 「測定と目標」の変更
Step1 |
---|
「測定と目標」の【テスト目標を追加】をクリックします。 |
Step2 |
---|
【リストから選択】をクリックします。 |
Step3 |
---|
メインとなる目標を選択します。 |
実際のテストでは、目標となる項目がない場合【カスタム目標を作成】から目標を新規作成します。
5. Optimizeの動作確認
Step1 |
---|
「設定」の【インストールを確認】をクリックします。 |
Step2 |
---|
正しくインストールされていることを確認し【ウェブサイト エクスペリエンスに戻る】をクリックします。 |
アクティベーションイベント後にテストをする場合、アンチフリッカースニペットを設定する必要はございません。
注意書きは無視していただいて構いません。
6. 「アクティベーションイベント」の設定
Step1 |
---|
「設定」の「アクティベーションイベント」から【ページの読み込み】をクリックします。 |
Step2 |
---|
【カスタムイベント】をクリックします。 |
Step3 |
---|
イベント名がoptimize.active になっていることを確認し【完了】をクリックします。 |
7. テスト開始
【開始】をクリックし「実行中」のステータスに切り替わったら、テストが開始されます。
テストが正常に反映されていたら完了です。 |
ご注意
テストの確認はGoogle Chromeのシークレットブラウザで行ってください。
キャッシュの影響でテストが正常に反映されない可能性があります。
初期設定のままテストを行った場合
結論からいうと、ページ読み込み時に一瞬テスト結果が反映され、その後JavaScriptがテスト結果を上書きします
また非同期通信はページ遷移時に読み込みが発生しないので、ページ遷移した際テスト結果が反映されません。
初期設定のままテストを行うと、テスト結果が反映されない。 |
その為テスト有効化のタイミングを、アクティベーションイベント発火後に設定するのです。
どのライブラリでもイベント発火後にテストを実施しないといけない
フロントエンドのライブラリを支える技術を「Single Page Application(SPA)」といいます。
非同期通信の技術を使って、JavaScriptがDOMを操作してページを切り替えています。
基本的にはどのライブラリでもA/Bテストを行う場合「アクティベーションイベント発火後」に設定する必要があります。
「非同期通信」という共通の技術を使っているからです。
JavaScriptがテスト結果を上書きしてしまうので、必ずイベント発火後にテストを実施しないといけません。
余談:Google Tag Manager(GTM)は公式非推奨
前述のアンチフリッカースニペットの項目にもありますが、Google Tag Managerを使ってOptimizeタグを配信することは、公式から非推奨の勧告が出ています。
GTMを使う場合、Optimizeコンテナを読み込む前にGTMコンテナを読み込みます。
両方読み込むまでテストが開始されないので、数値に誤差が出る可能性があります。
正確な測定結果が重要な「仮説検証」で、数値の誤差が出るのは致命的です。
その為OptimizeのタグはGTMを使わず、直接埋め込みOptimizeコンテナを先に読み込ませます。
最後に
SPAとOptimizeの設定を解説した記事はいくつかあります。
私も過去にGatsbyでOptimizeを使う方法を解説した記事を書きました。
ですが、環境構築からテストまで一気通貫で、かつ画像入りで解説した記事はなかったので、自分で執筆してみました。
SPAでOptimizeを使い始めた際は、アクティベーションイベントの件は全く知らなかったので、数値の誤差が出ているテストを、自分が気付かない内に執り行っていました。
テスト結果が反映されなくても、Optimizeではデザインを変更したBパターンとして記録されます。
なので気付きにくいのです。
今回は以上になります。