Safari ITP のトラッキング問題の修正

Safari ITP のトラッキング問題の修正

お知らせ:当社は、お客様により充実したサポート情報を迅速に提供するため、本ページのコンテンツは機械翻訳を用いて日本語に翻訳しています。正確かつ最新のサポート情報をご覧いただくには、本内容の英語版を参照してください。

SafariのIntelligent Tracking Prevention(ITP)は、JavaScriptで書き込まれたCookieを訪問者のブラウザーに保持できる期間を制限します。Zoho PageSenseでA/Bテスト、ヒートマップ、投票、ファネルを実施している場合、訪問者が早期に新規ユーザーとして扱われ、テスト結果が歪んだり、複数ステップのファネルが正しく機能しなくなったりする可能性があります。このガイドでは、ITPの仕組み、PageSenseのトラッキングへの影響、Cookie同期エンドポイントを使用して10分以内に解決する方法を説明します。

Safari ITPとは  

Appleは、サイトをまたいだユーザーのトラッキングを防止するためにITPを導入しました。バージョンアップのたびに制限が強化されています。

ITPのバージョン
機能

ITP 2.1
JavaScript(document.cookie)で書き込まれたCookieは、7日後に期限切れになります
ITP 2.2
訪問者が装飾されたリンク(トラッキングドメイン由来のクエリー文字列やフラグメントを含むURL)からアクセスした場合、JavaScriptのCookieは24時間後に期限切れになります

ITP 2.3
24時間ルールがWebサイトのCookieにも適用されます。また、Cookie以外のローカルストレージも、7日間使用されないと期限切れになります

