Visitor ID¶
Visitor ID は、未ログインまたはユーザーを確実に識別できないシナリオで、ブラウザ向けに安定した匿名識別子を生成します。
Guance Browser RUM SDK は、この値をルールに一致する XHR および Fetch リクエストヘッダーに注入し、API ゲートウェイが訪問者単位でレート制限を適用できるようにします。また、現在の値を RUM イベントの context.visitor_id に書き込み、関連分析に使用します。
Visitor ID は、レート制限のバケット化とオブザーバビリティの関連キーとしてのみ使用できます。認証、テナント分離、課金、監査には使用できません。
バージョン要件:RUM SDK 3.3.15 以降。
Visitor ID を有効にする¶
datafluxRum.init() で visitorId を設定します:
datafluxRum.init({
applicationId: "<APPLICATION_ID>",
site: "<PUBLIC_OPENWAY_URL>",
clientToken: "<CLIENT_TOKEN>",
visitorId: {
enabled: true,
header: "x-rum-visitor-id",
match: [
"https://api.example.com/",
/^https:\/\/gateway\.example\.com\//,
function (url) {
return url.includes("/security/")
}
],
ttlHours: 24
}
})
| パラメータ | 型 | 必須 | デフォルト値 | 説明 |
|---|---|---|---|---|
enabled |
Boolean | いいえ | false |
Visitor ID を有効にするかどうか。明示的に true に設定しない限り、識別子は生成されず、リクエストヘッダーも注入されません。 |
header |
String | 有効にする場合は必須 | なし | 注入するカスタムリクエストヘッダー名。有効な小文字の書き込み可能なリクエストヘッダーである必要があります。認証、CSRF、署名、分散型トレーシングのリクエストヘッダー、または SDK リソース関連ヘッダー x-rum-resource-id は使用できません。 |
match |
Array | 有効にする場合は必須 | なし | 空でない URL マッチングリスト。String、RegExp、Function をサポートします。いずれかが一致すると、リクエストヘッダーが注入されます。 |
ttlHours |
Number | いいえ | 24 |
Visitor ID の有効時間(単位:時間)。0 より大きい必要があります。有効期限が切れると、次回使用時にローテーションされます。スライディングによる有効期限延長は行われません。 |
リクエストマッチングルール¶
match 内の各タイプのルールは、次のようにマッチングされます:
- String:完全な URL の接頭辞と一致し、同一オリジン(プロトコル、ドメイン、ポート)に属している必要があります。たとえば、
https://api.example.comはhttps://api.example.com.evil.test/には一致しません; - RegExp:完全な URL に対して正規表現マッチングを実行します;
- Function:完全な URL を受け取り、Boolean を返します。
マッチング関数によってスローされた例外は SDK で分離され、そのルールは不一致として処理されます。ビジネスリクエストが中断されることはありません。SDK 自身のデータ送信リクエストには Visitor ID ヘッダーが注入されません。
ブラウザ SDK は、初期化後に開始された XHR および Fetch のみを処理します。ページナビゲーション、画像、フォーム送信、sendBeacon、WebSocket、Worker 内のリクエストは、この機能の対象外です。
識別子のライフサイクル¶
同じブラウザでは、Visitor ID の有効期間中は同じ識別子が再利用され、リクエストごとに新しい値が生成されることはありません。SDK は識別子をまず localStorage に保存します。使用できない場合は、sessionStorage へ、さらに現在のページメモリへと順にフォールバックします:
| ストレージレベル | 再利用範囲 |
|---|---|
localStorage |
同一オリジンにおける後続のページアクセスとタブ |
sessionStorage |
現在のタブのセッション |
| ページメモリ | 現在のページのライフサイクル |
次の場合、新しい値が生成されます:
- 現在の Visitor ID が
ttlHoursを超えている場合 - ビジネス側が
resetVisitorId()を明示的に呼び出した場合 - ブラウザのストレージがクリアされる、またはアクセスできなくなり、元のメモリ状態が終了した場合
複数レベルの有効な保存レコードが存在する場合、SDK は最新のレコードを選択します。ローテーション後、リフレッシュしても古いフォールバックレコードは復元されません。
ローカルストレージへの保存に成功した場合は永続的な識別子が生成され、セッションストレージまたはメモリにフォールバックした場合はセッション識別子が生成されます。ビジネス側は識別子の形式を解析したり、依存したりしないでください。
リクエストヘッダーと RUM データ¶
リクエストヘッダーは、match に一致する XHR および Fetch にのみ注入されます。機能を有効にすると、現在の Visitor ID が context.visitor_id として RUM イベントに書き込まれます。Visitor ID は、RUM セッション、ユーザー識別子、Trace とは相互に独立しています:
sessionSampleRateまたはtracingSampleRateは、Visitor ID ヘッダーを注入するかどうかを決定しません- Visitor ID は、RUM セッションを作成したり、強制的にサンプリングしたりしません
- サンプリングされなかったセッションは RUM データを送信しませんが、一致したビジネスリクエストには Visitor ID ヘッダーが引き続き付与されます
resetVisitorId()は、RUM セッション、ユーザー識別子、Trace を変更しません
ビジネス側が visitorId.header と同じ名前のリクエストヘッダーをすでに設定している場合、SDK は現在の Visitor ID でその値を上書きし、コンソールに警告を出力します。このリクエストヘッダーは SDK のみが管理する必要があります。match に一致しないリクエストは、injectTraceHeader が返す同名のヘッダーを含め、元のリクエストヘッダーを保持します。
同一オリジンの iframe によって作成され、現在のページの fetch() に渡されて送信される Request は、元のリクエストメソッド、リクエストボディ、ビジネスリクエストヘッダーを保持します。同じ XHR の send() がパラメータエラーにより同期的に失敗した後に再送信される場合、Visitor ID が重複して追加されることはありません。すでにそのリクエストに注入された識別子は、リトライ中のローテーションによって変更されることはありません。
グローバル、View、イベントのカスタムコンテキスト内の visitor_id は、SDK が管理する値を上書きしません。送信前にコンテキストを削除または調整する必要がある場合は、引き続き beforeSend を使用できます。
初期化前、またはリモート設定の待機中にバッファリングされたカスタムイベントには、SDK 起動後に Visitor ID が補完されます。すでに SDK の識別子スナップショットを持つイベントは、そのスナップショットを引き続き使用し、イベント発生時点の他のコンテキストは上書きされません。
リクエスト送信後、Resource が完了する前に Visitor ID がローテーションされた場合、その Resource の context.visitor_id は、リクエストヘッダーで実際に使用された古い値を保持します。ローテーション後の新しいリクエストと、その他の後続の RUM イベントは新しい値を使用します。
手動ローテーション¶
ユーザーがログアウトまたはアカウント切り替えを確認した後、Visitor ID を手動でローテーションできます:
呼び出し後、新たに開始された一致リクエストと後続の RUM イベントは新しい値を使用します。401、未認証リクエスト、または繰り返しトリガーされる可能性のある失敗分岐では呼び出さないでください。呼び出すと、バケットが継続的に切り替わり、レート制限を回避する経路になります。
CORS とセキュリティ境界¶
カスタムリクエストヘッダーを使用すると、クロスオリジンリクエストで CORS プリフライトがトリガーされます。API サービスは、Access-Control-Allow-Headers で visitorId.header を許可する必要があります。また、match は信頼できる API のみを対象とする必要があります。
Visitor ID はクライアント側で生成されるため、ユーザーは偽造、置換、削除が可能です。ゲートウェイは、この値だけを根拠に権限を付与することはできません。レート制限ポリシーは、リクエストヘッダーが欠落しているリクエストに対して、IP、セッション、その他のビジネスディメンションに基づくフォールバックルールも提供し、ペナルティ時間を短く保つことで、攻撃者が他の訪問者 ID を不正に使用して誤ってブロックする影響を抑える必要があります。
Cloudflare レート制限の例¶
以下の Cloudflare Advanced Rate Limiting テンプレートには 2 つのルールが含まれています。Visitor ID ヘッダーがある場合は訪問者識別子ごとにカウントし、リクエストヘッダーがない場合は送信元 IP でフォールバックします。これはオプションのゲートウェイ導入例であり、SDK のランタイム依存ではありません。Cloudflare を使用していないビジネスでは無視できます。
導入前に、リクエストパス、リクエストヘッダー名、しきい値、ペナルティ時間を必ず変更してください。ルールはデフォルトで無効になっています。まず作成して読み戻し、式、カウントディメンション、しきい値を確認し、問題がなければ有効にしてください。
Cloudflare Advanced Rate Limiting テンプレート
{
"name": "rum_visitor_id_rate_limit",
"description": "Rate limit matched API requests by the RUM Visitor ID header, with an IP fallback when the header is missing.",
"kind": "zone",
"phase": "http_ratelimit",
"rules": [
{
"description": "RUM Visitor ID API rate limit",
"expression": "(starts_with(http.request.uri.path, \"/api/\") and len(http.request.headers[\"x-rum-visitor-id\"]) > 0)",
"action": "block",
"ratelimit": {
"characteristics": [
"cf.colo.id",
"http.request.headers[\"x-rum-visitor-id\"]"
],
"period": 60,
"requests_per_period": 100,
"mitigation_timeout": 600,
"counting_expression": "(starts_with(http.request.uri.path, \"/api/\") and len(http.request.headers[\"x-rum-visitor-id\"]) > 0)",
"requests_to_origin": true
},
"enabled": false
},
{
"description": "Missing RUM Visitor ID IP fallback",
"expression": "(starts_with(http.request.uri.path, \"/api/\") and len(http.request.headers[\"x-rum-visitor-id\"]) eq 0)",
"action": "block",
"ratelimit": {
"characteristics": ["cf.colo.id", "ip.src"],
"period": 60,
"requests_per_period": 30,
"mitigation_timeout": 600,
"counting_expression": "(starts_with(http.request.uri.path, \"/api/\") and len(http.request.headers[\"x-rum-visitor-id\"]) eq 0)",
"requests_to_origin": true
},
"enabled": false
}
]
}
Cloudflare のルール形式については、API によるレート制限ルールの作成 および レート制限パラメータの説明 を参照してください。