Google Analyticsの代わりを1日で作る|サイト運営者のための軽量分析ツール構築術
GA4の画面を開くたびに迷子になる。集計したい数字は5つしかないのに、なぜここまで複雑なのか。
そう感じたことはないだろうか。探索レポート、エンゲージメント、コンバージョン、オーディエンス、ライフサイクル。メニューを開くたびに知らない単語が増えていく。知りたいのは、昨日何人来たか、どのページが読まれたか、それだけなのに。
私のまわりにいる個人事業主やひとりメディア運営者の多くが、同じ場所でつまずいている。導入したものの見方がわからず、結局3ヶ月に1回ダッシュボードを眺めて終わる。これは時間の無駄だ。そして何より、数字を見ないから施策も打てない。
この記事では、GA4の代わりを自分で持つという選択肢を紹介する。オープンソースを使う方法と、Next.jsで最小のものを自作する方法の両方を、手順つきで解説していく。読み終わるころには、今週末の1日で自分のサイトに分析基盤を置けるようになっているはずだ。
この記事の前提

図: 小さなサイト運営者が本当に見たい5つの数字
この記事は、月1万〜10万PVほどの小さなサイトを運営している人に向けて書いている。ブログ、LP、会社紹介ページ、コーポレートサイト、ポートフォリオ。どれでもいい。共通しているのは、数字を見たい理由がはっきりしているのに、GA4が重くて開く気がしないという点だ。
前提として、私はGA4を全否定しない。大企業のマーケティングチームがファネル分析やオーディエンス設計をやり切るなら、GA4の機能は必要だ。しかしひとりで事業を回している人間が見たい数字は、せいぜい次の5つに収まる。
・1日のアクセス数 ・よく読まれているページ ・どこから来たか(検索、SNS、直リンク) ・どの端末から来たか ・どれくらいの時間滞在したか
この5つだけなら、自分の手元に置いた方が早い。しかも安い。そしてページ表示も軽くなる。この記事の立場はその一点だ。
なぜGA4は個人サイトに重すぎるのか

