【調査・改善】Laravel 11.xでスクロールの深さを記録する

こんにちは。フリーランス・コンサルタント&エンジニアの 九保すこひ です。

さてさて、40,000件以上のプレスリリースが登録されているサイトを移転した記事を公開しました。

📝 【Laravel】最小構成でサーバー移転する5ステップ

おかげで504は発生しなくなり、アクセスも増えています♪

そして、この機会に「Webライティング」技術を使って、少しだけ長い文章を追加したんです。

個人的にはいい感じなんですが、実際「どこまで読まれたか?」を把握しないと、文章のいい悪いが判断できませんよね。

そこで、あるデータを使って調査をすることにしました。

それは・・・・・・

スクロール位置

です。

どれだけ深い場所までスクロールされたか」を知ることができれば、それだけ読者が興味をもっているかを調査できるわけですね。

そこで、過去に書いた機能で調査することにしました。

📝 【Laravel】ランディングページのどこで離脱したかチェックする

しかし、ある大きな欠点があること気づいたんです!

それは・・・・・・

 パソコンとスマホだとスクロール位置が違う😱

んです。

もちろんタブレットでもスクロール位置は違うので、調査データとしてふさわしくないんですね。

そこで、今回はこの欠点を補って「画面上の一番にあるテキスト」を保存することにしました。

例えば、以下だと「3行目のテキスト」が保存されるようにするわけです。

– – – – – – – – – 画面トップ – – – – – – – – –
3行目のテキスト←ここ
4行目のテキスト
5行目のテキスト
(…続く)

そこで❗

今回はスクロール位置だけでなく、テキストも保存できる調査機能をLaravelで実装してみることにしました。

以下のような方に向けて書いています。

  • ランディングページの反応がいいところ、悪いところを把握したい
  • 商品ページの離脱している場所を特定して改善したい
  • イベントページに表示するコンテンツの順番を変更する材料がほしい

ぜひ最後まで読んでくださいね!

「マーケ本『No Flop!』にも、
データは独自に取れって
書いてました👍」

【Laravel・スクロール調査】DBまわりに必要なファイルは2つ

データベース関連で必要な2ファイルをつくります。

  • モデル:データの出し入れ担当
  • マイグレーション:データベース設計書

以下コマンドで一気に2ファイルを作成できます。

php artisan make:model ScrollSurvey -m

作成したファイルはそれぞれ中身を変更してください。

1:モデル

app/Models/ScrollSurvey.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class ScrollSurvey extends Model
{
    use HasFactory;

    protected $fillable = [
        'survey_key',
        'scroll_top',
        'starting_text',
    ];
}

$fillableを定義して、以下のように値をセットできる項目を指定してます。

$scrollSurvey->scroll_top = 150; // 値をセット

2:マイグレーション

テーブル「scroll_surveys」に必要なのは以下5つです。

名称 意味
id 通し番号
survey_key 調査ごとのキー(ID)
scroll_top スクロール位置
starting_text 開始テキスト
created_at 登録日時
updated_at 更新日時

