MatomoでReactアプリをトラッキングしてみた（アクセス解析）

オープンソースのアクセス解析ツール「[Matomo](https://matomo.jp/)」を使って、Reactアプリをトラッキングしてみました。

- 環境：Windows 11のWSL（Ubuntu）で作業し、ブラウザのみWindows側を使用しました。

# Matomoのインストールと起動

本記事では、Matomoはローカル環境のDockerで起動します。

## docker-compose.yml等の準備

WSLのコンソールで作業ディレクトリを作成します。ディレクトリ名は何でも良いです。

```bash

cd
mkdir docker_matomo
cd docker_matomo
```

以下のサイトから、[docker-compose.yml](https://github.com/matomo-org/docker/blob/master/.examples/apache/docker-compose.yml)と[db.env](https://github.com/matomo-org/docker/blob/master/.examples/apache/db.env)を持ってきて、作業ディレクトリに保存します。

https://github.com/matomo-org/docker/tree/master/.examples/apache

### docker-compose.ymlの編集

- MYSQL_ROOT_PASSWORDにパスワードを設定します。
- portsはホスト側とコンテナ側で同じ値（80）に設定し直しました。

```diff

version: "3"

services:
  db:
    image: mariadb:10.11
    command: --max-allowed-packet=64MB
    restart: always
    volumes:
      - db:/var/lib/mysql:Z
    environment:
-      - MYSQL_ROOT_PASSWORD=
+      - MYSQL_ROOT_PASSWORD=secret
      - MARIADB_AUTO_UPGRADE=1
      - MARIADB_DISABLE_UPGRADE_BACKUP=1
    env_file:
      - ./db.env

  app:
    image: matomo
    restart: always
    volumes:
#     - ./config:/var/www/html/config:z
#     - ./logs:/var/www/html/logs:z
      - matomo:/var/www/html:z
    environment:
      - MATOMO_DATABASE_HOST=db
    env_file:
      - ./db.env
    ports:
-      - 8080:80
+      - 80:80

volumes:
  db:
  matomo:
```

### db.envの編集

- MYSQL_PASSWORDにパスワードを設定します。
- MATOMO_DATABASE_PASSWORDにパスワードを設定します。

```diff

-MYSQL_PASSWORD=
+MYSQL_PASSWORD=secret
MYSQL_DATABASE=matomo
MYSQL_USER=matomo
MATOMO_DATABASE_ADAPTER=mysql
MATOMO_DATABASE_TABLES_PREFIX=matomo_
MATOMO_DATABASE_USERNAME=matomo
-MATOMO_DATABASE_PASSWORD=
+MATOMO_DATABASE_PASSWORD=secret
MATOMO_DATABASE_DBNAME=matomo
MARIADB_AUTO_UPGRADE=1
MARIADB_INITDB_SKIP_TZINFO=1
```

## コンテナ群の起動

以下を実行します。

```bash

docker compose up -d
```

ビルドが走って、以下のように表示されました。

```

[+] Running 28/28
 ✔ db 8 layers [⣿⣿⣿⣿⣿⣿⣿⣿]      0B/0B      Pulled                                                                  12.7s
   ✔ 74ac377868f8 Pull complete                                                                                    6.4s
   ✔ 9f8acee20aa1 Pull complete                                                                                    6.4s
   ✔ 11b336495e01 Pull complete                                                                                    6.9s
   ✔ 20ab1641dd41 Pull complete                                                                                    6.9s
   ✔ eaf0c5c99086 Pull complete                                                                                    7.0s
   ✔ 239335430207 Pull complete                                                                                    9.2s
   ✔ 931baaab2c80 Pull complete                                                                                    9.2s
   ✔ f2e86cc8f052 Pull complete                                                                                    9.3s
 ✔ app 18 layers [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿]      0B/0B      Pulled                                                       9.3s
   ✔ 26c5c85e47da Pull complete                                                                                    2.0s
   ✔ 39c8021d1258 Pull complete                                                                                    2.1s
   ✔ dff43c2de684 Pull complete                                                                                    3.4s
   ✔ 383987c505e8 Pull complete                                                                                    3.5s
   ✔ 3fd742e8a904 Pull complete                                                                                    3.7s
   ✔ ccf9807e8362 Pull complete                                                                                    3.8s
   ✔ 11cc7ce10028 Pull complete                                                                                    3.8s
   ✔ 57c835f75a27 Pull complete                                                                                    3.9s
   ✔ 4c8d91ebbe83 Pull complete                                                                                    4.0s
   ✔ 48c538ea40cd Pull complete                                                                                    4.2s
   ✔ dcf6e657c420 Pull complete                                                                                    4.3s
   ✔ 564cd8aea1b3 Pull complete                                                                                    4.3s
   ✔ be10554faca5 Pull complete                                                                                    4.4s
   ✔ 9b84d91a239c Pull complete                                                                                    4.5s
   ✔ a6d225b9a14a Pull complete                                                                                    4.5s
   ✔ dfd639ae08f5 Pull complete                                                                                    5.7s
   ✔ 8284bbea84df Pull complete                                                                                    5.8s
   ✔ 0bf4e56844a0 Pull complete                                                                                    5.8s
[+] Running 0/1
 ⠇ Network docker_matomo_default  Creating                                                                         0.9s
[+] Running 5/5t of type `volume` should not define `bind` option
 ✔ Network docker_matomo_default  Created                                                                          0.9s
 ✔ Volume "docker_matomo_matomo"  Created                                                                          0.0s
 ✔ Volume "docker_matomo_db"      Created                                                                          0.0s
 ✔ Container docker_matomo-db-1   Started                                                                          1.9s
 ✔ Container docker_matomo-app-1  Started
```

コンテナ群が起動したか確認します。

```

docker compose ps
```

以下のように起動が確認できました。

```

NAME                  IMAGE               COMMAND                  SERVICE             CREATED             STATUS              PORTS
docker_matomo-app-1   matomo              "/entrypoint.sh apac…"   app                 36 seconds ago      Up 34 seconds       0.0.0.0:80->80/tcp, :::80->80/tcp
docker_matomo-db-1    mariadb:10.11       "docker-entrypoint.s…"   db                  36 seconds ago      Up 34 seconds       3306/tcp
```

## ブラウザでMatomoサイトに行く

ブラウザで http://localhost にアクセスします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/8f2149b4-8518-ed80-0f7f-901e1fbcb0bb.png)

内容を確認しながら「次へ」ボタンを押します。
「5. スーパーユーザー」の画面で、スーパーユーザーの設定を行いました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/b98c1d16-d995-60ef-04a5-9e3dfc1af80d.png)

「6. ウェブサイトのセットアップ」の画面で、後ほど作成するReactアプリの情報を入力しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/e600be7c-7078-37bf-5538-5e5d82ae5793.png)

