一、背景
相信很多人都接觸過**“埋點”這個概念,無論是前端還是后端開發,我們都可以使用這門技術來生產出一些運營性質的原始資料(介面耗時、程式安裝/啟動、用戶互動行為等等),然后分析它們得到一些抽象指標(例如留存率、轉化率),進而決定產品運營或者代碼優化的方向,現在業界有許多比較知名資料平臺,比如Google Analytics、Facebook Pixel、Mixpanel、GrowingIO、諸葛IO、TalkingData、神策資料等數不勝數一大票,這些平臺有單純做資料分析的,也有服務于特定領域例如廣告監測轉化的,都提供了多端(Android、iOS、Web、小程式、ReactNative)的埋點SDK和比較全面的BI服務,這一兩年,不少平臺都開始宣傳一種叫“無埋點”**的技術,下面以Web端為例,揭開它的神秘面紗,
二、什么是無埋點?
**“無埋點”在國外一些平臺被叫做Codeless Tracking,顧名思義就是可以寫“更少”的埋點代碼,而“代碼埋點”**一般需要開發人員撰寫代碼,監聽某個html元素的產生的事件,然后呼叫上報資料的介面,發送資料,而無埋點則可以由非技術人員(例如運營、產品),在可視化的工具中作出配置,然后就可以將html元素中產生的行為上報到后臺,下面是Mixpanel平臺的可視化工具的截圖,
在這個工具里,需要首先輸入頁面的url,頁面加載完成后,會出現可視化配置的工具條,點擊創建事件,就可以進入元素選擇模式,用滑鼠點擊頁面上的某個元素(例如button、a這些element),就可以在彈出的對話框里面,設定這個事件的名稱(比如叫TEST),保存這個配置之后,如果頁面在瀏覽器中被瀏覽,剛才配置的那個按鈕發生點擊時,就會向后臺上報一個TEST事件,我們還可以設定上報TEST事件的時候,帶上一些屬性(properties),這些屬性同樣也是在頁面中用滑鼠去選擇,然后保存起來的,
看到這里,首先從產品層面上,我們比較具體的了解到“無埋點”到底是干什么的了,無埋點就是用可視化工具配置頁面中需要被監測的元素,并設定這個元素產生行為的時候需要上報的資料,但是還有非常關鍵的一點必須提到,要讓“無埋點”作業起來,頁面里面還是必須嵌入了一段JS SDK的基礎代碼,只是不需要再去呼叫SDK具體的資料上報介面罷了,
所以,“無埋點”技術的關鍵是:
- 操作可視化配置工具,保存配置
- SDK基礎代碼如何根據配置上報行為
下面介紹一下如何實作這兩個關鍵,
三、關鍵技術
1. 基礎代碼
和代碼埋點一樣,要讓“無埋點”作業起來,網頁里也必須有一段“基礎代碼”,
<!-- start Mixpanel --><script type="text/javascript">(function(e,a){if(!a.__SV){var b=window;try{var c,l,i,j=b.location,g=j.hash;c=function(a,b){return(l=a.match(RegExp(b+"=([^&]*)")))?l[1]:null};g&&c(g,"state")&&(i=JSON.parse(decodeURIComponent(c(g,"state"))),"mpeditor"===i.action&&(b.sessionStorage.setItem("_mpcehash",g),history.replaceState(i.desiredHash||"",e.title,j.pathname+j.search)))}catch(m){}var k,h;window.mixpanel=a;a._i=[];a.init=function(b,c,f){function e(b,a){var c=a.split(".");2==c.length&&(b=b[c[0]],a=c[1]);b[a]=function(){b.push([a].concat(Array.prototype.slice.call(arguments,
0)))}}var d=a;"undefined"!==typeof f?d=a[f]=[]:f="mixpanel";d.people=d.people||[];d.toString=function(b){var a="mixpanel";"mixpanel"!==f&&(a+="."+f);b||(a+=" (stub)");return a};d.people.toString=function(){return d.toString(1)+".people (stub)"};k="disable time_event track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config reset opt_in_tracking opt_out_tracking has_opted_in_tracking has_opted_out_tracking clear_opt_in_out_tracking people.set people.set_once people.unset people.increment people.append people.union people.track_charge people.clear_charges people.delete_user".split(" ");
for(h=0;h<k.length;h++)e(d,k[h]);a._i.push([b,c,f])};a.__SV=1.2;b=e.createElement("script");b.type="text/javascript";b.async=!0;b.src="undefined"!==typeof MIXPANEL_CUSTOM_LIB_URL?MIXPANEL_CUSTOM_LIB_URL:"file:"===e.location.protocol&&"//cdn4.mxpnl.com/libs/mixpanel-2-latest.min.js".match(/^\\/\\//)?"https://cdn4.mxpnl.com/libs/mixpanel-2-latest.min.js":"//cdn4.mxpnl.com/libs/mixpanel-2-latest.min.js";c=e.getElementsByTagName("script")[0];c.parentNode.insertBefore(b,c)}})(document,window.mixpanel||[]);
mixpanel.init("46042714e64a7536dde6f02af1aec923");</script><!-- end Mixpanel -->
上面是Mixpanel平臺的基礎代碼,不同平臺家的這段基礎代碼,大同小異,都是一段IIFE形式的、壓縮過的js代碼,執行完成之后,在head里面插入了一個新的script標簽,異步去下載真正的核心SDK代碼下來作業,所以并不是基礎代碼可以根據配置上報行為,而是基礎代碼會下載一段**“更大”**的SDK核心代碼,這段代碼才是SDK真正的功能實作,
這樣子做的好處是,基礎代碼很短,加載的時候不會影響到網頁的性能,而且核心SDK代碼的更新也不需要用戶去更新這段基礎代碼,
2. 頁面的唯一標識
在配置元素行為的時候,需要唯一標識一個頁面,這樣才能保證A頁面的配置,不會下發給在B頁面,不會導致B頁面產生出A頁面里配置的行為,在Web里面標識頁面靠的是url,url由protocol、domain、port、path和引陣列成,存盤配置的時候要將url的引數提出來再存,而url的引數位置是可以變化的,比如urlA(http://a.b.com/c.html?pa=1&pb=2)和urlB(http://a.b.com/c.html?pb=2&pa=1)雖然urlA !== urlB,但是其實它們是一個頁面,
3. 元素的唯一標識
唯一標識頁面后,接下來就要唯一標識頁面里面的元素,這樣才能保證A頁面中配置的元素A1可以被SDK找到,從而監聽它產生的事件,
在html里面,元素是以DOM Tree組織的,如果沿著元素A1出發,一直向上記錄它的parent和它在parent中的index,直到根節點body,那么就可以得到元素A1在DOM Tree中的唯一路徑,
html的元素還會擁有很多屬性,例如css class、id可以用來定位元素,通過Chrome開發者工具可以看到Mixpanel的可視化工具在配置元素的時候,使用的是https://github.com/Autarc/optimal-select這個庫來生成element的唯一標識的,而Github上還有https://github.com/rowthan/whats-element這樣的庫,也可以生成元素在DOM Tree中的唯一標識,
此外,還有平臺在標識元素的時候,采用了xpath,這也是一個思路,
4. 如何查找元素
上面說到元素可以有唯一標識,那么有了唯一標識,就可以利用它的原理,找到這個元素,有一個很好用的API是document.querySelector(),這個API可以根據CSS選擇器找到對應的元素,此外,根據元素的標識方法,還可以使用document.getElementById()、document.getElementByName()來實作元素的查找,
這里需要重點強調的是,如果頁面在配置完成之后又發生了修改,導致DOM Tree發生變化,此時需要被監測的元素的唯一標識可能也會發生改變,很可能導致根據之前的配置無法找到該元素了,或者找到的并不是我們希望監測的元素,從而導致產生的事件數量發生比較明顯的變化,為了資料的穩定性和準確性,應該設有相應的監測告警處理這種case,并提示用戶去重新配置頁面,我個人認為這是無埋點最大的缺點,
5. 標記元素時的高亮效果和可視化互動實作
這是一個比較細節的點,其實熟悉js的大牛們都知道,有無數種方式去實作滑鼠移動到元素上時的類hover效果,點擊元素后彈出一個對話框,讓用戶輸入配置的資訊也so easy,但是我想說的是,一旦我們采用向頁面中動態添加元素的方式去實作可視化工具的互動界面,那么有可能會破壞掉頁面原來的DOM Tree結構,從而導致生成元素唯一標識的時候出現誤差,所以這里必須要好好處理,保證生成的元素標識不會受到影響,
我看到Mixpanel采用了CustomElement和ShadowDOM,把可視化工具所有的功能都用自定義的Web Component實作了,雖然目前只有Chrome支持Web Component,但是真的有點叼,,這樣自定義的元素和互動不會對用戶的網頁DOM產生影響,當然,如果你的可視化工具實作做的很輕,比如只是將用戶的網頁放在一個iframe里面,大部分互動都交給iframe的parent頁面去處理,那也可以在配置的時候,最小程度的破壞用戶的網頁了,
6. 配置工具中如何控制頁面的跳轉
當進入可視化配置狀態時,我們可以讓用戶點擊一個元素,然后彈一個對話框,讓用戶對這個元素進行配置,此時,如果這個元素本身的click行為是頁面跳轉呢?我們應該怎么處理?
這里本質上是一個互動設計的問題,在可視化配置工具中,應該有兩種基本互動操作,一種是讓用戶選中某一個元素,進行配置;另一種,是讓用戶可以觸發頁面原有的行為,
為什么要有第二種互動?因為我們的工具肯定要支持用戶進行二級頁面的可視化配置對不對?或者說,用戶的頁面中可能會彈出一個對話框,對話框里面有一個按鈕,用戶對監測這個按鈕,對它做配置,對不對?簡單來說,就是用戶頁面中原有的點擊行為,可能會導致頁面結構產生變化,例如跳轉,頁面內彈出對話框等等,
那問題就好解了,除了點擊,再設計一種互動來支持用戶網頁中原有的點擊行為不就好了,用“右鍵點擊”或者“按住shift+點擊”之類都可以,反正不要再和網頁默認的互動很容易產生沖突的方式就行,
最后再提一下,之前想很久沒有想明白,如何能夠能防止用戶點擊的時候頁面產生跳轉,后來才知道,DOM的事件流分三個階段:捕獲、目標、冒泡,所以為了避免用戶的點擊產身頁面跳轉,給document在捕獲階段加一個listener,攔截掉這個事件的繼續分發就行了,
簡單的示例代碼如下:
document.addEventListener('click', e => {
// 如果是按住shift的點擊,那么保持原有的行為
if (e.shiftKey) {
return;
}
// 如果是單純的點擊,那么攔截分發
e.preventDefault();
e.stopImmediatePropagation();
// 獲取元素的唯一標識,然后讓用戶進行配置等等
this._selectElement(e.target);
}, true); // useCapture必須為true
四、總結
可以看到“無埋點”并不是零侵入,用戶的網頁中依然需要加載SDK的代碼(除非你是瀏覽器廠商,可以在加載網頁的時候,給網頁加inject基礎代碼),只是每一個行為事件的上報代碼不需要開發人員手動撰寫,而是由運營人員用可視化工具配置,所以叫它**“可視化埋點”**也許更加合適,我們知道資料采集是資料分析的基礎和先決條件,資料采集做不好,其他的東西都是空中樓閣,
這里可以小結一下“無埋點”技術的優劣,無埋點的好處是技術成本低,對用戶非常友好,不需要重新部署,配置完成就可以生效,但是其缺點也非常明顯,不具有代碼埋點的靈活性和深度,只能采集到用戶肉眼可見的資料,無法獲取記憶體里的資料,同時也無法適應頁面結構的變化,所以在實際生產中,要選擇性地在合適的地方使用無埋點技術,
多扯一點產品設計和技術方案的選擇,產品上是否可以支持采集記憶體資料呢?當然可以,比如微信小程式的“自定義分析”,就可以支持上報頁面data下面的屬性,這時雖然同樣是可視化配置,運營人員肯定不會知道代碼里面的變數名字,必須得有開發人員參與配置才行,關于頁面結構發生變化之后的資料丟失,也是有方案可以破的,比如Mixpanel平臺的Codeless Tracking,實際上采集了頁面中所有頁面的點擊事件上報,然后在后臺再去根據用戶的配置計算轉化數量,這樣做的好處就是如果頁面變化后,用戶接到告警,修改了配置,那么用于資料上報方案是全量的,所以平臺是由能力將過去的資料回溯出來的,而上面我們說的根據配置下發,查找監測指定元素,再上報資料的方案屬于按需上報,資料出現誤差是無法回溯的,不過全量上報資料大家也知道,太不友好了,這個資料量太大,不僅前端消耗資源多,如果為了做資料回溯,后臺的存盤壓力也會加大,而存盤的資料大部分還是無效的,這個成本有點高了,
五、參考資料
- JS埋點技術分析
- https://github.com/Autarc/optimal-select
- https://github.com/rowthan/whats-element
- https://www.zhihu.com/question/38000812
- **本文作者:**unclechen
- 本文鏈接: 2018/06/24/揭開JS無埋點技術的神秘面紗/
- 著作權宣告: 本文采用知識共享 署名-非商業性使用-相同方式共享 4.0 國際 許可協議進行許可,轉載請注明出處!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/252145.html
標籤:其他