database/migrations/****_**_**_******_create_scroll_surveys_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('scroll_surveys', function (Blueprint $table) {
            $table->id();
            $table->string('survey_key')->comment('調査キー');
            $table->unsignedInteger('scroll_top')->comment('スクロール位置');
            $table->string('starting_text')->comment('開始テキスト');
            $table->timestamps(); // created_at, updated_at
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('scroll_surveys');
    }
};

ちなみに、お好みで滞在時間やIPアドレスを保存してもいいかもしれませんね👍

では、この状態でマイグレーションを実行してみましょう。

php artisan migrate

実際のテーブルはこうなりました。

【Laravel・スクロール調査】コントローラーで調査データを保存

調査データを保存するコントローラーをつくります。

以下のコマンドを実行してください。

php artisan make:controller ScrollSurveyController

作成されたファイルは以下のように変更します。

app/Http/Controllers/ScrollSurveyController.php

<?php

namespace App\Http\Controllers;

use App\Models\ScrollSurvey;
use Illuminate\Http\Request;

class ScrollSurveyController extends Controller
{
    public function store(Request $request)
    {
        $request->validate([
            'survey_key' => 'required|string',
            'scroll_top' => 'required|integer',
            'starting_text' => 'required|string',
        ]);

        $scrollSurvey = new ScrollSurvey();
        $scrollSurvey->survey_key = $request->survey_key;
        $scrollSurvey->scroll_top = $request->scroll_top;
        $scrollSurvey->starting_text = $request->starting_text;
        $scrollSurvey->save();
    }

    public function test()
    {
        return view('scroll_survey.test');
    }
}

中身としてはバリデーションがあって、保存するブロックがある基本的なコードになっています。

今回はページ移動する直前にアクセスされるものなので、返り値(returnの部分)は省略しています。

【Laravel・スクロール調査】ビューで調査データを自動送信

今回はスクロール位置を保存する機能のため、テストで縦に長いページが必要になってきます。

この「ビュー(≒HTML)」をつくっていきましょう。
以下のコマンドを実行してください。

php artisan make:view scroll_survey.test

ファイルが作成されるので、中身を以下のように変更します。

※今回はどの環境でも使えるようにネイティブJavaScriptを使って実装します。

resources/views/scroll_survey/test.blade.php

<html>
<head>
    <meta name="csrf-token" content="{{ csrf_token() }}">
</head>
<body>
    <div id="app">
        @for($i = 1; $i <= 100; $i++)
            <p>{{ $i }}行目のテキストですテキストですテキストですテキストですテキストです!</p>
        @endfor
        <div style="position:fixed;left:15px;bottom:15px;display:block;background-color:#ddd;padding:15px;">
            <a href="">ページ移動</a>
        </div>
    </div>
    <script>

        // 共通
        let params = {
            survey_key: 'your-survey-key',
            scroll_top: 0,
            starting_text: '',
        };

        // スクロールイベント
        const onScroll = () => {

            const currentScrollTop = window.scrollY;

            if(currentScrollTop > params.scroll_top) { // 最大値を更新

                params.scroll_top = currentScrollTop;
                params.starting_text = getStartingText();

            }

        };
        const getStartingText = () => {

            const elements = document.body.getElementsByTagName('*');

            for(const element of elements) {

                const rect = element.getBoundingClientRect();

                if (rect.top >= 0 && rect.bottom > 0 && element.innerText.trim() !== '') {

                    return element.innerText
                        .trim()
                        .substring(0, 25) +'...';

                }

            }

            return '';

        };

        // ページ遷移イベント
        const onBeforeUnload = () => {

            const url = '{{ route('scroll_survey.store') }}';
            const headers = {
                'Content-Type': 'application/json',
                'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
            }

            fetch(url, {
                method: 'POST',
                headers: headers,
                body: JSON.stringify(params)
            });

        };

        // ページ読み込みイベント
        window.onload = () => {

            window.addEventListener('scroll', onScroll); // スクロールイベント
            window.addEventListener('beforeunload', onBeforeUnload); // ページ遷移イベント

        };

    </script>
</body>
</html>

ここでは3つのブロックに分けています。

  • スクロールイベント
  • ページ遷移イベント
  • ページ読み込みイベント

ひとつずつ紹介していきましょう!

1:スクロールイベント

ページがスクロールされたときに実行されるコードです。
ここではスクロールされるたびに以下2つのデータを取得しています。

  • スクロール位置
  • 画面の一番上にあるテキスト

ただし、スクロール位置の場合、下の方へスクロールして、また上に戻ってくることも想定されるので、最大値(深さ)を更新するようにしています。

2:ページ遷移イベント

ページ遷移とは、具体的には以下の行動があったときです。
実際にはその直前に実行されます。

  • タブやウィンドウを閉じた
  • 戻るボタンでページが戻った
  • リンクから別のページへ移動した

そして、ここで調査データが送信されます。

今回は先ほどのコントローラーScrollSurveyControllerstore()メソッドへ送信されて、データ保存されることになりますね。

なお、今回はテストなので全ての要素をチェックしていますが、本番環境ではidをつけてるなどして、範囲を指定するといいでしょう。 

※「ページ移動」リンクはテストしやすくするために作ったリンクです。

3:ページ読み込みイベント

ここでは「スクロールイベント」「ページ遷移イベント」を起動しているだけです。

【Laravel・スクロール調査】ルートはシンプルな構成

最後にルート(URL)の設定をつくります。

routes/web.php

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ScrollSurveyController;

// スクロール位置の調査
Route::prefix('scroll_survey')->controller(ScrollSurveyController::class)->group(function () {
    Route::post('/', 'store')->name('scroll_survey.store');
    Route::get('/test', 'test')->name('scroll_survey.test'); // テスト用
});

これで作業は完了です!
お疲れ様でした。😊✨

【Laravel・スクロール調査】テストしてスクロールデータが自動保存できるか確認する

では、実際にテストして調査データが保存できるかテストしてみましょう!

1:ブラウザでアクセスする

実際にブラウザで「https://********/scroll_survey/test」へアクセスしてみましょう。

以下のように表示されるはずです。

リンクを拡大するとこうなります。

2:スクロールしてページ移動する

ランダムにページをスクロールさせて、以下の状態で「ページ移動」リンクをクリックしてみましょう。

どうなるでしょうか・・・・・・

はい❗

スクロール位置だけでなく、画面一番上にあるテキストまで取得することができました。

3:スクロールして戻るボタンを押す

今度は22行目まで移動して戻るボタンを押してみました。

どうなるでしょうか・・・・・・

はい❗
こちらもうまく調査データが保存されました。

4:スクロールしてタブを閉じてみる

最後に31行目までスクロール移動して、いきなりタブを閉じてみましょう。

うまくいくでしょうか・・・・・・

はい❗❗
これもうまくいきましたね。

すべて成功です😊✨

【Laravel・スクロール調査】実施したい企業様へ

今回のように調査データを保存しつつ改善を施すことで以下のようなメリットが期待できます。

  • ユーザーの離脱位置がわかる
  • A/Bテストでより読まれる文章へ改善できる

つまり、問題のある部分を特定し、少しずつユーザーのスクロールを深くしていくわけです。 

こうすることで、最終的に成約させたいページやフォームへ移動させることができ、売上の改善につながるでしょう。

もしそうしった施策を実行したい場合は、ぜひお問い合わせからご相談ください。

お待ちしております。😊✨

おわりに

今回はLaravelを使って過去記事の機能をブラッシュアップしてみました。

本来作成した機能は、実際に使って改善していくことで、より価値があるものになるといくのを体験できました。

ということで、実際にこの機能は40,000件登録されてるプレスリリース発行サイトへ適用してみます!

ぜひ皆さんもいろいろと調査データでサイト改善をしてみてくださいね。

ではでは〜❗

「次は、夏休みの
自由研究的な記事を予定してます。
お楽しみに〜👍」

このエントリーをはてなブックマークに追加       follow us in feedly  
開発のご依頼お待ちしております
開発のご依頼はこちらから: お問い合わせ
どうぞよろしくお願いいたします! by 九保すこひ