LoginSignup
32
33

More than 5 years have passed since last update.

(あどてく!) PlayFramework/Scalaで3rd Party Cookieを出力するピクセルトラッキングサーバーを作る

Last updated at Posted at 2015-04-29

アドテク(広告テクノロジー)では、ブラウザでサイト見ているユーザー(オーディエンス)を特定する技術が求められます。
自社ECサイトで会員登録をしたユーザーを特定するのは簡単ですが、会員登録をしていないユーザー(初めて自社サイトに訪れたユーザー)を特定するには何らかの手段が必要になります。
つまり初めて自社サイトを訪れた人がどんな思考の人か、どんなサイトのどんなページを見ていたか・・。
その情報を特定するためにCookieに特定のIDを付与する技術がアドテクでは使われています。

3rd Party Cookieとは

3rdCookie.png

今回の想定シナリオは以下のようになります
1. オーディエンスがサイト1(train.com)で大阪へいくための電車料金を調べる
2. サイト1には<img src="tracking.com/1.gif">が埋め込まれており、オーディエンスがサイトを見た瞬間にトラッキングサーバーへ通信が走る。(オーディエンスのブラウザ->トラッキングサーバー)
3. トラッキングサーバーはオーディエンスのブラウザにCookieを出力しトラッキングIDを付与する
4. オーディエンスは電車のチケットは当日駅で買うことにし、ホテルのサイト(hotel.com)でホテルを予約することにする
5. hotel.comにも<img src="tracking.com/1.gif">が埋め込まれており、オーディエンスがサイトを見た瞬間にトラッキングサーバーへ通信が走る。(オーディエンスのブラウザ->トラッキングサーバー)
6. トラッキングサーバーはオーディエンスのブラウザにtracking.comのクッキーが埋め込まれているのを確認し、再度IDを付与することはせずCookieのexpire(期限)だけを更新する。
7. オーディエンスのCookieIDからtrain.comで大阪の情報を調べていたことがログからわかるので、ホテルのページの広告枠に大阪のホテルの案内を出したり、ファーストビューを大阪ホテルのキャンペーンページに変更したりなど広告を最適化する。

トラッキング用のクッキーの種類は大きくわけて2つあります。

種類 説明     
1st Party Cookie 対象サイトのドメインのクッキーを使ってトラッキングする。絵でいう所のtrain.comのドメインでCookieを出力する
3rd Party Cookie 対象サイトとは別のトラッキングザーバーのドメインを使ってトラッキングする。絵でいう所のtracking.com

1st Party Cookieで代表的なのはGoogleAnalytics(GA)です。
参考:http://nexal.jp/blogs/2061.html

3rdPartyにはSafariをトラッキングできないという致命的な欠陥(※)がありそれを回避するには1stParyCookieが有効です。(他にもローカルストレージをモニョモニョする・・などもありますが)
(※)Safariのデフォルトの設定が「3rd Party Cookieを拒否する」となっているため事実上3rdのCookieを受け付けない。

ピクセルトラッキングとは

1x1の透明画像(だいたいはgif)をレスポンスとして返す裏でCookieを仕込み、Cookieにユーザーを特定するIDを付与する技術の事。
透明なのでブラウザからは見えない、というかほとんどはhtmlでhidden設定されてるのでブラウザには表示されない。
ピクセルトラッキングのHTMLの記述についてはDoubleClick(google)のサイトが超詳しい
https://support.google.com/dfp_premium/answer/1347585?hl=ja

画像でなくてもいいが、htmlのsrc=などでHTLMのオンロードで自動的に読み込めるものに限る。
またJSはサードパーティ製のサイトのJSを読み込めないブログサービスなどもあるので扱いづらい。
よって基本は画像になる。

PlayFramework/Scalaでピクセルトラッキングサーバーを作る

Playインストール

Activatorをダウンロードし
activator newでプロジェクトを新規作成する。(Scalaプロジェクト)

コントローラー実装

Tracking.scala
package controllers
import play.api._
import play.api.mvc._
import play.api.libs.Codecs
import java.security.MessageDigest
// Java8 lib
import java.util.Base64


object Tracking extends Controller {