図: GA4 と 軽量分析ツール
まず整理しておきたい。GA4が悪いのではない。GA4は大規模サイト向けに最適化された道具で、小さなサイトに載せると確実にオーバースペックになる、という話だ。
具体的に何が重いのか。
1つ目は、計測タグそのものが重い。GA4の計測スクリプトは圧縮後でおよそ50KB前後ある。これが読み込まれるまで、ページのCore Web Vitals(ウェブ体験の指標)にじわじわ悪影響を与える。LCP(最大コンテンツ描画時間)が0.1秒伸びるだけで、検索順位に跳ねることもある。
2つ目は、レポート画面が重い。探索レポートは一度作るたびにデータを読み込み直し、表示まで10秒以上待たされることがある。知りたいのは昨日のアクセス数なのに、1枚のグラフを出すのに1分かかる。これでは習慣にならない。
3つ目は、プライバシー対応がややこしい。EUのGDPR(個人情報保護規則)や日本の改正電気通信事業法の絡みで、Cookie同意バナーを置く必要が出てくる。同意バナーを出した瞬間に、訪問者の3割は拒否ボタンを押す。計測データの精度はそこで大きく削られる。
そして4つ目。これが一番大きい。数字を見る習慣が育たない。週1回ログインして、探索レポートを開いて、フィルタを設定して、やっとグラフが出る。このフローを1年続けられる個人事業主は、正直ほとんどいない。
代わりに何を置くか、3つの道
GA4を外すとき、取れる道は大きく3つある。順番に見ていこう。
1つ目は、既存のオープンソース分析ツールを自分のサーバーに置く方法。代表選手はPlausible AnalyticsとUmamiだ。どちらも無料で使えて、導入は数時間で終わる。
2つ目は、クラウド版のシンプル分析ツールを契約する方法。Plausible、Fathom、Simple Analyticsなどが月額9ドルから出している。サーバー管理の手間がないのが利点だ。
3つ目は、自分で最小の分析ツールを書く方法。Next.jsのmiddleware(リクエスト処理の入り口)でアクセスログを取り、Supabase(データベースと認証を一体にしたサービス)に書き込み、管理画面で日次集計を出す。これが今日の記事の本丸だ。
どれを選ぶかは、かけられる時間と、カスタマイズしたい度合いで決まる。割り切ってすぐ動かしたいなら1つ目。お金で解決したいなら2つ目。自分の知りたい数字だけを追いかけたい、かつ学習も兼ねたいなら3つ目。
参考になる事例
Plausible Analytics
チェコ発のオープンソース分析ツール。2019年に共同創業者2人で始まり、今ではひとり事業者や中小企業を中心に数万アカウントが使っている。公開されている数字では、月次の経常収益が約10万ドル規模、日本円にすると月1,500万円近い。創業者が書いているのは、GA4を嫌っている層がこれだけ大きい市場なんだ、という事実そのものだ。
Plausibleの計測スクリプトは1KBほどで、GA4の50分の1。Cookieを使わない設計のため、同意バナーが不要になる場面も多い。セルフホスト版はオープンソースで、Dockerで起動するだけで動く。自分のサーバーに置けば、サブスク費用はゼロだ。
Umami
もう1つの大物がUmami。GitHubのスター数は2万を超え、日本国内でも導入事例が増えている。こちらもPostgreSQL(データベース)とNode.jsで動くシンプルな構成で、Vercel(静的サイトのホスティングサービス)に1クリックで展開できるテンプレートが公開されている。
Umamiの良さは、画面がとにかく速いことだ。ダッシュボードを開いてから主要数字が出るまで1秒もかからない。GA4を使ったあとにUmamiを触ると、分析ツールはこんなに軽くていいんだと驚くはずだ。
国内の個人メディア
私の知っている個人事業主に、コーチングのサイトを運営している人がいる。その人は長いあいだGA4を入れていたが、開くのは月1回、それも5分で閉じていた。昨年の秋、思い切ってUmamiをさくらのVPS(月額880円のサーバー)に置いた。今は毎朝5分、ダッシュボードを開く習慣ができた。新しい記事を出した翌日の反応がリアルタイムで見られるのが楽しいと話している。
この話が示しているのは、ツールが軽くなると行動が変わるという事実だ。分析は続けられて初めて意味がある。
セルフホスト版Plausibleを1時間で導入する

