0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Chrome拡張機能で「サイトが使っているMarTechツール」を自動検知する仕組み

0
Posted at

はじめに

こんにちは、A-betのtoruです。個人でMarTech Inspectorというツール検知系のChrome拡張機能を開発・公開しています。

このツールは、閲覧中のWebサイトがGA4、GTM、Adobe Analytics、Tealium、KARTEなど、24種類のMarTech/計測ツールのうちどれを使っているかを自動で判定し、一覧表示するというものです。

「サイトが何のツールを使っているか」を判定するのに、各ツールベンダーが公式APIを提供しているわけではありません。そこで使うのが、いわゆるfingerprint(フィンガープリント)方式での検知です。この記事では、その実装レベルの考え方を紹介します。

MarTech Inspectorの実際の検知ルール(24ツール分の具体的なパターン)自体は非公開にしていますが、「どういう発想で・どういう技術要素を組み合わせているか」は共有できる範囲でまとめます。

そもそも何を手がかりに検知するか

計測ツールは大きく分けて、ページ上に痕跡を残します。手がかりになるのは主に3種類です。

  1. グローバル変数(windowオブジェクトに生えるオブジェクト・関数)
  2. Cookie(命名規則にツールごとの特徴が出る)
  3. リクエスト先のドメイン・パス(計測ビーコンの送信先)

これらを単独で見るのではなく、複数組み合わせて「確度」を上げるのがポイントです。単一の手がかりだけだと誤検知が起きやすいためです。

1. グローバル変数を見る

多くの計測ツールは、初期化時にwindowオブジェクトへ何らかのプロパティを生やします。たとえばGTMであればwindow.dataLayer、GA4であればwindow.gtagが代表的です(これは各ツールの公式ドキュメントに書かれている公開情報です)。

// 概念的な例:グローバル変数の有無をチェックする
function checkGlobalVars() {
  const signals = [];
  if (typeof window.dataLayer !== 'undefined') {
    signals.push({ tool: 'GTM/GA4系', signal: 'dataLayer', confidence: 0.6 });
  }
  if (typeof window.gtag === 'function') {
    signals.push({ tool: 'GA4', signal: 'gtag', confidence: 0.6 });
  }
  return signals;
}

ここで注意が必要なのは、MV3のcontent scriptはデフォルトでページ本体とは別のJS実行コンテキスト(isolated world)で動くため、ページが持つwindow.dataLayerを直接読みには行けないという点です。

これを回避するために、chrome.scripting.executeScriptworld: "MAIN"オプションを使い、document_startのタイミングでページ本体の実行コンテキストに直接コードを注入します。

chrome.scripting.executeScript({
  target: { tabId },
  world: "MAIN",
  func: () => {
    return {
      hasDataLayer: typeof window.dataLayer !== 'undefined',
      hasGtag: typeof window.gtag === 'function'
    };
  }
});

document_startで仕込むことで、ページ自身の初期化スクリプトが走るより先にフックできるため、後からwindowオブジェクトが書き換えられてしまうケースにもある程度耐えられます。

2. Cookieの命名規則を見る

計測ツールは、識別子をCookieに保存することが多く、ツールごとに命名規則の傾向があります。たとえばGA4であれば_gaから始まるCookieを発行することが公式に案内されています。

// 概念的な例:Cookie名のパターンマッチ
function checkCookiePatterns(cookies) {
  const signals = [];
  for (const cookie of cookies) {
    if (/^_ga/.test(cookie.name)) {
      signals.push({ tool: 'GA4', signal: `cookie:${cookie.name}`, confidence: 0.5 });
    }
    // 実際にはツールごとの正規表現パターンをテーブル化して回している
  }
  return signals;
}

Cookie名は難読化・変更されることもあるため、これも単独の決め手にはせず、あくまで一つの信号として扱います。

3. リクエスト先のドメイン・パスを見る

計測ビーコンは、決まったドメイン(またはパスの特徴)にリクエストを送信します。Chrome拡張機能ではchrome.webRequest(MV3では読み取り専用のonBeforeRequestなど)を使って、発生したリクエストのURLを監視できます。

chrome.webRequest.onBeforeRequest.addListener(
  (details) => {
    const url = new URL(details.url);
    // ドメインパターンに応じてツールを推定する
    matchRequestPattern(url.hostname, url.pathname);
  },
  { urls: ["<all_urls>"] }
);

MV3ではwebRequestのブロッキング系機能が制限されているため、あくまで「観測」目的での利用にとどめる必要がある点は注意が必要です(通信を書き換えたり止めたりする用途には使えません)。

3種類の信号を組み合わせて確度を上げる

ここまでの3つの信号(グローバル変数・Cookie・リクエスト)は、それぞれ単独では誤検知の可能性があります。たとえば「dataLayerという変数名だけ」であれば、計測ツールと無関係な自作のJSが偶然同じ名前を使っている可能性もゼロではありません。

そこで、MarTech Inspectorでは各信号に重み(confidence)を持たせ、複数の信号が同時に揃った場合にのみ「検知済み」と判定するロジックを組んでいます。

// 概念的な例:複数信号のスコアを合算して閾値判定する
function judgeDetection(signals, threshold = 0.8) {
  const scoreByTool = {};
  for (const s of signals) {
    scoreByTool[s.tool] = (scoreByTool[s.tool] || 0) + s.confidence;
  }
  return Object.entries(scoreByTool)
    .filter(([, score]) => score >= threshold)
    .map(([tool]) => tool);
}

実際の重み付けやパターンの組み合わせ方(24ツール分のテーブル)はプロダクトの中核ロジックなので非公開にしていますが、「単一シグナルで判定しない」という設計方針自体は、この手の検知ツールを作る上で汎用的に使える考え方だと思います。

まとめ

  • MarTechツールの検知は、公式APIがない前提で「グローバル変数・Cookie・リクエスト」の3系統の手がかりを組み合わせるfingerprint方式で行う
  • MV3環境では、ページ本体のグローバル変数を見るためにworld: "MAIN"document_startでの早期注入が必要
  • 単一の手がかりだけで判定すると誤検知しやすいため、複数信号のスコアリングで確度を上げるのが実用上のポイント

MarTech Inspector自体はChrome Web Storeで公開しているので、実際の検知結果を見てみたい方はこちらからどうぞ。

開発の経緯や他の機能(Live Mock、A/B Calculatorなど)については、noteで連載しています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?