装飾されたリンクとは、Safariによってサイト横断トラッカーに分類されたドメインから送信される、クエリー文字列またはフラグメント(例:?utm_source=newsletter#section)を含むURLです。
ITPが有効な環境:iOS 12.2以降、iPadOS、macOS Mojave/High Sierra/Catalina以降のSafari。

ITPがZoho PageSenseに与える影響  

PageSenseは、訪問者に表示されたパターン、ファネル内の位置、セッションの進捗状況などのトラッキングデータを、ブラウザーのCookieとlocalStorageに保存します。ITPによって保存期間が短縮されると、次の問題が発生する可能性があります。
  1. 訪問者がテストに再度振り分けられます。再訪問者のCookieが期限切れになっていると、PageSenseはその訪問者を新規訪問者として扱います。以前とは異なるパターンに割り当てられる可能性があるため、体験に一貫性がなくなり、重複データによってテスト結果の精度が低下します。
  2. ファネルが途中で中断します。コンバージョンファネルが7日間を超える場合(装飾されたリンクからの訪問者は24時間を超える場合)、PageSenseは訪問者の進捗状況を追跡できなくなります。それ以前のステップを関連付けていたトラッキングデータが期限切れになるため、8日目にコンバージョンした訪問者は集計されません。
  3. ユニーク訪問者数が水増しされます。Cookieの期限切れ後に同じユーザーが再訪問すると、新しいユニーク訪問者として登録されます。テスト期間全体では、サンプルサイズやコンバージョン率が大幅に歪む可能性があります。
  4. アンケートの途中経過が失われます。訪問者がlocalStorageの保存期間である7日以内にPageSenseのアンケートを完了しなかった場合、回答内容が失われます。また、Cookieではアンケートを開始済みと識別されたままになるため、その訪問者にアンケートが再表示されることもありません。

Notesメモ:CookieとlocalStorageの期限切れの問題が発生するのはSafariのみです。Chrome、Firefox、Edgeには影響しません。

サーバーSet-CookieHTTPレスポンスヘッダーを使用して設定したCookieには、ITPの有効期限の上限が適用されません。解決方法は簡単です。ブラウザーの要求からPageSenseのCookieを読み取り、有効期間の長いサーバー設定Cookieとして再発行する軽量のエンドポイントを、ご利用のサーバーでホストします。
PageSenseのトラッカーは、Safariでこのエンドポイントを自動的に呼び出します(訪問者1人につき1時間に最大1回)。エンドポイントの場所を指定するだけで利用できます。
Zohoにデータが保存または送信されることはありません。エンドポイントは、PageSenseの既存のCookie値を、有効期限を延長した状態で訪問者のブラウザーに返すだけです。すべての処理はお客さまのサーバー上で実行されます。

設定

手順1:同期エンドポイントのデプロイ  
以下のコードスニペットのいずれかを、Webサイトと同じドメイン(例:https://yoursite.com/pagesense-sync)でホストします。
デプロイする前に、スニペット内のCOOKIE_DOMAINの値を、先頭にドットを付けた登録可能ドメインに変更します(例:.yoursite.com)。サイトがapp.yoursite.comにある場合も、サブドメイン間でCookieにアクセスできるよう、ドメインには.yoursite.comを指定します。
Notes
ドメイン値に関するメモ:以下のすべてのスニペットで、.example.comをお客さまの登録可能ドメインに置き換えてください。たとえば、Webサイトがstore.acmecorp.comの場合は、.acmecorp.comを使用します。正しい値がわからない場合は、Zoho PageSenseサポートにお問い合わせください。
Python(Flask)
  1. python
  2. '''
  3. PageSenseのCookie同期エンドポイント(Safari ITP対策)— Python/Flask。
  4. PageSenseのファーストパーティCookieをSet-Cookieで再発行し、Safariで
  5. 本来の有効期間が維持されるようにします。サイトと同じドメインでホストしてください。

  6. from pagesense_sync import pagesense_sync_blueprint
  7. app.register_blueprint(pagesense_sync_blueprint)
  8. '''

  9. fromflask importBlueprint,request,make_response

  10. # --- 設定:先頭にドットを付けた登録可能なドメインに置き換えてください ---
  11. # 例:store.acmecorp.com上のサイトの場合は「.acmecorp.com」
  12. COOKIE_DOMAIN = '.example.com'

  13. MAX_AGE_SECONDS = 34560000  # 400日

  14. pagesense_sync_blueprint = Blueprint('pagesense_sync',__name__)


  15. @pagesense_sync_blueprint.route('/pagesense-sync', methods=['GET'])
  16. def pagesense_sync():
  17. is_https = (
  18. request.is_secure
  19.         orrequest.headers.get('X-Forwarded-Proto', '')== 'https'
  20.     )

  21. response = make_response('', 204)
  22. response.headers['Cache-Control']= 'no-store'

  23.     forname,value inrequest.cookies.items():
  24.         ifname.startswith('zab') orname.startswith('zps'):
  25. response.set_cookie(
  26. name,
  27. value,
  28.                 max_age=MAX_AGE_SECONDS,
  29.                 path='/',
  30.                 domain=COOKIE_DOMAIN,
  31.                 secure=is_https,
  32.                 httponly=False,  # トラッカーがこれらのCookieを読み取れる必要があります
  33.                 samesite='None' ifis_https else 'Lax',
  34.             )

  35.     returnresponse

Node.js(Express)
  1. javascript
  2. /**
  3. * PageSenseのCookie同期エンドポイント(Safari ITP対策)— Node.js/Express。
  4. * Set-Cookieを使用してPageSenseのファーストパーティCookieを再発行し、Safariで
  5. * 完全な有効期間が維持されるようにします。サイトと同じドメインにマウントしてください。
  6. *
  7. * const pagesenseSync = require('./pagesense-sync.node.js');
  8. * app.get('/pagesense-sync', pagesenseSync);
  9. */

  10. // --- 設定:先頭にドットを付け、登録可能なドメインに置き換えてください ---
  11. // 例:store.acmecorp.com上のサイトの場合は'.acmecorp.com'
  12. constCOOKIE_DOMAIN = '.example.com';

  13. constMAX_AGE_SECONDS = 34560000; // 400日

  14. module.exports= function pagesenseSync(req, res) {
  15.     constisHttps = req.secure || req.headers['x-forwarded-proto']=== 'https';
  16.     constraw = req.headers.cookie || '';

  17.     constsetCookies = raw.split(';').reduce((acc, pair) => {
  18.         constidx = pair.indexOf('=');
  19.         if (idx < 0) returnacc;
  20.         constname = pair.slice(0,idx).trim();
  21.         constvalue = pair.slice(idx + 1).trim();
  22.         if (name.indexOf('zab')=== 0|| name.indexOf('zps')=== 0) {
  23. acc.push(
  24. name + '='+ value +
  25.                 '; Max-Age='+ MAX_AGE_SECONDS +
  26.                 '; Path=/'+
  27.                 '; Domain='+ COOKIE_DOMAIN +
  28.                 (isHttps ? '; Secure; SameSite=None': '; SameSite=Lax')
  29.                 // 意図的にHttpOnlyにしていません。トラッカーがこれらのクッキーを読み取る必要があるためです
  30.             );
  31.         }
  32.         returnacc;
  33.     }, []);

  34.     if (setCookies.length) {
  35. res.setHeader('Set-Cookie',setCookies);
  36.     }
  37. res.setHeader('Cache-Control', 'no-store');
  38. res.status(204).end();
  39. };
Java(Servlet)
  1. java
  2. import java.io.IOException;
  3. import javax.servlet.annotation.WebServlet;
  4. import javax.servlet.http.Cookie;
  5. import javax.servlet.http.HttpServlet;
  6. import javax.servlet.http.HttpServletRequest;
  7. import javax.servlet.http.HttpServletResponse;

  8. /**
  9. * PageSenseのCookie同期エンドポイント(Safari ITP対策)— Java Servlet。
  10. * Set-Cookieを使用してPageSenseのファーストパーティCookieを再発行し、Safariで
  11. * 有効期間全体が維持されるようにします。サイトと同じドメインにデプロイしてください。
  12. */
  13. @WebServlet('/pagesense-sync')
  14. public class PageSenseSyncServlet extends HttpServlet {

  15.     // --- 設定:先頭にドットを付けた登録可能なドメインに置き換えてください ---
  16.     // 例:store.acmecorp.comのサイトの場合は'.acmecorp.com'
  17.     private static final StringCOOKIE_DOMAIN = '.example.com';

  18.     private static final intMAX_AGE_SECONDS = 34560000; // 400日

  19.     @Override
  20.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
  21.         booleanisHttps = request.isSecure()|| 'https'.equalsIgnoreCase(request.getHeader('X-Forwarded-Proto'));

  22.         Cookie[]cookies = request.getCookies();
  23.         if (cookies != null) {
  24.             for (Cookiecookie :cookies) {
  25.                 Stringname = cookie.getName();
  26.                 if (name.startsWith('zab')|| name.startsWith('zps')) {
  27.                     // SameSiteを設定するため、ヘッダーを手動で構築
  28.                     //(javax.servletのCookieはSameSiteをサポートしていません)
  29.                     StringBuilderheader = new StringBuilder();
  30. header.append(name).append('=').append(cookie.getValue())
  31.                           .append('; Max-Age=').append(MAX_AGE_SECONDS)
  32.                           .append('; Path=/')
  33.                           .append('; Domain=').append(COOKIE_DOMAIN);
  34.                     if (isHttps) {
  35. header.append('; Secure; SameSite=None');
  36.                     } else {
  37. header.append('; SameSite=Lax');
  38.                     }
  39.                     // 意図的にHttpOnlyにしない — トラッカーがこれらのCookieを読み取る必要がある
  40. response.addHeader('Set-Cookie',header.toString());
  41.                 }
  42.             }
  43.         }

  44. response.setHeader('Cache-Control', 'no-store');
  45. response.setStatus(HttpServletResponse.SC_NO_CONTENT);
  46.     }
  47. }
.NET (ASP.NET Core)
  1. csharp
  2. using Microsoft.AspNetCore.Http;
  3. using Microsoft.AspNetCore.Mvc;
  4. using System;

  5. /// <summary>
  6. /// PageSenseのCookie同期エンドポイント(Safari ITP対策)— ASP.NET Core。
  7. /// Set-Cookieを使用してPageSenseのファーストパーティーCookieを再発行し、Safariが
  8. /// Cookieの有効期間全体を維持できるようにします。サイトと同じドメインでホストしてください。
  9. /// </summary>
  10. [ApiController]
  11. public class PageSenseSyncController : ControllerBase
  12. {
  13.     // --- 設定:先頭にドットを付けた登録可能なドメインに置き換えてください ---
  14.     // 例:「.acmecorp.com」(store.acmecorp.com上のサイトの場合)
  15.     private const stringCookieDomain = '.example.com';

  16.     private const intMaxAgeSeconds = 34560000; // 400日

  17.     [HttpGet('/pagesense-sync')]
  18.     public IActionResult Sync()
  19.     {
  20.         boolisHttps = Request.IsHttps
  21. || string.Equals(Request.Headers['X-Forwarded-Proto'], 'https',
  22. StringComparison.OrdinalIgnoreCase);

  23.         foreach (varcookie inRequest.Cookies)
  24.         {
  25.             if (cookie.Key.StartsWith('zab',StringComparison.Ordinal)
  26. || cookie.Key.StartsWith('zps',StringComparison.Ordinal))
  27.             {
  28. Response.Cookies.Append(cookie.Key,cookie.Value, new CookieOptions
  29.                 {
  30. MaxAge = TimeSpan.FromSeconds(MaxAgeSeconds),
  31. Path = '/',
  32. Domain = CookieDomain,
  33. Secure = isHttps,
  34. HttpOnly = false, // トラッカーがこれらのCookieを読み取る必要があります
  35. SameSite = isHttps ? SameSiteMode.None : SameSiteMode.Lax
  36.                 });
  37.             }
  38.         }

  39. Response.Headers['Cache-Control']= 'no-store';
  40.         return NoContent();
  41.     }
  42. }
手順2:PageSenseにエンドポイントの場所を指定  
次の行を、サイトの<head>内にあるPageSense SmartCodeより前に追加します。
  1. html
  2. <script>window.zpsITPSyncUrl = '/pagesense-sync';</script>
  3. <!-- 以下にPageSense SmartCodeを記述 -->
以上で完了です。PageSenseは、SafariおよびiOSのブラウザーで、訪問者1人につき1時間に最大1回、自動的にエンドポイントを呼び出します。

仕組み  

エンドポイントは、ブラウザーが各要求ですでに送信しているPageSenseのCookie(zabまたはzpsで始まるCookie)を読み取り、有効期限を400日後に設定したSet-Cookieレスポンスヘッダーを使用して再発行します。サーバー側で設定されたCookieには、ITPによる7日間の上限は適用されません。
エンドポイントは、Cache-Control: no-storeを指定して204 No Contentを返すため、キャッシュされることなく、常に新たに実行されます。CookieにはHttpOnly: falseが設定されます。これは、PageSenseのトラッカーがJavaScriptからCookieを読み取る必要があるため、意図的な設定です。

エンドポイントでできること/できないこと  

Cookieの有効期間をITPの7日間の上限を超えて延長

再訪問時のA/Bテストのパターンの一貫性を確保

セッションをまたぐ複数ステップのファネル追跡を修正

Safariによるユニーク訪問者数の過大計上を修正

同じ登録可能ドメイン内のサブドメイン間で動作

クロスドメイン追跡には非対応(Safariによって完全にブロックされます)


スプリットURLテストにおけるクロスドメイン追跡の問題の解決

異なるドメイン間でスプリットURLテストを実行すると、ブラウザーによってクロスドメイン追跡に必要なCookieがブロックされる場合があります。その結果、パターンページへのリダイレクト後にPageSenseが訪問者を認識できず、テストの追跡が不完全または不正確になる可能性があります。これに対応するため、PageSenseはCookieだけに依存せず、必要なテスト情報を一時的にパターンURL経由で渡します。これにより、ブラウザーのプライバシー制限がクロスドメイン追跡に影響する場合でも、訪問者を正しく追跡できます。
パターンページが情報を読み取ると、PageSenseはページを再読み込みせずに、ブラウザーのアドレスバーから一時的な追跡パラメーターを自動的に削除します。訪問者には簡潔なURLが表示されたまま、テストは正確に追跡されます。
例:次のページを使用してスプリットURLテストを実行するとします。
パターンページ - https://www.newsite.com/pricing
訪問者が元のページにアクセスすると、PageSenseは訪問者をパターンに割り当て、一時的に次のURLへリダイレクトします。
各パラメーターの意味は次のとおりです。
  • ps_expはテストを識別します。
  • ps_varは割り当てられたパターンを識別します。
  • ps_visitorは訪問者を識別します。
パターンページがこの情報を受信すると、PageSenseは一時的なパラメーターを削除し、訪問者には次のURLが表示されます。

仕組み  
  1. 訪問者が元のページにアクセスします。
  2. PageSenseが訪問者をパターンに割り当てます。
  3. 訪問者は、一時的なトラッキングパラメーターが付加されたパターンページにリダイレクトされます。
  4. パターンページが情報を読み取り、訪問者のトラッキングを継続します。
  5. PageSenseは、ページを再読み込みせずにURLから一時的なパラメーターを削除します。
メモ:この方法により、ブラウザーのプライバシー設定でドメイン間Cookieが制限されている場合でも、異なるドメインにまたがるスプリットURLテストで安定したトラッキングが可能になります。

既知の制限:アンケートと投票の回答状況  

Cookie同期エンドポイントはCookieベースのトラッキングには対応できますが、localStorageには対応できません。訪問者がPageSenseのアンケートや投票への回答途中で、7日以内に完了しなかった場合、回答状況はlocalStorageに保存されますが、ITPによって期限切れになる可能性があります。
この場合、訪問者のCookieはサーバーによって設定されて長期間保持されるため、アンケートがすでに表示されたことを引き続き識別でき、PageSenseが再度表示することはありません。ただし、回答途中の内容は失われます。現在、この制限を回避する方法はありません。これはSafariによって課されるlocalStorageの制限であり、Cookieの処理方法にかかわらず適用されます。

よくある質問  

1. これらのCookieは本当に400日間保持されますか?
Cookieは、Max-Age=34560000(ブラウザーで許可される上限の400日)を指定して発行されます。ただし、PageSenseでは独自の有効期限が管理されます。各Cookieの設定上の有効期間は、メタデータCookie(zpsCookieMeta)に保存されます。PageSenseはこの情報を読み取り、設定された有効期限を過ぎたCookieを存在しないものとして扱い、クライアント側で削除します。そのため、サーバー側の400日という有効期限は上限であり、データが実際に保持される期間を保証するものではありません。

2. このエンドポイントをホストすることで、セキュリティ上のリスクは生じますか?
いいえ。このエンドポイントは、訪問者のブラウザーにすでに保持されているCookieの値を再送信するだけです。情報が保存または記録されたり、Zohoに転送されたりすることはありません。同期スクリプトはすべてお客さま自身のサーバー上で実行され、Cookieが第三者に送信されることはありません。

3. Safari以外のブラウザーにも影響しますか?
いいえ。PageSenseのトラッカーが同期エンドポイントを呼び出すのは、ITPが有効なSafariおよびiOSブラウザーのみです。Chrome、Firefox、Edgeには影響しません。

4. サイトが複数のドメインにまたがっている場合でも利用できますか?
いいえ。Cookieのドメインは、PageSenseがインストールされているサイトの登録可能なドメインと一致している必要があります。完全に異なるドメイン間(例:siteA.comsiteB.com)のトラッキングはSafariではサポートされておらず、この方法では対応できません。

5. パラメーターが付加されていないリンクから訪問者がアクセスした場合はどうなりますか?
追加の対応は必要ありません。訪問者のURLにクエリー文字列やフラグメントが含まれていない場合、ITP 2.2の24時間という上限は適用されません。PageSenseに組み込まれているlocalStorageへのフォールバックにより、通常の7日間の有効期間に自動的に対応します。同期エンドポイントは主に、UTMパラメーターやその他のクエリー文字列を含むキャンペーンリンクからアクセスする訪問者に有効です。






このヘルプは、各手順をわかりやすく進められるように構成されています。さらにサポートが必要な場合やご不明な点がある場合は、support@zohopagesense.com - までお気軽にお問い合わせください。いつでもサポートいたします。