  val COOKIE_KEY = "Z_SYSTEM_3RD_PARTY_COOKIE_ID_SCALA"
  val COOKIE_MAX_AFTER_AGE = Some(31622400 + 31622400)

  //ref https://css-tricks.com/snippets/html/base64-encode-of-1x1px-transparent-gif/
  val onePixelGifBase64 = "R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
 val onePixelGifBytes = Base64.getDecoder().decode(onePixelGifBase64)

  def pixelTracking = Action {request =>
    val cookies = request.cookies
    val cookieValue = cookies.get(COOKIE_KEY).map { cookie =>
      Logger.debug(s"Cookie Exist! ${cookie.value}")
      cookie.value
    }.getOrElse {
      val newValue = uniqueIdGenerator()
      Logger.debug("Cookie Generate! $newValue")
      newValue
    }
    Ok(onePixelGifBytes).withCookies(Cookie(COOKIE_KEY, cookieValue, COOKIE_MAX_AFTER_AGE)).as("image/gif")
  }

  val uniqueIdGenerator = () => {
    val milliTime = System.currentTimeMillis()
    val nanoTime = System.nanoTime()
    val baseString = s"$milliTime $nanoTime"
    Logger.debug(baseString)

    val md = MessageDigest.getInstance("SHA-256")
    md.update(baseString.getBytes())

    val id = Codecs.toHexString(md.digest())
    Logger.debug(id)
    id
  }
}

val uniqueIdGenerator 関数 (CookieID生成関数)

トラッキング用のIDはどようなアクセス状況下、どのようなサーバーマシン構成でもオーディエンスに対してユニークなIDを割り当てることが求められる。
今回はミリ秒とナノ秒(※)をスペースでつなげてSHA256した16進法文字列をIDとした。
これであれば同じミリ秒でアクセスしたユーザーがいない限りはユニークなIDとなる。
よりアクセス数があるサーバーであればユーザーのIPやサーバーのIPやMACアドレス、プロセスID、Javaプロセスのフリーメモリ数などを足してハッシュ化するといいだろう。
ロジックを使いまわして別トラッキングサーバーを作る場合は、トラッキングサーバーの種別ID("hogehoge-TrankingServer1")などを連結すればよいだろう。
(※)現在の一般のCPUでは正確なナノ秒は測定できないがSystem.nanoTime()はミリ秒よりは正確な値を返す。

def pixelTracking メソッド

このメソッドが実際のリクエストを受け付ける処理となる。

処理は単純で
1. リクエストにCookieの値("Z_SYSTEM_3RD_PARTY_COOKIE_ID_SCALA")があるかを検索
2. Cookieの値があったらCookieのExpire(有効期限)を更新して1x1ピクセルgifを返却
3. Cookieの値がなかったらuniqueIdGenerator関数を実行しCookieIDを生成
4. 生成したCookiIDをレスポンスに付与し、同時に1x1ピクセルgifを返却

ルーティングの設定

/conf/route
GET        /1.gif               controllers.Tracking.pixelTracking

http://サーバーのドメイン/1.gif にアクセスすると処理が実行されるようになる。

トラッキングサーバー起動

activatorを起動し、runでポート9000で起動する

activator
[info] Loading project definition from play_scala_study/play_scala_1/project
[info] Set current project to play_scala_1 (in build file:/play_scala_study/play_scala_1/)
[play_scala_1] $ run

--- (Running the application, auto-reloading is enabled) ---

[info] play - Listening for HTTP on /0:0:0:0:0:0:0:0:9000

http://localhost:9000/1.gif にアクセスし、画面にgifが表示され、Cookieが書き込まれていることを確認する。(ブラウザの開発者ツールで確認する)
二回目のアクセスでクッキーIDが変更されていないことを確認する。

実際に運用する場合はport80で起動するようポートを指定して起動する。

activator
start 80

自社サービスのサイトのHTMLの実装

トラッキングサーバーは起動したので、別のドメインのサイトのページに以下のような記述を埋め込めばトラッキングは完了です。

train.com/index.html
<p>安い電車予約どっとこむ</p>
<img src="http://tracking.com/1.gif" style="display:none">
hotel.com/index.html
<p>安いホテル予約どっとこむ</p>
<img src="http://tracking.com/1.gif" style="display:none">
32
33
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
32
33