muffet 1665
客戶案例介紹
trackProduct
- tracker(‘viewItem’, product)
- tracker(‘addToCart’, product)
- tracker(‘addToWishlist’, product)
程式碼的觸發
const trackProduct = new Event({
name: 'trackProduct',
trigger: routeChange.path.contains('/product').and(routeChange.host.eq('www.eslite.com')),
runOnce: false,
delay: 2000,
fn: function (retry = 5) {
let product
let method = 'update'
// 這個 ecName 是從別的地方匯過來的,就是商家姓名 - sku 就是產品的獨特ID
const sku = `${ecName}:product:${location.pathname.match(/product\/(\d+)/).pop()}`
logger(sku, "==========")
// 這一段不太懂
if (document.querySelector('.nuxt-error')?.textContent.match('頁面不存在|程式錯誤500')) {
method = 'expire'
product = new Product({ sku, live: 0 })
// insertPixel 就是一個插入一段程式碼的 fc,後面接的就是要插入的程式碼,這邊插入的應該就是 塔圖的追蹤碼
insertPixel(`//track.tagtoo.com.tw/up?t=${method.slice(0, 1)}&${product.toQueryString()}`)
return
}
// 商品名稱
const title = document.querySelector('h1')?.textContent
// 特價
const price = document.querySelector('span.item-price')?.textContent.replace(/\D/g, '')
// 原價
const storePrice = document.querySelector('span.pre-product-price')?.textContent.replace(/\D/g, '') ?? price
// 商品描述 -> 他把其他怪怪的字符都用空字串取代掉了,最後只取前200個字
const description =
document
.querySelector('.article')
?.textContent.replace(/<[^>]+>|[\uffff]/g, '')
.slice(0, 200) ?? ''
// 書本規格 -> 判斷這本書是否為限制級的書籍
const restricted = [...document.querySelectorAll('.product-description-schema .row .row span')].some((e) =>
e.textContent.match('級別.*限')
)
// 如果是就回傳,不是就繼續往下
if (restricted) return
// 麵包屑
const categoryPath = Array.from(document.querySelectorAll('.breadcrumb li'), ($li) => $li.textContent).join(
'>'
)
// 圖片網址
const imageUrl = document.querySelector('.product-images .swiper-slide-active img')?.src
// 購買按鈕
const live = Number(
document
.querySelector('.product-information .btn-eslite-red, .btn-secondary')
?.textContent.includes('直接購買')
)
// btn-eslite-red: 直接購買/貨到通知
// btn-secondary: 無法購買
// 作者
const author = document.querySelector('.author span.text-underline')?.textContent ?? ''
// 出版社
const publisher = document.querySelector('.publisher span.text-underline')?.textContent ?? ''
// 規格
const schema = document.querySelector('.product-description-schema')?.textContent ?? ''
// ISBN 號碼
const isbn = schema.match(/ISBN13 \/ (\d+)/)?.pop() ?? ''
// 分開符號
const separator = ' ' + '。' + ' '
// 活動口號
const promotionTag = Array.from(document.querySelectorAll('.promotion-activities-items > .row'))
.map((e) => e.textContent.trim())
.join(separator)
// 活動口號句尾加上一段字
const tags =
Array.from(document.querySelectorAll('.tags .badge'), (e) => {
return e.textContent.trim()
}).join(separator) + `-promotionTag:${promotionTag}`
// 活動口號開頭再加上另一段推行銷字串
const activity = Array.from(
document.querySelectorAll('.promotion-activities-items > .row , .exhibition-name'),
(e) => {
return e.textContent.trim()
}
).join(separator)
// 運費
const shipping = 50
// 產品的細節 - 包含客製化抓的東西
product = new Product({
title,
sku,
price,
storePrice,
description,
categoryPath,
imageUrl,
live,
customLabel1: author,
customLabel2: publisher,
customLabel3: tags,
customLabel4: activity,
shipping,
gtin: isbn,
})
logger(isNaN(product.get('price')), product.get('imageUrl').match('/img/loading_'))
// 如果今天產品沒有原價、沒有特價、沒有圖片,持續嘗試爬蟲,我們一開始有設定retry = 5 ,所以可以跑5次迴圈,又或者是,書籍的類型包含 性知識/性愛,就回傳null
if (
isNaN(product.get('price')) ||
isNaN(product.get('storePrice')) ||
product.get('imageUrl').match('/img/loading_')
) {
setTimeout(() => {
if (retry > 0) {
retry--
window.tgk('run', 'trackProduct', retry)
}
}, 1000)
return null
} else if (categoryPath.match('性知識/性愛')) {
return null
}
// 送出 viewItem 事件
tracker('viewItem', product)
// 插入像素
insertPixel(`//track.tagtoo.com.tw/up?t=${method.slice(0, 1)}&${product.toQueryString()}`)
logger(insertPixel(`//track.tagtoo.com.tw/up?t=${method.slice(0, 1)}&${product.toQueryString()}`), "=========")
// 微軟的追蹤碼
let UETData = ['ecommerce', 'ViewContent', product.get('sku'), product.get('price')]
sendUETCustomEvent(...UETData)
// 加入購物車和直接購買的按鈕
const $addToCartBtns = document.querySelectorAll('div.add-cart.cart-button, div.direct-buy')
$addToCartBtns.forEach(($btn) => {
$btn.addEventListener('click', () => {
// 兩個按鈕點擊,都要送 addToCart 事件
tracker('addToCart', product)
// 送微軟事件
UETData = ['ecommerce', 'AddToCart', product.get('sku'), product.get('price')]
sendUETCustomEvent(...UETData)
})
})
// 蒐藏按鈕
const $addToWishlistBtn = document.querySelector('div.add-trace.cart-button')
$addToWishlistBtn?.addEventListener('click', () => {
// 送 addToWishlist 事件
tracker('addToWishlist', product)
// 送微軟事件
UETData = ['ecommerce', 'AddToWishlist', product.get('sku'), product.get('price')]
sendUETCustomEvent(...UETData)
})
},
})
印出來的 console
> fire all viewItem (3ad66d57-42a8-48a9-8280-f525d9f30569)
>Product(17) {'advertiserId' => 1655, 'title' => '【藥師健生活】上班必備組(五百益生菌x1+葉黃素x1) 共2入', 'sku' => 'eslite:product:100', 'link' => 'https://www.eslite.com/product/100F339042682337476000', 'categoryPath' => '首頁>食品保健>養生保健>益生菌', …}
> fire facebook viewItem event
> send gtag event 'view_item' to ["AW-477262169"]
> {items: Array(1), value: 2790, currency: 'TWD', send_to: Array(1)}
> fire google viewItem event
> tagtoo.tracker.event(): ViewContent, [object Object]
> fire tagtoo viewItem event
> fire yahoo viewItem event
trackCheckout
- tracker(‘trackCart’, cart)
- tracker(‘checkout’, cart)
程式碼的觸發
const trackCheckout = new Event({
name: 'trackCheckout',
// 網址包含 /cart/step1 , 就觸發事件
trigger: routeChange.path.contains('/cart/step1').and(routeChange.host.eq('www.eslite.com')),
delay: 3000,
runOnce: false,
fn: (retry = 5) => {
// 宣告一個函式
const getCart = () => {
// cart 變數,繼承 Cart 物件
const cart = new Cart()
// 抓到購物車所有的產品
const $items = document.querySelectorAll('div.cart-item-row')
// forEach 迴圈抓資料
$items.forEach(($item) => {
// 標題
const title = $item.querySelector('.product-name').textContent
// 產品ID
const pID = $item
.querySelector('a')
.href.match(/product\/(\d+)/)
.pop()
// 有前綴的產品獨特ID
const sku = `${ecName}:product:${pID}`
// 產品價格
const price = $item.querySelector('.cart-price-black').textContent.replace(',', '')
// 數量
const qty = $item.querySelector('input.number-view').value
// 把剛剛的東西都塞進 cart 裡面
cart.add(new Product({ title, sku, price, qty }))
})
// 儲存這些資訊到 cart
cart.save()
return cart
}
// 點選結帳
const nextStepBtn = document.querySelector('.summary-item .btn-e-red')
// 如果這個事件已經綁定過了,就直接回傳
if (nextStepBtn._tg_event_bind) {
return
}
// 檢查購物車是不是空的,如果是空的,等幾秒後再檢查一次,檢查五次後還是空的話,再結束動作
const cart = getCart()
if (cart.products.length === 0) {
setTimeout(() => {
if (retry > 0) {
retry--
window.tgk('run', 'trackCheckout', retry)
}
}, 1500)
return
}
// 送出兩個 tracker
tracker('trackCart', cart)
tracker('checkout', cart)
// 整理成 Yahoo 渠道格式
const cartData = cart.toYahoo()
// 送到微軟渠道
sendUETCustomEvent('ecommerce', 'AddToCart', cartData.skus, cartData.value)
sendUETCustomEvent('ecommerce', 'InitiateCheckout', cartData.skus, cartData.value)
// 點擊按鈕就觸發 getCart()
nextStepBtn.addEventListener('click', () => {
getCart()
})
// 綁定事件,這樣不會重複觸發
nextStepBtn._tg_event_bind = true
},
})
印出來的 console
> fire all trackCart (4ab2ee8f-51b7-408a-8018-6cfc31afc391)
> Cart {products: Array(2), total: 4180, tax: 0, shipping: 0, currency: undefined, …}
> fire facebook trackCart event
> send gtag event 'view_cart' to ["AW-477262169"]
> {transaction_id: undefined, value: 4180, shipping: 0, currency: 'TWD', coupon: undefined, …}
> fire google trackCart event
> tagtoo.tracker.event(): AddToCart, [object Object]
> fire tagtoo trackCart event
> fire yahoo trackCart event
> fire all checkout (eb9a578e-5589-4171-8e13-5721a49f98f1)
> Cart {products: Array(2), total: 4180, tax: 0, shipping: 0, currency: undefined, …}
> fire facebook checkout event
> send gtag event 'begin_checkout' to ["AW-477262169"]
> {transaction_id: undefined, value: 4180, shipping: 0, currency: 'TWD', coupon: undefined, …}
> fire google checkout event
> fire yahoo checkout event
> fire facebook checkout conversion
> send gtag event 'conversion' to "AW-477262169/oJzUCMbUq-sBENniyeMB"
> {send_to: 'AW-477262169/oJzUCMbUq-sBENniyeMB', value: 4180, currency: 'TWD', transaction_id: 'ecc12fe2-54ae-47a1-9847-e472dc289e74'}
> fire google checkout conversion
> fire tagtoo checkout conversion
> fire yahoo checkout conversion
trackPayment
- tracker(‘addShippingInfo’, cart)
程式碼的觸發
// 付款方式事件
const trackPayment = new Event({
name: 'trackPayment',
// 網只有 step2 觸發事件
trigger: routeChange.path.contains('/cart/step2').and(routeChange.host.eq('www.eslite.com')),
delay: 2000,
runOnce: true,
fn: () => {
// 宣告一個函式 - 購物車物流
const trackShippingInfo = () => {
// 讀取我們剛剛存擋的購物車
const cart = Cart.load()
// 宣告物流的方法
const methods = {
'7-ELEVEN': '711',
全家: 'cvs',
宅配: 'drop_shipping',
門市: 'in_store',
以外: 'drop_shipping',
捐書: 'drop_shipping',
}
// 收取貨物的方法
const selectedShipping = document.querySelector('.cart-options-block .radio-option.active').title
// 購物車的運送方式 = 這一段的意思就是要用 selectedShipping 這個變數,找到 methods 對應的 key 值
cart.shippingMethod = Object.entries(methods).find(([method]) => selectedShipping.includes(method))[1]
// 送出tracker
tracker('addShippingInfo', cart)
}
// 宣告一個函式 - 購物車金流
const trackPaymentInfo = () => {
// 讀取購物車資料
const cart = Cart.load()
// 抓到選擇的金流方式
cart.payment = document.querySelector('#step2-box-payment .radio-option.active').title
// 送出tracker
tracker('addPaymentInfo', cart)
// 購物車儲存
cart.save()
// yahoo 渠道格式
const cartData = cart.toYahoo()
// 送一份到微軟
sendUETCustomEvent('ecommerce', 'AddPaymentInfo', cartData.skus, cartData.value)
}
// 確認結帳按鈕
const $placeOrderButton = document.querySelector('.summary-item button[type="submit"]')
// 判斷按鈕一開始有沒有綁定事件,沒有的話一開始false
if ($placeOrderButton && !$placeOrderButton._tg_event_bind) {
$placeOrderButton.addEventListener('click', () => {
// 觸發兩個tracker
trackShippingInfo()
trackPaymentInfo()
})
// 綁定事件
$placeOrderButton._tg_event_bind = true
}
},
})
印出來的 console
> fire all addShippingInfo (9b7a6513-deab-40c8-a210-91c275ca5a49)
> Cart {products: Array(1), total: 379, tax: 0, shipping: 0, currency: undefined, …}
> send gtag event 'add_shipping_info' to ["AW-477262169"]
> {transaction_id: undefined, value: 379, shipping: 0, currency: 'TWD', coupon: undefined, …}
> fire google addShippingInfo event
> fire tagtoo addShippingInfo event
trackPurchase
- tracker(‘purchase’, cart)
程式碼的觸發
// 完成購買事件
const trackPurchase = new Event({
name: 'trackPurchase',
// 網址有 step3 觸發事件
trigger: routeChange.path.contains('/cart/step3').and(routeChange.host.eq('www.eslite.com')),
delay: 1500,
fn: () => {
// 宣告變數
const storageKeyName = '_sent_trans_ids'
// 儲存商店ID
const storeIds = storage.get(storageKeyName, [])
// 儲存訂單ID - 完成訂單的時候,網址會有有該筆訂單的ID,把他抓下來
const orderId = location.search.match(/orderid=(\d+)/).pop()
// 如果今天商店ID裡面沒有訂單的ID,那就做以下的事情
if (storeIds.indexOf(orderId) === -1) {
// 讀取購物車
const cart = Cart.load()
// 設定購物車的訂單ID
cart.orderId = orderId
// 送出 tracker
tracker('purchase', cart)
// yahoo 渠道格式
const cartData = cart.toYahoo()
// 送一份到微軟
sendUETCustomEvent('ecommerce', 'Purchase', cartData.skus, cartData.value)
// 購物車清空
Cart.clear()
// 把訂單ID塞進商店ID裡面
storeIds.push(orderId)
// storage.set 是將程式碼存在瀏覽器的方式,這一段是將 storeIds 陣列以 storageKeyName 變數名存在瀏覽器中,有效期是30小時
storage.set(storageKeyName, storeIds, 60 * 60 * 30)
}
},
})
印出來的 console
> fire all purchase (f458da53-2030-496d-bb06-fce059fad465)
> Cart {products: Array(2), total: 1213, tax: 0, shipping: 0, currency: undefined, …}
> fire facebook purchase event
> send gtag event 'purchase' to ["AW-477262169"]
> {transaction_id: '2398315', value: 1213, shipping: 0, currency: 'TWD', coupon: undefined, …}
> fire google purchase event
> tagtoo.tracker.event(): Purchase, [object Object]
> fire tagtoo purchase event
> fire yahoo purchase event
> fire facebook purchase conversion
> send gtag event 'conversion' to "AW-477262169/9friCJnMkOkBENniyeMB"
> {send_to: 'AW-477262169/9friCJnMkOkBENniyeMB', value: 1213, currency: 'TWD', transaction_id: '2398315'}
> fire google purchase conversion
> fire tagtoo purchase conversion
> fire yahoo purchase conversion
trackRegister
- tracker(‘register’, ‘phone’)
- sendUETCustomEvent(‘ecommerce’, ‘Register’, ‘phone’, 1)
程式碼的觸發
const trackRegister = new Event({
name: 'trackRegister',
trigger: routeChange.path.contains('/registry/complete').and(routeChange.host.eq('www.eslite.com')),
delay: 1500,
fn: () => {
tracker('register', 'phone')
sendUETCustomEvent('ecommerce', 'Register', 'phone', 1)
},
})
印出來的 console
> fire all register (694ffe23-987e-4be7-9d11-86ed0f2cbde4)
> phone
> fire facebook register event
> send gtag event 'sign_up' to ["AW-477262169"]
> {method: 'phone', send_to: Array(1), currency: 'TWD'}currency: "TWD"method: "phone"send_to: ['AW-477262169'][[Prototype]]: Object
> fire google register event
> fire yahoo register event
> fire facebook register conversion
> send gtag event 'conversion' to "AW-477262169/MZErCN7juesBENniyeMB"
> {send_to: 'AW-477262169/MZErCN7juesBENniyeMB', value: undefined, currency: 'TWD', transaction_id: '96914b6e-5786-4e61-b690-05b00635f03e'}
> fire google register conversion
> fire tagtoo register conversion
> fire yahoo register conversion
trackLogin
- tracker(‘login’, { label: ‘phone’ })
程式碼觸發
// 登入事件
const trackLogin = new Event({
name: 'trackLogin',
// 網址有login會觸發
trigger: routeChange.path.contains('/login').and(routeChange.host.eq('www.eslite.com')),
delay: 1500,
fn: () => {
// 找到按鈕
const $loginBtn = document.querySelector('button')
logger($loginBtn._tg_event_bind, "========")
// 綁定事件 - 一開始因為沒綁定事件,先讓按鈕的事件是false,並用!來讓他變成true
if ($loginBtn && !$loginBtn._tg_event_bind) {
// 按下按鈕的時候
$loginBtn.addEventListener('click', () => {
// 宣告變數
let isValid = true
// 登入的兩個欄位
const $formInputs = document.querySelectorAll('input.form-control')
// 兩個欄位跑迴圈,如果其中一個欄位沒有填寫,就把 isValid 設定為 false
$formInputs.forEach(function ($input) {
if ($input.value.length === 0) {
isValid = false
}
})
// isValid 要是 true 才送 tracker
if (isValid) {
tracker('login', { label: 'phone' })
}
})
// 點擊按鈕後,綁定事件
$loginBtn._tg_event_bind = true
}
},
})
印出來的 console
> fire all login (d4fb832b-827c-4a4d-b0ce-7c47c0e7ca99)
> {label: 'phone'}
> send gtag event 'login' to ["AW-477262169"]
> {method: '[object Object]', send_to: Array(1), currency: 'TWD'}
> fire google login event
trackSearch
- tracker(‘search’, searchKey)
程式碼觸發
// 搜尋事件
const trackSearch = new Event({
name: 'trackSearch',
// 網址有 Search 的時候,會觸發事件
trigger: routeChange.path.contains('/Search').and(routeChange.host.eq('www.eslite.com')),
delay: 1500,
fn: () => {
// 宣告變數
const $titleTag = document.querySelector('title')
// 確認之前是否有綁定事件
if (!$titleTag._tg_event_bind) {
// 這一段的意思是,會解析網站的連結,location.search 會找到 search 後面的部分,.match(/keyword=([^&]+)/) 是正規表達式,找到keyword的詞
const searchKey = decodeURIComponent(location.search.match(/keyword=([^&]+)/).pop())
// 送出 tracker 事件
tracker('search', searchKey)
// 送出微軟事件
sendUETCustomEvent('ecommerce', 'Search', searchKey, 1)
}
// 綁定事件
$titleTag._tg_event_bind = true
},
})
印出來的 console
> fire all search (114e6490-ea43-4510-8bfc-5294856bb351)
> 歷史
> fire facebook search event
> send gtag event 'search' to ["AW-477262169"]
> {search_term: '歷史', send_to: Array(1), currency: 'TWD'}
> fire google search event
> fire yahoo search event
> fire facebook search conversion
> send gtag event 'conversion' to "AW-477262169/Fb2QCL_uq-sBENniyeMB"
> {send_to: 'AW-477262169/Fb2QCL_uq-sBENniyeMB', value: undefined, currency: 'TWD', transaction_id: '69c2fec9-a97a-462c-b160-2930cca4741c'}
> fire google search conversion
> fire tagtoo search conversion
> fire yahoo search conversion
trackExhibitions
- tracker(addToCart, new Product({ title, sku, price }))
- tracker(addToWishlist, new Product({ title, sku, price }))
程式碼觸發
// 觸發事件
const trackExhibitions = new Event({
name: 'trackExhibitions',
// 觸發連結
trigger: routeChange.path.contains('/exhibitions'),
delay: 1500,
fn: () => {
// 宣告一個函式 - 這個函式會抓取點到的東西
const bindTrackingEvent = (e) => {
const target = e.target
const $item = target.closest('div.card')
const title = $item.querySelector('.desc').title
const pID = $item.querySelector('a').href.split('/').pop()
const sku = `${ecName}:product:${pID}`
const price = $item.querySelector('.slider-price').textContent.replace(/\D/g, '')
tracker(e.currentTarget._tg_event_name, new Product({ title, sku, price }))
}
// 加入購物車按鈕
const $addToCartBtns = document.querySelectorAll('.small-cart-and-wish-btn button:first-of-type, .cart-btn')
// 家務許願清單按鈕
const $addToWishlistBtns = document.querySelectorAll('.wish-btn, .small-cart-and-wish-btn button:nth-child(2)')
$addToCartBtns.forEach(($btn) => {
// 判斷目前有沒有綁定事件
if (!$btn._tg_event_name) {
// 綁定 addToCart 事件
$btn._tg_event_name = 'addToCart'
// 點擊按鈕、觸發上面的函式
$btn.addEventListener('click', bindTrackingEvent)
}
})
$addToWishlistBtns.forEach(($btn) => {
if (!$btn._tg_event_name ) {
// 綁定 addToWishlist 事件
$btn._tg_event_name = 'addToWishlist'
// 點擊按鈕、觸發上面的函式
$btn.addEventListener('click', bindTrackingEvent)
}
})
},
})
印出來的 console
加入許願清單
> fire all addToWishlist (e3b194db-47b2-4c02-948f-0ab0ca8b2d23)
> Product(7) {'advertiserId' => 1655, 'title' => "I'm So Happy You're Here: A Little Book About Why You're Great", 'sku' => 'eslite:product:1001283452682184591000', 'link' => 'https://www.eslite.com/exhibitions/CU202011-01219', 'price' => 299, …}
> fire facebook addToWishlist event
> send gtag event 'add_to_wishlist' to ["AW-477262169"]
> {items: Array(1), value: 299, currency: 'TWD', send_to: Array(1)}
> fire google addToWishlist event
> fire yahoo addToWishlist event
加入購物車
> fire all addToCart (47bccdd6-178e-49a9-880a-2fccbd64fa64)
> Product(7) {'advertiserId' => 1655, 'title' => "I'm So Happy You're Here: A Little Book About Why You're Great", 'sku' => 'eslite:product:1001283452682184591000', 'link' => 'https://www.eslite.com/exhibitions/CU202011-01219', 'price' => 299, …}
> fire facebook addToCart event
> send gtag event 'add_to_cart' to ["AW-477262169"]
> {items: Array(1), value: 299, currency: 'TWD', send_to: Array(1)}
> fire google addToCart event
> tagtoo.tracker.event(): AddToCart, [object Object]
> fire tagtoo addToCart event
> fire yahoo addToCart event
> fire facebook addToCart conversion
> send gtag event 'conversion' to "AW-477262169/LU6WCOfUuesBENniyeMB"
> {send_to: 'AW-477262169/LU6WCOfUuesBENniyeMB', value: 299, currency: 'TWD', transaction_id: 'd75d7a32-db52-45f0-a7d3-166d74792876'}
> fire google addToCart conversion
> fire tagtoo addToCart conversion
> fire yahoo addToCart conversion