Cloudflare Pages を使用したファーストパーティトラッキング
Cloudflare Pages Functions を使用してファーストパーティプロキシをセットアップします。これはサイトが既に Cloudflare Pages でホストされている場合、最適なオプションです。
難易度: 簡単 - プロジェクトに 1 つのファイルを追加するだけです。5 分程度で完了します。
この方法が機能する理由(同一オリジン)
このアプローチは、ウェブサイトと同じオリジン上にある /api/_z/script.js を使用します。Firefox ETP などのトラッキング保護は、クロスオリジンリクエストのみをブロックします。
- ブラウザが見るもの:
yourdomain.com/api/_z/script.js→ 同一オリジン ✅ - あなたの関数は Zenovay サーバーにサーバー間でプロキシします(ブラウザはこれを見ません)
- リクエストがファーストパーティであるため、すべてのトラッキング保護がバイパスされます
開始する前に
以下があることを確認してください:
- Cloudflare Pages でデプロイされたプロジェクト
- Zenovay トラッキングコード(ドメインで見つけることができます。サイトを開き、一般タブ → トラッキングスクリプトカード)
- プロジェクトのソースコードへのアクセス
トラッキングコードの形式
トラッキングコードは次のようになります: ZV_XXXXXXXXXX
ZV_で始まります- その後に 10 文字(文字と数字)が続きます
- 大文字小文字を区別します - 正確にコピーしてください
例: ZV_Q8U0GYD70WR