「8. おめでとうございます」の画面で、「MATOMOを続ける」ボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/5156b06e-c331-3c59-b48f-239aa350dbff.png)

以下の画面が出たら、サインインします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/94af5c67-6f6e-4616-e5e7-16f9799d28ec.png)

サインインに成功しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/4d747bea-72ea-5f50-83aa-ad4ac669cdd2.png)

Matomo等のバージョンは以下の通りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/bbaf6b1b-b765-144b-ab94-7e661d16f2f2.png)

# Reactアプリの作成

[このページ](https://www.npmjs.com/package/@datapunt/matomo-tracker-react)を参考に、簡易的なReactアプリを実装しました。
以下、ソースコードだけ載せます。

```package.json

{
  "name": "try_matomo",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "@datapunt/matomo-tracker-react": "^0.5.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.10.0"
  },
  "devDependencies": {
    "@types/react": "^18.0.27",
    "@types/react-dom": "^18.0.10",
    "@vitejs/plugin-react": "^3.1.0",
    "typescript": "^4.9.3",
    "vite": "^4.1.0"
  }
}
```

```main.tsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import { MatomoProvider, createInstance } from '@datapunt/matomo-tracker-react'

const instance = createInstance({
    urlBase: 'http://localhost',
    siteId: 1,
    userId: undefined, // optional, default value: `undefined`.
    trackerUrl: 'http://localhost/matomo.php', // optional, default value: `${urlBase}matomo.php`
    srcUrl: 'http://localhost/matomo.js', // optional, default value: `${urlBase}matomo.js`
    disabled: false, // optional, false by default. Makes all tracking calls no-ops if set to true.
    heartBeat: { // optional, enabled by default
        active: true, // optional, default value: true
        seconds: 10 // optional, default value: `15
    },
    linkTracking: false, // optional, default value: true
    configurations: { // optional, default value: {}
        // any valid matomo configuration, all below are optional
        disableCookies: true,
        setSecureCookie: true,
        setRequestMethod: 'POST'
    }
})

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
    // @ts-ignore
    <MatomoProvider value={instance}>
        <App />
    </MatomoProvider>
)
```

```App.tsx

