メインコンテンツへスキップ
7分で読めます

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

トラッキングスクリプトカード。HTML、React、Next.js、ファーストパーティタブを表示しているスクリプトスニペット
ドメインの一般設定下のトラッキングスクリプトカード。ファーストパーティタブからコードをコピーしてください。

仕組み

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 - 関数は機能しません

ディレクトリ構造を作成します:

ターミナル - プロジェクトルートから実行Bash
# 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 ファイルを以下の内容で作成します:

functions/api/_z/[[path]].ts - このファイル全体をコピーしてくださいTypeScript
/**
* 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 を作成します:

functions/api/_z/[[path]].js - JavaScript バージョンJavaScript
/**
* 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 に追加します。場所はフレームワークによって異なります:

トラッキングスクリプト - HTML の <head> セクションに追加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

app/layout.tsx または _app.tsxTSX
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

app.vue または nuxt.config.tsVUE
<!-- In app.vue -->
<script setup>
useHead({
script: [
  {
    src: '/api/_z/script.js',
    defer: true,
    'data-tracking-code': 'YOUR_TRACKING_CODE'
  }
]
})
</script>

Astro

src/layouts/Layout.astroASTRO
---
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

index.htmlHTML
<!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 から自動デプロイメントがある場合:

ターミナルBash
git add .
git commit -m "Add Zenovay first-party tracking"
git push

Cloudflare Pages は自動的にビルドとデプロイを行います。

オプション B: Wrangler CLI を使用

ターミナルBash
# プロジェクトを最初にビルドする
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 タブ

  1. Cloudflare ダッシュボード → Pages に進みます
  2. プロジェクトをクリックします
  3. Functions タブをクリックします
  4. api/_z/[[path]] が一覧に表示されます

関数が見つかりません?

  • functions/ フォルダがプロジェクトルート(src/ の内部ではない)にあることを確認してください
  • ファイルが [[path]].ts または [[path]].js という名前であることを確認してください
  • デプロイメントが正常に完了したか確認してください

チェック 2: ブラウザのネットワークタブ

  1. デプロイされたサイトを開きます
  2. F12 (Mac では Cmd+Option+I)を押して DevTools を開きます
  3. Network タブをクリックします
  4. ページを更新します(Cmd+R または Ctrl+R)
  5. フィルターボックスで script.js と入力します
  6. /api/_z/script.js を探します

表示される内容:

  • ステータス: 200 ✅
  • ドメイン: Pages ドメイン(例: your-project.pages.dev
  • レスポンス: JavaScript コード

チェック 3: Firefox ストリクトモード(最も重要!)

Firefox は最も厳密なトラッキング保護を備えています。Firefox で動作する場合は、どこでも動作します。

  1. Firefox ブラウザを開きます
  2. メニュー(☰)→ 設定 をクリックします
  3. 左サイドバーの プライバシーとセキュリティ をクリックします
  4. 「拡張トラッキング保護」の下で 厳密 を選択します
  5. ウェブサイトにアクセスします
  6. DevTools(F12)→ Network タブを開きます
  7. 更新して /api/_z/script.js がステータス 200 で読み込まれていることを確認します

チェック 4: Zenovay ダッシュボード

  1. app.zenovay.com に進み、ログインします
  2. ウェブサイトをクリックします
  3. デプロイされたサイトを別のタブにアクセスします
  4. 1~2 分以内に、訪問がダッシュボードに表示されます

最終チェックリスト

完了する前に、これらのすべてを確認してください:

  • functions/api/_z/[[path]].ts ファイルがプロジェクトルートに存在する
  • Cloudflare Pages Functions タブに関数が表示される
  • スクリプトが /api/_z/script.js でステータス 200 で読み込まれる
  • data-tracking-code 属性に正しいトラッキングコードが含まれている
  • 拡張トラッキング保護を厳密に設定した Firefox でテストされている
  • Zenovay ダッシュボードに訪問が表示されている

トラブルシューティング

関数が 404 を返す

原因: 関数ファイルが間違った場所にあるか、名前が間違っています。

解決策:

  1. ファイルが 正確に functions/api/_z/[[path]].ts にあることを確認します
    • functions フォルダはプロジェクトルートにあります
    • api/_z/ サブディレクトリが必要です
    • [[path]].ts という名前で、二重括弧である必要があります
  2. functions フォルダがデプロイメントに含まれていることを確認します
  3. Cloudflare ダッシュボードの Functions タブを確認します

関数が 500 を返す

原因: 関数コードにシンタックスエラーまたはランタイムエラーがあります。

解決策:

  1. Cloudflare のエラーの詳細については Functions ログを確認します:
    • Pages プロジェクト → Functions → Logs に進みます
  2. すべてのコードが正しくコピーされたことを確認します
  3. onRequest をエクスポートしていることを確認します(export default ではありません)

ビルド中に TypeScript エラーが発生

原因: 型定義がありません。

解決策: オプション 1: Cloudflare Workers 型をインストールします:

ターミナルBash
npm install --save-dev @cloudflare/workers-types

オプション 2: 代わりに JavaScript バージョンを使用してください([[path]].js に名前変更します)

コンソールの CORS エラー

原因: CORS ヘッダーが正しく追加されていません。

解決策: 関数に以下の両方が含まれていることを確認してください:

  1. プリフライトリクエスト用の OPTIONS ハンドラー
  2. レスポンスに responseHeaders.set('Access-Control-Allow-Origin', '*') を含める

ジオロケーションが間違っている

原因: クライアント IP が転送されていません。

解決策: 関数に以下が含まれていることを確認してください:

const clientIP = request.headers.get('CF-Connecting-IP') || ''
proxyHeaders.set('X-Zenovay-Real-IP', clientIP)

スクリプトが読み込まれるが、ダッシュボードにデータが表示されない

原因: トラッキングコードが一致しません。

解決策:

  1. DevTools コンソール(F12 → Console タブ)を開いてエラーを確認してください
  2. data-tracking-code が Zenovay ダッシュボード内の内容と正確に一致していることを確認してください(大文字小文字を区別します!)
  3. ドメインが Zenovay に登録されていることを確認してください

次のステップ

このページは役に立ちましたか?