概要
INFO:Web Attributionはエンタープライズ向け機能です。アカウントでこの機能を有効にするには、カスタマーサクセスマネージャーにお問い合わせください。
このガイドでは、Google Tag Manager(GTM)を使用してSingular Web SDKを実装する方法を説明します。この方法は、ウェブサイトコードに直接アクセスできないチームや、GTMを通じてトラッキングを管理したい場合に最適です。
重要!同一サイトでGTMとネイティブJavaScriptの両方を実装しないでください。重複トラッキングやイベントカウントの過大計上を防ぐため、いずれか一方の方法のみを選択してください。Singularはイベントの重複排除を自動で行いません。
- ネイティブJavaScriptとGoogle Tag Managerの両方の方法を実装しないでください。重複トラッキングを避けるため、いずれか一方のみを選択してください。
- Singular Web SDKはユーザーのブラウザ内でクライアントサイドに動作するよう設計されています。正常に機能するには、localStorageや Document Object Model(DOM)などのブラウザ機能へのアクセスが必要です。サーバーサイド(例:Next.js SSRやnode.js経由)でSDKを実行しようとしないでください。サーバー環境ではブラウザAPIへのアクセスが提供されないため、トラッキングが失敗します。
前提条件
開始前に、以下が用意されていることを確認してください:
-
SDKキーとSDKシークレット:
- 確認方法:Singularアカウントにログインし、[Developer Tools] > [SDK Integration] > [SDK Keys] に移動してください。
-
プロダクトID:
-
概要:ウェブサイト固有の名前(理想的には逆DNS形式、例:
com.website-name)。 - 重要性:このIDはウェブサイトをSingular内のアプリとして関連付け、Singularのアプリページに記載されているWebアプリのbundleIDと一致させる必要があります。
-
概要:ウェブサイト固有の名前(理想的には逆DNS形式、例:
- Google Tag Managerがサイトに設定済みであること。
- GTM内でウェブサイトのタグ、トリガー、変数を編集する権限が必要です。カスタマイズ内容によっては、カスタムタグ の作成方法やタグシーケンスの設定方法を知る必要がある場合があります。
- Google Tag Manager への変更を公開する権限がない場合は、テスト後に誰かに変更を公開してもらうよう依頼する必要があります。
- GTM でのコンテナおよびタグのプレビューとデバッグの方法に関する知識。
- 追跡したいイベントの一覧。アイデアについては、当社の「Singular標準イベント:完全リスト」および「業種別推奨イベント」をご覧ください。
実装手順
ステップ1: Singular Web TrackingテンプレートをGTMコンテナに追加
- Google タグマネージャーアカウントにログインし、ウェブサイトのコンテナを選択します。
- [タグ] > [新規] に移動します。
- タグに「Singular Init Tag」という名前を付けます
- タグ設定ボックスをクリックしてタグ設定を開始します。
- タグの種類を選択: 「コミュニティテンプレートギャラリーでさらにタグの種類を探る」を選択します。
- 「Singular」を検索し、「Singular Web Tracking」を選択します。「ワークスペースに追加」ボタンをクリックします。
ステップ2: SDKの初期化
-
以下の内容でフォームフィールドを入力してください:
- トラッキングタイプを「初期化」に設定
- Api Keyフィールドに実際のSDKキーを入力
- シークレット欄に実際のSDKシークレットを入力 実際のプロダクトIDを入力
-
実際のプロダクトIDを入力してください。 例:
com.website-nameSingularプラットフォームの「Apps」ページにある BundleID 値と一致している必要があります。ヒント!テスト用に専用のプロダクトIDを使用してください
com.website-name.dev本番環境へプッシュする前に更新してください。 これにより、Singularレポートにおいてテストデータと本番アプリのデータが分離されます。 -
オプション:
- ログレベル: SDKの デバッグ ログをコンソールに出力する設定 。デフォルトはなし。
- イベント重複排除
- グローバルプロパティの設定
- スマートバナーの有効化(エンタープライズ版のみ)
- カスタマーユーザーIDの設定
- セッションタイムアウト: SDKが新規セッションを作成するまでの ユーザーの非アクティブ状態の最大時間 。 Singularはユーザーセッションを送信し、ユーザーリテンションの計算と 再エンゲージメントアトリビューションを有効化します。 デフォルト値は30分です。
- クロスサブドメイントラッキング
- トリガー設定を選択し、このタグを機能させるトリガーを設定します。
- 「新規」を選択し、トリガー名を「Singular Init Trigger」と命名します。
- トリガー設定をクリックし、「ページビュー - ウィンドウ読み込み」を選択 「保存」をクリック。
- 再度「保存」をクリックしてタグを保存します。
-
タグページから「プレビュー」をクリックし、
Singular
初期化タグがトリガーされることをテストします。
成功!プレビューコンソールの「発火したタグ」セクションに「Singular Init Tag」が表示された場合、初期化タグの設定は正常に完了しています。
重要! SPA(シングルページアプリケーション)の場合 、 異なるページに遷移するたびに ページ訪問トラックタイプをトリガーする必要があります。 最初に読み込まれたページではページ訪問を呼び出さないでください。 初期化タグが既にページ訪問を報告しているためです。
ソリューション概要
- カスタムJavaScript変数を使用して、最初のページ読み込みかどうかを検出します。
-
2つのタグを設定します:
- 「シングル初期化タグ」(追跡タイプ = 初期化) :最初のページ読み込み時のみ発火
- 「シングルページ訪問タグ」(追跡タイプ = ページ 訪問)を、履歴変更トリガーを使用して、 すべてのルート変更時(初回読み込みを除く)に 発火させる。
- SPAがルート変更時に履歴イベントをdataLayerに確実にプッシュするように設定する。
ステップ3: イベントのトラッキング
SDKを初期化した後、ユーザーがウェブサイト上で重要なアクションを実行した際にカスタムイベントを追跡できます。
重要!Singularは重複イベントをブロックしません! ページ再読み込みや重複に対する保護措置は開発者の責任です。誤った収益データを防ぐため、特に収益イベント向けに重複排除手法の導入を推奨します。詳細は下記「ステップ5:重複イベントの防止」の例を参照してください。
基本イベント追跡
単純なイベントを追跡するか、有効なJSONを使用してカスタム属性を追加し、 イベントに関する詳細なコンテキストを提供します:
-
Singular Web Trackingテンプレートを使用して、カスタムイベント用の新しいタグを作成します。 イベントタグに名前を付けます。
-
イベントタグに名前を付けます。
-
[Track Type] = [Custom Event] を選択
-
「イベント名」フィールドを調整するか、適切な変数を設定します。
-
「カスタムユーザーID」フィールドを調整するか、適切な変数を設定します。
-
必要に応じて「属性」を調整し、キー/値ペアを イベントに 渡します。
-
トリガーを設定し、タグが意図したタイミングで発火するようにします。
-
トリガーとタグを保存し、プレビューでテストします。
コンバージョンイベントの追跡
コンバージョンイベントの追跡:
-
Singular Web Trackingテンプレートを使用してカスタムイベント用の新規タグを作成します。 コンバージョンイベントタグに名前を付けます。
-
コンバージョンイベントタグに名前を付けます。
-
トラッキングタイプ = コンバージョンイベントを選択
-
「イベント名」フィールドを調整するか、適切な変数を設定します。
-
「カスタムユーザーID」フィールドを調整するか、適切な変数を設定します。
-
必要に応じて「属性」を調整し、キー/値ペアを イベントに 渡します。
-
トリガーを設定し、タグが意図したタイミングで発火するようにします。
-
トリガーとタグを保存し、プレビューでテストします。
収益イベント追跡
収益情報を含むコンバージョンイベントを追跡し、 より詳細なコンテキストを得るためにオプションの属性を追加します:
-
Singular Web Trackingテンプレートを使用してカスタムイベント用の新規タグを作成します。 収益イベントタグに名前を付けます。
-
収益イベントタグに名前を付けます。
-
トラッキングタイプ = 収益イベントを選択
-
「イベント名」フィールドを調整するか、適切な変数を設定します。
-
「カスタムユーザーID」フィールドを調整するか、適切な変数を設定します。
-
「通貨」フィールドを調整するか、適切な変数を設定します。 収益通貨は3文字のISO 4217通貨コード(例:「USD」、「EUR」、「INR」)で渡してください。
-
「収益」フィールドを調整するか、適切な変数を設定します。 収益は指定通貨で表す必要があります。
-
必要に応じて「属性」を調整し、イベント上でキー/値ペアを渡します。
-
トリガーを設定し、期待されるタイミングでタグがトリガーされるようにします。
-
トリガーとタグを保存し、プレビューでテストしてください。
一般的なイベント実装パターン
ページロードイベント用のGTMトリガー作成
Singular Web SDKをGoogle Tag Managerで実装するには、 ページ読み込み時に発火するページロードトリガーを作成する必要があります。
クイック設定:GTM で トリガー 新規 トリガー設定 に移動し、 トリガータイプとして「ページビュー」を選択します。ほとんどの実装では、 すべてのページロードでトリガーを発動させるため「すべてのページビュー」を選択します。
完全な設定手順については、Google公式のタグマネージャードキュメントを参照してください:
ボタンクリック用GTMトリガーの作成
Singular Web SDKを介したボタン操作をGoogleタグマネージャーで追跡するには、 ユーザーが特定の要素をクリックした際に発火するクリックトリガーを作成する必要があります。
簡易設定:GTMで トリガー 新規 トリガー設定に移動し、 「すべての要素」を選択するとページ上のあらゆる要素 (ボタン、リンク、画像) のクリックを追跡可能。 「リンクのみ」を選択するとHTMLアンカー要素のみ対象。
クリック変数の有効化:クリックトリガー作成前に、 GTMで組み込みクリック変数を有効化します。 [変数] → [設定]→ [組み込み変数] に移動し、 「クリック」下の全オプションを選択します。
特定の要素をターゲットにする:パフォーマンス向上のため、 「すべてのクリック」ではなく「 一部のクリック」を使用し、 クリックID、クリッククラス、クリックテキストに基づく条件を追加して 特定のボタンをターゲットにします。
完全な設定手順については、Google公式のタグマネージャードキュメントを参照してください:
フォーム送信イベント用のGTMトリガー作成
Google タグ マネージャー経由で Singular Web SDK を使用してフォーム完了を追跡するには、 ユーザーがサイトでフォームを正常に送信したときに発火する フォーム送信トリガーを作成する必要があります。
簡易設定:GTMで トリガー 新規 トリガー設定 に移動し、 トリガータイプとして「フォーム送信」を選択。 「検証チェック」を有効化し、正常送信時のみ トラッキングが行われるようにします。また、 ページリダイレクト前にトラッキングを許可するため、 「タグ待機」を2000ms遅延で有効化することを検討してください。
フォーム変数の有効化:フォームトリガー作成前に、 GTMで組み込みフォーム変数を有効化します。 [変数] → [設定]→ [組み込み変数]に移動し、 「フォーム」下の全オプションを選択します。
パフォーマンス最適化:効率化のため、 「すべてのフォーム」ではなく「 一部のフォーム」を選択し、 フォーム送信が発生する特定のフォームやページを 条件で絞り込んでください。
代替手法:最新のAJAXフォームは標準のフォーム送信トリガーで動作しない場合があります。 組み込みトリガーが作動しない場合、成功メッセージやサンキューページのトラッキングには 要素可視性トリガーなどの代替トラッキング手法を検討してください。
完全な設定手順については:Google公式のタグマネージャードキュメントを参照してください:
ステップ4: カスタマーユーザーIDの設定
Singular SDKメソッドを使用して、内部ユーザーIDをSingularに送信できます。
注: Singularのクロスデバイスソリューションをご利用の場合、 すべてのプラットフォームでユーザーIDを収集する必要があります。 注:複数のユーザーが単一デバイスを使用する場合、 ログイン時とログアウト時にユーザーIDを設定/解除する ログアウトフローの実装を推奨します。
注:複数のユーザーが単一デバイスを使用する場合、ログイン/ログアウト時にユーザーIDを設定 /解除するログアウトフローの実装を推奨します。
ヒント!モバイルSDKで使用しているのと同じカスタマーユーザーIDを使用してください。これによりクロスデバイスアトリビューションが可能になり、プラットフォームをまたいだユーザー行動の完全な可視化が実現します。
ユーザーがログインせずにウェブサイト上でアクションを実行している間は、 Singularが生成したユーザーIDでイベントが送信されます。 ただしユーザーが登録またはログイン後は、 ウェブサイトで使用しているユーザーID(例:ハッシュ化されたメールアドレス)を Singularに送信できます。
SingularはユーザーIDを、ユーザーレベルデータエクスポート(アトリビューションログのエクスポート参照)および内部BIポストバック(設定済みの場合、内部BIポストバックの設定参照)で使用します。
ユーザーIDをSingularに送信する方法は2つあります:
- 推奨: ウェブサイト起動時にユーザーIDが判明している場合 、 SDK初期化時に 「Initialization」トラックタイプでユーザーIDを設定します。これにより、 最初のページ訪問時からユーザーIDがSingularに利用可能になります。
- 代替方法として、認証後など任意のタイミングで 「ログイン」トラックタイプのタグをトリガーできます。 ユーザーIDが利用可能になり次第、すぐに呼び出すことを推奨します。 注:このタグの呼び出しはイベントをトリガーしません。 今後発生するイベントトリガーに追加されるユーザーIDを設定するだけです!
SingularでユーザーIDを設定するには、 「ログイン」トラックタイプのSingularタグを追加します:
- Google タグマネージャーアカウントで、[タグ] > [新規] をクリックします。
- タグ設定ウィンドウで、 [タグ設定] をクリックし、[タグタイプ] メニューから「Singular Web Tracking」を選択します。
- [トラックタイプ] で「ログイン」を選択します。
- カスタムユーザーID欄に、ユーザーIDを含むGoogleタグマネージャー変数を入力します。
- [トリガー設定]をクリックし、トリガーとなるイベントを追加します:ユーザー ログイン または登録。
- [保存]をクリックします。
ユーザーIDの設定を解除するには、 「ログアウト」トラッキングタイプのタグを追加します:
- Google タグマネージャーアカウントで、[タグ] > [新規] をクリックします。
- [タグ設定]ウィンドウで[タグ設定]をクリックし、[タグタイプ]メニューから「単一ウェブトラッキング」を選択します。
- [トラッキングタイプ] で「ログアウト」を選択します。
- [トリガー設定]をクリックし、トリガーイベントを追加します:ユーザー ログアウト。
- [保存]をクリックします。
注記:
- ユーザーIDは、ログアウト追跡タイプを使用して解除するか、ユーザーがローカルストレージを削除するまで持続します。
- ウェブサイトの閉じる/更新操作ではユーザーIDは解除されません。
- シークレットモードなどのプライベートブラウジングでは、ブラウザ終了時にローカルストレージが自動的に削除されるため、SingularがユーザーIDを保持できません。 ステップ5: イベント重複排除(任意)
ステップ5: イベント重複排除(任意)
Google Tag Manager でのイベント重複排除
重要!GTMトリガーが短時間で同一Singularイベントを複数回発火させる場合(例:連続クリックや同一アクションの複数トリガー)、Singularのオプション機能「イベント重複排除」を有効化し、重複エクスポートを自動抑制してください。
GTMで重複が発生する理由
GTMは同一ユーザーアクションに対してタグを複数回評価・発火する可能性があります(例: トリガー条件の重複や複数イベントリスナー)。これにより Singularイベントエクスポートの重複が発生します。
GTM重複排除方法(推奨)
Singular SDKイベント重複排除:Singular Web SDKのGTMテンプレートで重複排除を有効化し、設定可能な時間枠内で同一の重複排除パラメータに一致する重複イベントを削除します。
実装手順
イベント重複排除の有効化:Singular Web SDK 初期化タグ/テンプレートで、 イベント重複排除オプションを有効にします。
時間枠の設定(オプション):2つのイベントを重複と見なす最大時間枠(ミリ秒単位)を設定します(デフォルト:1000ms / 1秒)。
重複排除の仕組み
有効化時、SDKは以下のパラメータのハッシュ値を用いて、同一イベントが時間枠内で再度発生した場合にイベント(ページ訪問を除く)を抑制します:EventName,EventProductName,IsRevenueEvent,CustomUserId,GlobalProperties,MatchId,WebUrl
(さらに収益やカスタム引数などのイベント「追加」ペイロード)。
ステップ6: GTM実装のテスト
- GTMプレビューモードを開き、ウェブサイトを読み込みます。
- 以下の点を確認してください:
-
SDKが読み込まれる(
singular-sdk.jsへのネットワークリクエスト) - イベントが期待通りにトリガーされ、アクションごとに1回のみ発生している
-
singularに関連するブラウザコンソールのエラーがないこと -
sdk-api-v1.singular.netへのネットワークリクエストが送信されている
- ブラウザ開発者ツールの「ネットワーク」タブで 適切なペイロードが送信されていることを確認
成功!ネットワークリクエストに正しいSingularイベントが表示され 重複がない場合、本番環境に移行可能です!
ステップ7: Web-to-Appフォワーディングの実装
Web-to-Appアトリビューション転送
Singular Web SDKを使用して、ウェブサイトからモバイルアプリへのユーザージャーニーを追跡し、 モバイルアプリインストールや 再エンゲージメントへの正確なウェブキャンペーンアトリビューションを実現します。 デスクトップユーザー向けのQRコードサポートを含む、Web-to-App転送の設定手順に従ってください。 当社の「Web-to-Mobile App Attribution Forwarding Guide」に従い、 モバイルウェブアトリビューション用のSingular Web SDKを設定してください。
- モバイルウェブアトリビューション用にSingular Web SDKを設定するには、 「ウェブサイトからモバイルアプリへのアトリビューション転送ガイド」 に従ってください。
-
モバイルWebからアプリへのトラッキング設定:
-
アプリ起動タグを追加し、アプリを開く/インストールするボタンクリックをトリガーに設定します。
-
Open Appタグの設定時には、 Singularの「リンク管理」ページから モバイルWeb→アプリのベースリンクを指定してください。
-
-
アプリ起動タグを追加し、アプリを開く/インストールするボタンクリックをトリガーに設定します。
-
デスクトップWebからアプリへのトラッキングの場合:
-
QRコード生成用クリーンアップタグを作成
- GTMで[タグ] > [新規]に移動し、 [カスタムHTML]を選択します。
-
コードを追加:
- 選択したQRCodeライブラリをインジェクション
-
Web-to-Appリンクを取得
window.singularSdk.buildWebToAppLink(baselink); - 返されたリンクからQRコードを生成。
- ページ上のQRコード画像を更新します。
- タグ名を設定:"Singular - QRコードジェネレーター (クリーンアップ)"
- トリガー不要:クリーンアップタグは メインタグからトリガーを継承
-
Singular Initタグを設定:
- タグ設定をクリック
- 詳細設定 > タグシーケンスに移動
- 「[Singular Init タグ] 発火後にクリーンアップタグを発火」にチェック
- ドロップダウンからQRコードジェネレータタグを選択
- タグを保存し、プレビューモードでテストしてください。
-
QRコード生成用クリーンアップタグを作成
ヒント!モバイルアプリ内ブラウザのWebビュー(Facebook、Instagram、TikTokなどで使用されるもの)は、 ユーザーがデバイスのネイティブブラウザに移動すると SingularデバイスIDが変更される 可能性があり、アトリビューションを妨げます。
これを防ぐには、各広告ネットワークで常に適切なSingularトラッキングリンク形式を使用してください:
詳細トピック
Singularバナー
グローバルプロパティの追加
Singular SDKでは、カスタムプロパティを定義し、 すべてのセッションおよびイベントと共に Singularサーバーへ送信できます。これらのプロパティは、 ユーザー情報、アプリモード/ステータス、その他任意の情報を 表すことができます。
-
有効なJSONオブジェクトとして最大5つのグローバルプロパティを定義できます。 グローバルプロパティは、ブラウザの
localStorageに クリアされるまで永続化されます。 -
各プロパティ名と値は最大200文字までです。 これより長いプロパティ名または値を送信した場合、 200文字に切り詰められます。
-
グローバルプロパティは、Singularのユーザーレベルイベントログとポストバックに反映されます。
グローバルプロパティは、Google Tag Managerのトラッキングテンプレート初期化時にサポートされました。SingularGTM初期化タグタイプでは、プロパティのJSONオブジェクトを設定し、既存プロパティを上書きするかどうかを選択します。
GTMのグローバルプロパティタグタイプ
初期化時にグローバルプロパティを設定するには 初期化タグタイプを使用します。初期化後の実行時更新には 専用のグローバルプロパティタグタイプ(設定、取得、解除、クリア)を使用してください。
初期化タグの設定
SingularGTMのInitializationタグタイプでは、
`Global Properties `(オブジェクト)を
`Key`および`Value `フィールドに
変数、データレイヤー値、またはテキストを割り当てることで設定します。
`Override `(true/false)フィールドは
必要に応じて調整してください。
`Override `が
`false`の場合、既存のプロパティは変更されません。
`true`の場合、既存のプロパティは
上書きされます。
グローバルプロパティの設定(初期化後)
「グローバルプロパティの設定」タグタイプを使用して、 実行時に単一のプロパティを追加または更新します。
Track Type: setGlobalProperties
propertyKey: user_type
value: premium
グローバルプロパティの取得
「グローバルプロパティの取得」タグタイプを使用すると、 現在のグローバルプロパティオブジェクトを読み取れます。 グローバルプロパティオブジェクトを保存するには、 データレイヤーキー名を設定できます。
Track Type: getGlobalProperties
グローバルプロパティの解除
「グローバルプロパティの解除」タグタイプを使用すると、 単一のプロパティキーを削除できます(オブジェクト全体をクリアしません)。
Track Type: unsetGlobalProperty
propertyKey: user_type
グローバルプロパティのクリア
「グローバルプロパティのクリア」タグタイプを使用すると、 すべてのグローバルプロパティを削除します。
Track Type: clearGlobalProperties
オーガニック検索トラッキング
オーガニック検索トラッキング設定タグの作成
重要! - このタグはSingular SDKの初期化前に必ず発火させること!
このカスタムHTMLタグは、ドキュメントURLを修正し、Singular Web SDKが初期化時に読み取る必要があるオーガニック検索トラッキングパラメータ(wpsrcおよびwpcn)を追加します。タグのシーケンスは、適切な実行順序を確保するために不可欠です。
この例は、オーガニック検索トラッキングを有効にするための 回避策 ソリューションとして提供されています。コードは あくまで 例として使用し、マーケティング部門のニーズに基づいて ウェブ 開発者が更新・保守を行う必要があります。 オーガニック 検索トラッキングは広告主ごとに異なる意味を持つ場合があります。 サンプルを 確認し、必要に応じて調整してください。
なぜこれを使用するのか?
-
キャンペーンパラメータが存在しない場合でも、 オーガニック検索からの訪問が適切に追跡されることを保証します。
-
明確なアトリビューションのため、URLに
wpsrcパラメータ(参照元)の値とwpcnパラメータ(キャンペーン名)を 「OrganicSearch」として付加します。 -
現在のURLとリファラーを
localStorageに保存し、 後で使用できるようにします。 -
純粋なJavaScript、依存関係ゼロ、統合が容易。
動作原理
-
ページURLから既知のキャンペーンパラメータ(Google、 Facebook、TikTok、UTMなど)をチェック。
-
キャンペーンパラメータが存在せず、リファラーが 検索エンジンの場合、以下を追加:
-
wpsrc(リファラーを値として) -
wpcn(値として OrganicSearch を設定)
-
-
ページを再読み込みせずにブラウザのURLを更新します。
-
現在のURLとリファラーを
localStorageにsng_urlとsng_refとして保存。
使用方法
- GTMで[タグ] > [新規]に移動し、 [タグ設定]をクリックして [カスタムHTML]を選択します。
- 以下の完全なJavaScriptコードを貼り付けます。
-
このタグのトリガー作成はスキップします。 このタグはSingular Initタグの前に実行する必要があるため、 タグシーケンスを使用してInitタグより前に発火するよう設定します。
- 「Singular - Organic Search Setup」のような説明的な名前を使用してください。
- Singular Web SDK Initタグを開きます。
- [タグ設定]をクリック
- 詳細設定 > タグシーケンスに移動します。
- 「[Singular Init Tag] 発火前にセットアップタグを発火」にチェックを入れます。
- ドロップダウンから「Singular - Organic Search Setup」タグを選択 してください。
- 推奨:URL変更が不完全な状態での初期化を防ぐため、 「[セットアップタグ]が失敗した場合、[Singular 初期化タグ]を起動しない」にチェックを入れてください。
- タグを保存します。
-
GTMのプレビューモードで確認:
- セットアップタグが最初に発火し、URLを修正します。
- Singular Initタグが2番目に発火し、 変更された URLパラメータを読み取ります。
- タグ間のタイミング競合は発生しません。
高度なタグシーケンスについては、Googleの 公式 ドキュメントを参照してください:
<script>
(function() {
// singular-web-organic-search-tracking: setupOrganicSearchTracking.js
// Tracks organic search referrals by appending wpsrc and wpcn to the URL if no campaign parameters exist and the referrer is a search engine.
// Configuration for debugging (set to true to enable logs)
var debug = true;
// List of campaign parameters to check for exclusion
var campaignParams = [
'gclid', 'fbclid', 'ttclid', 'msclkid', 'twclid', 'li_fat_id',
'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'wpsrc'
];
// Whitelist of legitimate search engine domains (prevents false positives)
var legitimateSearchEngines = new Set([
// Google domains
'google.com', 'google.co.uk', 'google.ca', 'google.com.au', 'google.de',
'google.fr', 'google.it', 'google.es', 'google.co.jp', 'google.co.kr',
'google.com.br', 'google.com.mx', 'google.co.in', 'google.ru', 'google.com.sg',
// Bing domains
'bing.com', 'bing.co.uk', 'bing.ca', 'bing.com.au', 'bing.de',
// Yahoo domains
'yahoo.com', 'yahoo.co.uk', 'yahoo.ca', 'yahoo.com.au', 'yahoo.de',
'yahoo.fr', 'yahoo.it', 'yahoo.es', 'yahoo.co.jp',
// Other search engines
'baidu.com', 'duckduckgo.com', 'yandex.com', 'yandex.ru',
'ask.com', 'aol.com', 'ecosia.org', 'startpage.com',
'qwant.com', 'seznam.cz', 'naver.com', 'daum.net'
]);
// Extract main domain from hostname (removes subdomains)
function getMainDomain(hostname) {
if (!hostname) return '';
var lowerHost = hostname.toLowerCase();
// Handle special cases for known search engines with country codes
var searchEnginePatterns = {
'google': function(host) {
// Match google.TLD patterns more precisely
if (host.indexOf('google.co.') !== -1 || host.indexOf('google.com') !== -1) {
var parts = host.split('.');
for (var i = 0; i < parts.length - 1; i++) {
if (parts[i] === 'google') {
return parts.slice(i).join('.');
}
}
}
return null;
},
'bing': function(host) {
if (host.indexOf('bing.co') !== -1 || host.indexOf('bing.com') !== -1) {
var parts = host.split('.');
for (var i = 0; i < parts.length - 1; i++) {
if (parts[i] === 'bing') {
return parts.slice(i).join('.');
}
}
}
return null;
},
'yahoo': function(host) {
if (host.indexOf('yahoo.co') !== -1 || host.indexOf('yahoo.com') !== -1) {
var parts = host.split('.');
for (var i = 0; i < parts.length - 1; i++) {
if (parts[i] === 'yahoo') {
return parts.slice(i).join('.');
}
}
}
return null;
}
};
// Try specific patterns for major search engines
for (var engine in searchEnginePatterns) {
if (lowerHost.indexOf(engine) !== -1) {
var result = searchEnginePatterns[engine](lowerHost);
if (result) return result;
}
}
// Handle other known engines with simple mapping
var otherEngines = {
'baidu.com': 'baidu.com',
'duckduckgo.com': 'duckduckgo.com',
'yandex.ru': 'yandex.ru',
'yandex.com': 'yandex.com',
'ask.com': 'ask.com',
'aol.com': 'aol.com',
'ecosia.org': 'ecosia.org',
'startpage.com': 'startpage.com',
'qwant.com': 'qwant.com',
'seznam.cz': 'seznam.cz',
'naver.com': 'naver.com',
'daum.net': 'daum.net'
};
for (var domain in otherEngines) {
if (lowerHost.indexOf(domain) !== -1) {
return otherEngines[domain];
}
}
// Fallback: Extract main domain by taking last 2 parts (for unknown domains)
var parts = hostname.split('.');
if (parts.length >= 2) {
return parts[parts.length - 2] + '.' + parts[parts.length - 1];
}
return hostname;
}
// Get query parameter by name, using URL.searchParams with regex fallback for IE11
function getParameterByName(name, url) {
if (!url) url = window.location.href;
try {
return new URL(url).searchParams.get(name) || null;
} catch (e) {
if (debug) console.warn('URL API not supported, falling back to regex:', e);
name = name.replace(/[\[\]]/g, '\\$&');
var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)');
var results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
}
// Check if any campaign parameters exist in the URL
function hasAnyParameter(url, params) {
for (var i = 0; i < params.length; i++) {
if (getParameterByName(params[i], url) !== null) {
return true;
}
}
return false;
}
// Improved search engine detection - only checks hostname, uses whitelist
function isSearchEngineReferrer(referrer) {
if (!referrer) return false;
var hostname = '';
try {
hostname = new URL(referrer).hostname.toLowerCase();
} catch (e) {
// Fallback regex for hostname extraction (IE11 compatibility)
var match = referrer.match(/^(?:https?:\/\/)?([^\/\?#]+)/i);
hostname = match ? match[1].toLowerCase() : '';
}
if (!hostname) return false;
// First check: exact match against whitelist
if (legitimateSearchEngines.has(hostname)) {
if (debug) console.log('Exact match found for:', hostname);
return true;
}
// Second check: subdomain of legitimate search engine
var hostParts = hostname.split('.');
if (hostParts.length >= 3) {
// Try domain.tld combination (e.g., google.com from www.google.com)
var mainDomain = hostParts[hostParts.length - 2] + '.' + hostParts[hostParts.length - 1];
if (legitimateSearchEngines.has(mainDomain)) {
if (debug) console.log('Subdomain match found for:', hostname, '-> main domain:', mainDomain);
return true;
}
// Try last 3 parts for country codes (e.g., google.co.uk from www.google.co.uk)
if (hostParts.length >= 3) {
var ccDomain = hostParts[hostParts.length - 3] + '.' + hostParts[hostParts.length - 2] + '.' + hostParts[hostParts.length - 1];
if (legitimateSearchEngines.has(ccDomain)) {
if (debug) console.log('Country code domain match found for:', hostname, '-> cc domain:', ccDomain);
return true;
}
}
}
if (debug) {
console.log('Hostname not recognized as legitimate search engine:', hostname);
}
return false;
}
// Main function to update URL with organic search tracking parameters
function setupOrganicSearchTracking() {
var url = window.location.href;
var referrer = document.referrer || '';
// Store URL and referrer in localStorage
try {
localStorage.setItem('sng_url', url);
localStorage.setItem('sng_ref', referrer);
} catch (e) {
if (debug) console.warn('localStorage not available:', e);
}
if (debug) {
console.log('Current URL:', url);
console.log('Referrer:', referrer);
}
// Skip if campaign parameters exist or referrer is not a search engine
var hasCampaignParams = hasAnyParameter(url, campaignParams);
if (hasCampaignParams || !isSearchEngineReferrer(referrer)) {
if (debug) console.log('Skipping URL update: Campaign params exist or referrer is not a legitimate search engine');
return;
}
// Extract and validate referrer hostname
var referrerHostname = '';
try {
referrerHostname = new URL(referrer).hostname;
} catch (e) {
if (debug) console.warn('Invalid referrer URL, falling back to regex:', e);
var match = referrer.match(/^(?:https?:\/\/)?([^\/]+)/i);
referrerHostname = match ? match[1] : '';
}
// Extract main domain from hostname
var mainDomain = getMainDomain(referrerHostname);
if (debug) {
console.log('Full hostname:', referrerHostname);
console.log('Main domain:', mainDomain);
}
// Only proceed if main domain is valid and contains safe characters
if (!mainDomain || !/^[a-zA-Z0-9.-]+$/.test(mainDomain)) {
if (debug) console.log('Skipping URL update: Invalid or unsafe main domain');
return;
}
// Update URL with wpsrc and wpcn parameters
var urlObj;
try {
urlObj = new URL(url);
} catch (e) {
if (debug) console.warn('URL API not supported, cannot modify URL:', e);
return;
}
// Set wpsrc to the main domain (e.g., google.com instead of tagassistant.google.com)
urlObj.searchParams.set('wpsrc', mainDomain);
// Set wpcn to 'Organic Search' to identify the campaign type
urlObj.searchParams.set('wpcn', 'Organic Search');
// Update the URL without reloading (check if history API is available)
if (window.history && window.history.replaceState) {
try {
window.history.replaceState({}, '', urlObj.toString());
if (debug) console.log('Updated URL with organic search tracking:', urlObj.toString());
} catch (e) {
if (debug) console.warn('Failed to update URL:', e);
}
} else {
if (debug) console.warn('History API not supported, cannot update URL');
}
}
// Execute the function
setupOrganicSearchTracking();
})();
</script>
クロスサブドメイントラッキング
デフォルトでは、Singular Website SDKはSingularデバイスIDを生成し、 ブラウザストレージを使用してこれを永続化します。このストレージはサブドメイン間で共有できないため、 SDKは各サブドメインごとに新しいIDを生成することになります。
サブドメイン間でSingularデバイスIDを永続化したい場合は、 以下のいずれかの方法を使用できます:
方法B(上級者向け):SingularデバイスIDの手動設定
Singular SDKによるデバイスIDの自動永続化を望まない場合、 トップレベルドメインクッキーやサーバーサイドクッキーなどを使用し、 ドメインを跨いでIDを手動で永続化できます。 値はSingularが事前に生成した 有効なuuid4形式のIDである必要があります。
注記:SingularデバイスIDは、カスタムJavaScript変数を定義し、 Initトラッキングタグ呼び出し後に singularSdk.getSingularDeviceId()を呼び出すことで取得できます。
GTM実装における一般的な問題点
| 必須のデバイス識別子 | |
|---|---|
| イベントが複数回発火する | トリガーを調整または制限し、「1ページあたり1回」を使用するか条件を追加 |
| 製品IDの形式が不正 |
製品IDは逆DNS表記(com.company.site )を使用する必要があります
|
| イベントが追跡されていない |
イベント名のスペルと大文字小文字を確認してください。singular
イベントタグが実行される前にSDKが読み込まれていることを確認してください
|
| SDKスクリプトがブロックされている | 広告ブロッカーまたは制限的なコンテンツセキュリティポリシーが原因。問題が継続する場合はネイティブJS実装への移行を検討 |
ベストプラクティス
- GTMを整理整頓:タグとトリガーに明確な名前を付け、 その目的を文書化する
- 未使用またはレガシータグを定期的に監査する。
- 重複イベントのリスク低減のため、トリガー数を最小限に抑える。
- 変更後は、本番環境へ反映する前に必ずGTMのプレビューモードで徹底的にテストする。
- クッキーベースのトラッキング(クロスサブドメイントラッキング)を使用する場合、 プライバシーポリシーを それに応じて更新する。