import {Page1} from "./pages/Page1"
import {Page2} from "./pages/Page2"
import {BrowserRouter, Route, Routes} from "react-router-dom";

function App() {
    return (
        <div>
            <BrowserRouter>
                <Routes>
                    <Route path="/page1" element={<Page1 />} />
                    <Route path="/page2" element={<Page2 />} />
                </Routes>
            </BrowserRouter>
        </div>
    )
}

export default App
```

```pages/Page1.tsx

import React from "react";
import { useMatomo } from '@datapunt/matomo-tracker-react'

export const Page1 : React.FC = () => {
    const { trackPageView, trackEvent } = useMatomo()
    React.useEffect(() => {
        trackPageView({
            documentTitle: 'page1'
        });
    }, [])

    return (
        <div>
            <button
                onClick = {(e) => {
                    trackEvent({ category: 'page1', action: 'onClick' });
                }}
            >
                page1
            </button>
        </div>
    )
}
```

Page2.tsxはPage1.tsxからコピーし、1を2に置換しました。

```pages/Page2.tsx

import React from "react";
import { useMatomo } from '@datapunt/matomo-tracker-react'

export const Page2 : React.FC = () => {
    const { trackPageView, trackEvent } = useMatomo()
    React.useEffect(() => {
        trackPageView({
            documentTitle: 'page2'
        });
    }, [])

    return (
        <div>
            <button
                onClick = {(e) => {
                    trackEvent({ category: 'page2', action: 'onClick' });
                }}
            >
                page2
            </button>
        </div>
    )
}
```

# Reactアプリの実行とMatomoダッシュボード確認

Reactアプリ起動前は、Matomoのビジット数・アクション数は0になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/3764aa19-2639-c3d7-f0e6-9250693e2dc3.png)

Reactアプリを起動し、http://localhost:5173/page1 にアクセスします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/106fcd62-744d-cd11-6274-34dc38b20e43.png)

Matomoのビジット数・アクション数が1になりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/31d4b5e0-e012-dbec-1987-0697948534be.png)

Matomoで「ビジター」→「ビジットログ」へ行くと、以下のようにpage1へのアクセスが観測できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/ed9f2ced-dd0a-07a3-e194-2952ae40bdd8.png)

Reactアプリで「page1ボタン」を2回押した後、http://localhost:5173/page2 にアクセスして「page2ボタン」を3回押しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/a35d0a32-2257-201a-e462-5eee1edca62a.png)

Matomoで「リアルタイム」に行くと、以下のようにアクション数が7に増えたことが確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/7f5c2d49-d58b-65e7-b6b1-3be607123d45.png)

Matomoで「ビジットログ」を押すと、以下のように2回のページアクセスと5回のボタン押下が観測できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/1d6d4b89-95bc-79b5-e3e6-a5cda7242815.png)

Reactアプリで再び http://localhost:5173/page1 にアクセスし、「page1」ボタンを5回押しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/3597f69f-61a2-02ed-078d-74a06cceb6a8.png)

Matomoでビジットログを押すと、以下のようにPage1へのアクセスとボタン押下が観測できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/d784707c-c3d9-f00e-0ff7-c52a06799d6e.png)

# 参考サイト（感謝します）

- [MatomoJa](https://matomo.jp/)
- [Matomo Analytics](https://github.com/matomo-org)
- [Matomo Tracker (React)](https://www.npmjs.com/package/@datapunt/matomo-tracker-react)
- [Adding Matomo tracker to React App with Typescript](https://forum.matomo.org/t/adding-matomo-tracker-to-react-app-with-typescript/45001)