図: Plausibleセルフホスト導入の流れ
ここからは実際の手順に入っていく。まずは最短ルート、Plausibleのセルフホスト版を立てる場合だ。
必要なもの。
・月額1,000円前後のVPS(Hetzner、さくらのVPS、ConoHaなど) ・ドメイン1つ(サブドメインでよい、例: stats.example.com) ・Docker(コンテナを動かすソフト)が入ったサーバー
手順は次の通り。
- サーバーにSSH(遠隔で操作する仕組み)で接続する。
- 公式リポジトリをクローンする。
git clone https://github.com/plausible/community-edition plausible - .envファイルを開き、BASE_URLとSECRET_KEY_BASEを設定する。シークレットキーは
openssl rand -base64 64で生成できる。 - docker-compose up -d で起動する。
- ブラウザでstats.example.comにアクセスし、管理者アカウントを作る。
- 計測したいサイトを登録する。発行された計測タグをサイトに貼る。
ここまでで40分から1時間。GA4を導入するより明らかに速い。月1,000円のサーバー代だけで、自分のデータを自分の手元に置ける。
ただしセルフホストには注意点もある。サーバーのOSアップデートや、Plausible本体のバージョンアップは自分で回す必要がある。忘れると脆弱性を抱えたまま放置することになる。月に1回、30分でいいのでメンテナンスの時間を取ってほしい。
Next.js middlewareで自作する最小構成
ここからが本題だ。Plausibleでも満足できない人、知りたい指標だけを自分の形で追いかけたい人向けに、Next.jsで自作する方法を書く。
全体像はこうだ。
・Next.jsのmiddleware.tsでアクセスを拾う ・Supabaseのテーブルにイベントを書き込む ・管理画面(/admin/stats)でSupabaseから集計して表示する
これだけ。コードは全部で300行ほどに収まる。
データベースを用意する
まずSupabaseで新しいプロジェクトを作る。無料プランで十分だ。次にpage_viewsというテーブルを1つ作る。必要な列はこれだけ。
・id(UUID、主キー) ・created_at(日時、デフォルトでnow) ・path(アクセスされたパス) ・referer(どこから来たか) ・user_agent(端末情報) ・country(国、あとで足してもいい) ・session_id(簡易的な訪問者識別子)
SQLで書くと次のようになる。
create table page_views (
id uuid primary key default gen_random_uuid(),
created_at timestamptz default now(),
path text not null,
referer text,
user_agent text,
country text,
session_id text
);
create index idx_page_views_created_at on page_views(created_at desc);
create index idx_page_views_path on page_views(path);
インデックス(検索を速くする仕組み)は最低でも2つ貼っておく。日付順の取り出しとパス別の集計で必ず使うからだ。
middlewareでイベントを記録する
次にNext.jsのmiddleware.tsを作る。middlewareはリクエストがページに届く前に挟み込める処理の入り口だ。ここでアクセス情報を取り、Supabaseに送る。
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export async function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
if (pathname.startsWith('/_next') || pathname.startsWith('/api')) {
return NextResponse.next();
}
const sessionId = request.cookies.get('sid')?.value ?? crypto.randomUUID();
fetch(`${process.env.SUPABASE_URL}/rest/v1/page_views`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': process.env.SUPABASE_SERVICE_KEY!,
'Authorization': `Bearer ${process.env.SUPABASE_SERVICE_KEY}`,
},
body: JSON.stringify({
path: pathname,
referer: request.headers.get('referer') ?? null,
user_agent: request.headers.get('user-agent') ?? null,
country: request.headers.get('x-vercel-ip-country') ?? null,
session_id: sessionId,
}),
}).catch(() => {});
const response = NextResponse.next();
response.cookies.set('sid', sessionId, {
maxAge: 60 * 30,
httpOnly: true,
sameSite: 'lax',
});
return response;
}
export const config = {
matcher: ['/((?!_next|api|favicon.ico).*)'],
};
ポイントはいくつかある。
1つ目は、fetchを待たずに返していること。計測のために表示速度を落とすのは本末転倒だ。ログ送信は投げっぱなしにして、エラーがあっても握りつぶす。
2つ目は、session_idをCookieで30分持つこと。30分以上間隔が空いたら別セッションとみなす、という業界標準の定義に合わせている。
3つ目は、_nextやapiへのアクセスは除外していること。これを入れないとアセット(画像やJSファイル)の読み込みまで全部記録されてしまう。
管理画面で集計する
次にダッシュボード。/app/admin/stats/page.tsxを作り、Supabaseから昨日の数字を取ってくる。コードの骨格はこうだ。
import { createServerClient } from '@/lib/supabase-server';
export default async function StatsPage() {
const supabase = createServerClient();
const since = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
const { data: views } = await supabase
.from('page_views')
.select('path, session_id, referer')
.gte('created_at', since);
const totalViews = views?.length ?? 0;
const uniqueSessions = new Set(views?.map(v => v.session_id)).size;
const pathCounts = new Map<string, number>();
views?.forEach(v => {
pathCounts.set(v.path, (pathCounts.get(v.path) ?? 0) + 1);
});
const topPaths = [...pathCounts.entries()]
.sort((a, b) => b[1] - a[1])
.slice(0, 10);
return (
<div>
<h1>昨日のアクセス</h1>
<p>ページビュー: {totalViews}</p>
<p>訪問者: {uniqueSessions}</p>
<h2>人気ページ Top10</h2>
<ol>
{topPaths.map(([path, count]) => (
<li key={path}>{path}: {count}</li>
))}
</ol>
</div>
);
}
ここまでで、1日のアクセス数、訪問者数、よく読まれているページの3つが取れる。あと2つ、参照元と端末の集計を追加すれば、最初に挙げた5つの指標はすべて揃う。コード総量は300行にも届かない。
認証をかける
最後に絶対に忘れてはいけないこと。/admin配下に認証をかけてほしい。Supabase Authを使えば10分で済む。これを忘れると、自分のサイトのアクセス状況が世界中から丸見えになる。
Next.jsのmiddlewareで/adminへのアクセスを捕まえ、Supabaseのセッションがなければログインページに飛ばす。これだけでよい。
よくある失敗・落とし穴
ここまで読んで、よし作るぞと思ったあなたに、先回りして落とし穴を共有しておく。
落とし穴1: データを溜めすぎる
個人サイトでも1年経つと数十万行のログが溜まる。SupabaseやPostgreSQLの無料枠はストレージに上限がある。月1回、90日より古いデータを別テーブルに集計して退避し、元データは消す。これを最初から設計に入れておかないと、半年後にデータベースが固まる。
具体的には、daily_statsという集計済みテーブルを別に作り、日次でcron(定期実行)を回して1日分を集約する。元のpage_viewsは90日で消す。これで容量問題は解決する。
落とし穴2: ボットを数えてしまう
インターネットのトラフィックの半分近くはボットだ。検索エンジンのクローラー、AIの学習クローラー、スパムの巡回。これを数えると、1日のアクセス数が体感の3倍になる。
対策はシンプルで、user_agentにbot、crawl、spider、facebookexternalhitなどの文字列が含まれるリクエストをmiddleware側で除外する。これだけで8割のノイズは消える。
落とし穴3: プライバシー対応を後回しにする
Cookieを使わない設計なら同意バナーは不要、と書いたが、IPアドレスをそのまま保存すると個人情報扱いになる可能性がある。私の自作案ではIPは記録していない。これは意図的な設計だ。countryだけ記録して、IPは絶対に保存しない。この線引きを最初に決めておこう。
落とし穴4: リアルタイム性を追い求める
数字をリアルタイムで見たくなる気持ちはわかる。でも個人サイトの運営者が1分ごとの数字を見てもやることはない。1日1回、朝のコーヒーと一緒に見る、これで十分だ。リアルタイム機能を追うと開発工数が一気に跳ね上がる。
落とし穴5: 計測を目的化する
最後にこれを書いておきたい。数字を見る目的は、次の行動を決めるためだ。見て満足するためではない。昨日よく読まれた記事があったら、その続編を書く。流入元がTwitter(現X)に偏っていたら、そこでの発信頻度を上げる。この往復運動が起きて初めて分析の意味がある。
GA4から離れる理由も、ここに尽きる。見る習慣が続かない道具は、どれだけ高機能でも価値を生まない。
明日からやる3つのこと
長くなったので、行動に落とし込んで終わる。
自分が本当に見たい指標を紙に5つ書き出す。PV、UU、人気ページ、流入元、滞在時間。この5つで過不足ないか、それとも別のものが要るか、30分考える。多くの人はこのステップで、自分が今まで見てきた数字の9割は不要だったことに気づく。
週末の半日を確保して、セルフホスト版PlausibleかUmamiを1つ立ち上げる。VPSは月1,000円、ドメインは年1,500円。初期投資は2,500円だ。GA4と並行稼働させて、1週間使ってみる。軽さに驚くはずだ。
それでも物足りなかったら、Next.jsでの自作に挑戦する。この記事のコードをそのままコピーして動かすところから始めてほしい。完璧を目指さなくていい。最初は1日のアクセス数が出るだけで十分だ。そこから少しずつ、自分の欲しい数字を足していけばいい。
分析ツールは、自分の事業の計器盤だ。計器盤は軽くて、すぐ開けて、毎日見たくなるものでなければ意味がない。GA4を開くたびにため息が出るなら、それはもう自分には合っていないというサインだ。
今週末、1日だけ時間をとって、自分専用の計器盤を作ってほしい。来週の月曜の朝、コーヒーを片手にダッシュボードを開いたとき、あなたはきっとこう思う。なぜもっと早くこうしなかったんだろう、と。