仕組み
Cloudflare Pages プロジェクトに functions フォルダを追加すると、Cloudflare は自動的にサーバーレス関数を作成します。Zenovay の API にリクエストをプロキシする関数を作成して、これらをブラウザに対してファーストパーティリクエストとして表示させます。
ブラウザ → yourdomain.pages.dev/api/_z/script.js ✅ (ファーストパーティ)
↓
Cloudflare Function
↓
api.zenovay.com/fp/script.js (サーバー間)
ステップ 1: Functions ディレクトリを作成
ファイルの場所は重要
functions フォルダはプロジェクトルートになければなりません。src/ の内部や public/ の内部ではありません。
正しい場所:
your-project/
├── functions/ ← ここです (プロジェクトルート)
│ └── api/
│ └── _z/
│ └── [[path]].ts
├── src/
├── public/
└── package.json
間違った場所:
- ❌
src/functions/api/_z/[[path]].ts- 関数は機能しません - ❌
public/functions/api/_z/[[path]].ts- 関数は機能しません
ディレクトリ構造を作成します:
# Functions ディレクトリ構造を作成する
mkdir -p functions/api/_z
# 正しい場所にいることを確認する
ls -la
# 以下が表示されるはずです: functions/ src/ public/ package.json などこれらのコマンドを実行した後、プロジェクト構造は次のようになります:
your-project/
├── functions/
│ └── api/
│ └── _z/
│ └── [[path]].ts ← 次に作成します
├── src/
├── public/
├── package.json
└── ...
ステップ 2: プロキシ関数を作成
ファイル名は重要です
ファイルは [[path]].ts (またはJavaScriptの場合は [[path]].js)という名前である必要があります:
- 2 つの開き括弧:
[[ - 単語
path - 2 つの閉じ括弧:
]] - ファイル拡張子:
.tsまたは.js
これは /api/_z/ の後のパスを処理する「キャッチオール」ルートを作成します。
TypeScript か JavaScript?
- プロジェクトが TypeScript を使用している場合は
.tsを使用してください - プロジェクトが JavaScript を使用している場合は
.jsを使用してください - どちらもまったく同じように機能します
不確実な場合は、まず .ts を試してください。ビルド中に TypeScript エラーが発生した場合は、代わりに .js に名前変更してください。
functions/api/_z/[[path]].ts ファイルを以下の内容で作成します:
/**
* Zenovay First-Party Proxy
* This function proxies tracking requests to make them first-party
*/
interface EventContext {
request: Request
params: { path?: string[] }
}
export async function onRequest(context: EventContext): Promise<Response> {
const { request, params } = context
// Build path from catch-all parameter
// [[path]] captures: script.js, e/CODE, settings/CODE, etc.
const path = (params.path || []).join('/')
const url = new URL(request.url)
const targetUrl = `https://api.zenovay.com/fp/${path}${url.search}`
// Handle CORS preflight requests
if (request.method === 'OPTIONS') {
return new Response(null, {
status: 204,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
},
})
}
try {
// Get the real client IP for accurate geolocation
const clientIP = request.headers.get('CF-Connecting-IP') || ''
// Forward request with real IP
const proxyHeaders = new Headers(request.headers)
proxyHeaders.set('X-Zenovay-Real-IP', clientIP)
proxyHeaders.delete('Host')
// Build the request
const requestInit: RequestInit = {
method: request.method,
headers: proxyHeaders,
}
// Include body for POST/PUT/PATCH requests
if (['POST', 'PUT', 'PATCH'].includes(request.method)) {
requestInit.body = await request.arrayBuffer()
}
// Forward to Zenovay
const response = await fetch(targetUrl, requestInit)
// Add CORS headers to response
const responseHeaders = new Headers(response.headers)
responseHeaders.set('Access-Control-Allow-Origin', '*')
return new Response(response.body, {
status: response.status,
headers: responseHeaders,
})
} catch (error) {
console.error('Proxy error:', error)
return new Response(JSON.stringify({ error: 'Proxy error' }), {
status: 502,
headers: { 'Content-Type': 'application/json' },
})
}
}JavaScript の代替
JavaScript を使用する場合は、functions/api/_z/[[path]].js を作成します:
/**
* Zenovay First-Party Proxy
* This function proxies tracking requests to make them first-party
*/
export async function onRequest(context) {
const { request, params } = context
// Build path from catch-all parameter
const path = (params.path || []).join('/')
const url = new URL(request.url)
const targetUrl = `https://api.zenovay.com/fp/${path}${url.search}`
// Handle CORS preflight requests
if (request.method === 'OPTIONS') {
return new Response(null, {
status: 204,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
},
})
}
try {
// Get the real client IP for accurate geolocation
const clientIP = request.headers.get('CF-Connecting-IP') || ''
// Forward request with real IP
const headers = new Headers(request.headers)
headers.set('X-Zenovay-Real-IP', clientIP)
headers.delete('Host')
// Forward to Zenovay
const response = await fetch(targetUrl, {
method: request.method,
headers: headers,
body: ['POST', 'PUT', 'PATCH'].includes(request.method)
? await request.arrayBuffer()
: undefined,
})
// Add CORS headers to response
const responseHeaders = new Headers(response.headers)
responseHeaders.set('Access-Control-Allow-Origin', '*')
return new Response(response.body, {
status: response.status,
headers: responseHeaders,
})
} catch (error) {
return new Response(JSON.stringify({ error: 'Proxy error' }), {
status: 502,
headers: { 'Content-Type': 'application/json' },
})
}
}ステップ 3: トラッキングスクリプトを追加
このスクリプトをウェブサイトの HTML に追加します。場所はフレームワークによって異なります:
<!-- Zenovay Analytics - First-Party Tracking -->
<script defer
data-tracking-code="YOUR_TRACKING_CODE"
src="/api/_z/script.js">
</script>YOUR_TRACKING_CODE を置き換えてください Zenovay ダッシュボードから実際のトラッキングコード(例: ZV_Q8U0GYD70WR)に置き換えてください。
フレームワーク固有の例
React / Next.js
export default function RootLayout({ children }) {
return (
<html lang="en">
<head>
<script
defer
data-tracking-code="YOUR_TRACKING_CODE"
src="/api/_z/script.js"
/>
</head>
<body>{children}</body>
</html>
)
}Vue / Nuxt
<!-- In app.vue -->
<script setup>
useHead({
script: [
{
src: '/api/_z/script.js',
defer: true,
'data-tracking-code': 'YOUR_TRACKING_CODE'
}
]
})
</script>Astro
---
const { title } = Astro.props;
---
<html lang="en">
<head>
<title>{title}</title>
<script defer data-tracking-code="YOUR_TRACKING_CODE" src="/api/_z/script.js"></script>
</head>
<body>
<slot />
</body>
</html>単純な HTML
<!DOCTYPE html>
<html>
<head>
<title>My Website</title>
<script defer data-tracking-code="YOUR_TRACKING_CODE" src="/api/_z/script.js"></script>
</head>
<body>
<!-- Your content -->
</body>
</html>ステップ 4: デプロイ
プロジェクトを Cloudflare Pages にデプロイします:
オプション A: Git を使用(推奨)
Git から自動デプロイメントがある場合:
git add .
git commit -m "Add Zenovay first-party tracking"
git pushCloudflare Pages は自動的にビルドとデプロイを行います。
オプション B: Wrangler CLI を使用
# プロジェクトを最初にビルドする
npm run build
# Cloudflare Pages にデプロイする
npx wrangler pages deploy ./dist --project-name=your-project-name./dist をビルド出力ディレクトリ(./out または ./build などの可能性があります)に置き換え、your-project-name を Cloudflare Pages プロジェクト名に置き換えてください。
ステップ 5: 動作確認
チェック 1: Cloudflare の Functions タブ
- Cloudflare ダッシュボード → Pages に進みます
- プロジェクトをクリックします
- Functions タブをクリックします
api/_z/[[path]]が一覧に表示されます
関数が見つかりません?
functions/フォルダがプロジェクトルート(src/の内部ではない)にあることを確認してください- ファイルが
[[path]].tsまたは[[path]].jsという名前であることを確認してください - デプロイメントが正常に完了したか確認してください
チェック 2: ブラウザのネットワークタブ
- デプロイされたサイトを開きます
- F12 (Mac では Cmd+Option+I)を押して DevTools を開きます
- Network タブをクリックします
- ページを更新します(Cmd+R または Ctrl+R)
- フィルターボックスで
script.jsと入力します /api/_z/script.jsを探します
表示される内容:
- ステータス: 200 ✅
- ドメイン: Pages ドメイン(例:
your-project.pages.dev) - レスポンス: JavaScript コード
チェック 3: Firefox ストリクトモード(最も重要!)
Firefox は最も厳密なトラッキング保護を備えています。Firefox で動作する場合は、どこでも動作します。
- Firefox ブラウザを開きます
- メニュー(☰)→ 設定 をクリックします
- 左サイドバーの プライバシーとセキュリティ をクリックします
- 「拡張トラッキング保護」の下で 厳密 を選択します
- ウェブサイトにアクセスします
- DevTools(F12)→ Network タブを開きます
- 更新して
/api/_z/script.jsがステータス 200 で読み込まれていることを確認します
チェック 4: Zenovay ダッシュボード
- app.zenovay.com に進み、ログインします
- ウェブサイトをクリックします
- デプロイされたサイトを別のタブにアクセスします
- 1~2 分以内に、訪問がダッシュボードに表示されます
最終チェックリスト
完了する前に、これらのすべてを確認してください:
-
functions/api/_z/[[path]].tsファイルがプロジェクトルートに存在する - Cloudflare Pages Functions タブに関数が表示される
- スクリプトが
/api/_z/script.jsでステータス 200 で読み込まれる -
data-tracking-code属性に正しいトラッキングコードが含まれている - 拡張トラッキング保護を厳密に設定した Firefox でテストされている
- Zenovay ダッシュボードに訪問が表示されている
トラブルシューティング
関数が 404 を返す
原因: 関数ファイルが間違った場所にあるか、名前が間違っています。
解決策:
- ファイルが 正確に
functions/api/_z/[[path]].tsにあることを確認しますfunctionsフォルダはプロジェクトルートにありますapi/_z/サブディレクトリが必要です[[path]].tsという名前で、二重括弧である必要があります
functionsフォルダがデプロイメントに含まれていることを確認します- Cloudflare ダッシュボードの Functions タブを確認します
関数が 500 を返す
原因: 関数コードにシンタックスエラーまたはランタイムエラーがあります。
解決策:
- Cloudflare のエラーの詳細については Functions ログを確認します:
- Pages プロジェクト → Functions → Logs に進みます
- すべてのコードが正しくコピーされたことを確認します
onRequestをエクスポートしていることを確認します(export defaultではありません)
ビルド中に TypeScript エラーが発生
原因: 型定義がありません。
解決策: オプション 1: Cloudflare Workers 型をインストールします:
npm install --save-dev @cloudflare/workers-typesオプション 2: 代わりに JavaScript バージョンを使用してください([[path]].js に名前変更します)
コンソールの CORS エラー
原因: CORS ヘッダーが正しく追加されていません。
解決策: 関数に以下の両方が含まれていることを確認してください:
- プリフライトリクエスト用の OPTIONS ハンドラー
- レスポンスに
responseHeaders.set('Access-Control-Allow-Origin', '*')を含める
ジオロケーションが間違っている
原因: クライアント IP が転送されていません。
解決策: 関数に以下が含まれていることを確認してください:
const clientIP = request.headers.get('CF-Connecting-IP') || ''
proxyHeaders.set('X-Zenovay-Real-IP', clientIP)
スクリプトが読み込まれるが、ダッシュボードにデータが表示されない
原因: トラッキングコードが一致しません。
解決策:
- DevTools コンソール(F12 → Console タブ)を開いてエラーを確認してください
data-tracking-codeが Zenovay ダッシュボード内の内容と正確に一致していることを確認してください(大文字小文字を区別します!)- ドメインが Zenovay に登録されていることを確認してください
次のステップ
- カスタムイベント - ユーザーインタラクションを追跡
- 訪問者識別 - 分析をユーザーにリンク
- トラブルシューティング - 問題に関するその他のヘルプ