כולנו מכירים את הטרנד של אתרי ה-Single Page Application (SPA) – הם נטענים מהר, מעבירים את הגולש מעמוד לעמוד בצורה חלקה מבלי לטעון את הדף שוב ושוב, והרבה אתרים חדשים אוהבים להשתמש בזה כדי לשפר את חווית המשתמש.
העניין הוא, שאם אתם רוצים להטמיע את גוגל אנליטיקס באתר מבוסס SPA אתם עלולים להתקל בקשיים, על אחת כמה וכמה אם אתם רוצים להטמיע את גוגל אנליטיקס דרך גוגל תג מנג’ר – ועל זה בדיוק אנחנו הולכים לדבר בפוסט הקרוב.
השפות הפופולאריות שמשמשות את אתרי ה-SPA הן React ו-Angular, אבל הרעיון שעומד מאחריהן זהה ולכן הפוסט הזה רלוונטי גם אם אתר ה-SPA שלכם נכתב בשפה אחרת.
על פי ויקיפדיה, זו ההגדרה של Single Page Applications (שימו לב שהדגשתי את הדברים שנוגעים אלינו):
A single-page application (SPA) is a web application or web site that fits on a single web page with the goal of providing a user experience similar to that of a desktop application. In an SPA, either all necessary code – HTML, JavaScript, and CSS – is retrieved with a single page load,[1] or the appropriate resources are dynamically loaded and added to the page as necessary, usually in response to user actions. The page does not reload at any point in the process, nor does control transfer to another page, although the location hash or the HTML5 History API can be used to provide the perception and navigability of separate logical pages in the application.[2] Interaction with the single page application often involves dynamic communication with the web server behind the scenes.
ופה בדיוק ה-בעיה.
באתר רגיל, כאשר אתם מטמיעים את הסקריפט של התג מנג’ר בראש קוד ה-HTML, הדפדפן יטען אותו בכל פעם שעמוד כלשהוא יטען.
למשל – כאשר אתם מקלידים בשורת ה-URL את הכתובת lixfix.co.il, הדפדפן שלכם הולך לשרת המתאים ומבקש ממנו את הקובץ index.html.
בקובץ הזה מופיע הסקריפט של התג מנג’ר (כי הטמעתם אותו בראש הקוד, זוכרים?), וכאשר הדף נטען – הקוד של ה-GTM נטען ביחד איתו ומיד יורה את תג ה-pageview הרגיל של גוגל אנליטיקס.
כאשר אתם עוברים לעמוד אחר, כמו עמוד צור קשר למשל, הדפדפן שוב פעם מבקש מהשרת את קוד ה-HTML שמתאים לעמוד הזה, בראש הקוד הזה שוב פעם מופיע הסקריפט של התג מנג’ר, ככה שגם עכשיו הדפדפן טוען את הדף ביחד עם ה-GTM ושולח את ה-pageview לגוגל אנליטיקס.
אבל מה קורה כשהעמוד לא נטען מחדש, כמו למשל באתרי SPA?
שאלה מצויינת, כי פה בדיוק נוצרת הבעיה.
כפי שראינו קודם, אתרי SPA טוענים את ה-HTML רק בנחיתה של הגולש, כי במעבר בין הדפים הבאים הם פשוט מחליפים את התוכן של העמוד באופן דינמי, מבלי לטעון את העמוד מחדש.
שימו לב להמחשה שיצרתי – בשורה העליונה ניתן לראות שבמעבר בין עמודים כל הקוד של האתר נטען שוב ושוב (כולל התוכן החדש), ואילו בשורה התחתונה רק הקוד של התוכן עצמו משתנה:
ומה התוצאה?
מכיון שהתג מנג’ר נטען רק בעמוד הראשון של הביקור – ה-pageview יישלח לגוגל אנליטיקס רק בעמוד הראשון ולא בעמודים הבאים.
אגב, גם אם אתם לא משתמשים באתר HTML רגיל אלא במערכת ניהול תוכן (CMS) כמו וורדפרס, מערכת ה-CMS יוצרת עבורכם את קוד ה-HTML בכל פעם שהעמוד נטען מחדש ככה שלמעשה זה אותו דבר בדיוק.
אז מה עושים כדי לשלוח את גוגל אנליטיקס בכל הדפים?
ישנם 2 פתרונות אפשריים לבעיה הזו:
פתרון 1: אומרים למתכנת לשלוח איוונט בכל פעם שהוא מזהה מעבר בין “דפים”
אמרנו כבר שבאתרי SPA אין מעבר אמיתי בין דפים כי התוכן נטען באופן דינמי, אבל העקרון פה הוא שבכל פעם שהמתכנת מזהה שהגולש טוען “עמוד” אחר – הוא ידחוף איוונט לדטאלייר, ואת האיוונט הזה אנחנו מגדירים בתור טריגר לתג האנליטיקס שלנו, בנוסף לטריגר הרגיל של All Pages.
האיוונט יישלח על ידי המתכנת באופן הבא:
1 | dataLayer.push({'event':'virtualPageview'}) |
הטריגר יוגדר בצורה כזו:
ואז נלביש את שני הטריגרים על התג שלנו:
מה שיקרה זה שכאשר הגולש נוחת באתר, מה שיפעיל את תג האנליטיקס זה הטריגר הרגיל של All Pages, ובמעבר בין ה”עמודים” (שכבר אמרנו שהם לא עמודים אמיתיים ולכן ה-GTM לא נטען שוב) מה שיפעיל אותו יהיה הטריגר של האיוונט, שכאמור יישלח באופן ידני על ידי המתכנת.
פתרון 2: שימוש ב-history Listener
כדי להבין את זה אני אתן הקדמה קצרה:
מכיוון שאתרי SPA לא באמת מעבירים את הגולש מעמוד אחד לשני, נוצרת בעייה מבחינת היוזר ומבחינת האינדוקס של התוכן בגוגל –
היוזר לא יכול לנווט אחורה/קדימה בין העמודים כי ה-URL נשאר כל הזמן אותו דבר, וגוגל לא יכולה לאנדקס את התוכן על פי URL-ים כי כל התוכן נמצא תחת אותו URL.
מהסיבה הזו, אתרי SPA משתמשים בד”כ ב-History API שמאפשר להם לשנות באופן מלאכותי את ה-URL המוצג בדפדפן, וזה גם משנה את ההיסטוריה של הדפדפן כדי שידע לאן להעביר את הגולש בזמן לחיצה על back או forward.
אם תכתבו את השורה הזו ב-console של הדפדפן תוכלו לראות שה-URL של הפוסט השתנה ל-https://www.lixfix.co.il/google-analytics-and-tag-manager-in-single-page-application/hello, ואם תעשו back אתם תחזרו ל-URL המקורי ולא תחזרו למקום שממנו הגעתם לפוסט הזה (פייסבוק למשל):
1 | history.pushState(null, null, 'hello'); |
ואיך זה נוגע אלינו?
כמו שאתם בטח יודעים, בגוגל תג מנג’ר יש listeners שעוזרים לנו לעקוב אחרי אירועים כמו קליק, טופס שנשלח וכד’, ואחד מהליסטנרים הללו הוא historyListener.
בגדול, הליסטנר הזה מאזין לשינויים שקרו ב-history של הדפדפן, ובכל פעם ששינוי כזה קורה הוא דוחף לדטאלייר איוונט בשם gtm.historyChange:
בצורה כזו, בכל פעם שהגולש עובר מ”עמוד” ל”עמוד” באתרי SPA, ההיסטוריה של הדפדפן תשתנה, והליסטנר שלנו יאפשר לנו להלביש את תג ה-pageview גם בעמודים הדינמיים.
א-ב-ל,
מסתבר שזה לא עובד פיקס מכל מיני סיבות שקשורות לאופן העבודה של אתרי ה-SPA, ולכן מנסיוני לא כדאי להסתמך על ה-historyChange Listener בתור טריגר לשליחת Pageviews, אלא לנקוט בשיטה הראשונה שמערבת את המתכנתים.
בנוסף לנ”ל, כדאי לשלוח Virtual Pageview
בנוסף לקיסטום הטריגר ששולח את התג, כדאי לדחוף באופן ידנית ערך לפרמטר page תחת fields to set שישלח את כתובת ה-URL האמיתית.
בכל פעם שהקוד של גוגל אנליטיקס נטען בעמוד (ולא משנה אם זה hard coded או דרך התג מנג’ר), הוא יוצר טראקר שמכיל מידע על ה-document location (להלן dl), כלומר ה-URL שבו הגולש נמצא כרגע, ומה-dl הזה נגזר ה-URL שנשלח לאנליטיקס ב-pageview או ב-event.
אז בעמוד שבו הגולש נחת הכל טוב ויפה, אבל בעמודים הבאים, מכיוון שהקוד של גוגל אנליטיקס לא נטען שוב – הוא משתמש באותו טראקר שהיה בהתחלה ושולח את אותו URL!
חשוב לציין שזה נכון רק באתרי SPA שבהם הקוד של GA מוטמע ישירות בעמוד, כיוון שבאתרים בהם הקוד מוטמע עם תג מנג’ר נוצר טראקר חדש עם כל תג שנשלח, והטראקר הזה אמור לקחת את ה-URL המעודכן ולשלוח אותו.
מהסיבה הזו, אם קוד האנליטיקס שלכם מוטמע hard coded אתם חייבים לשלוח virtual pageview, ואם הוא מוטמע עם תג מנג’ר זה רק בגדר המלצה.
עד כאן החלק הפשוט – עכשיו נכנס להגדרות מורכבות יותר
אם הגעתם לכאן רק כדי לדעת איך לשתול את גוגל אנליטיקס באתרי SPA – דיינו.
אבל אם יש לכם הטמעה קצת יותר מורכבת, ואתם משתמשים בפיצ’רים כמו Custom Dimensions, Custom Metrics או אפילו אם אתם סתם משתמשים באיוונטים או מביאים טראפיק מאדוורדס או ממקורות שעושים שימוש ב-UTM – אתם בצרות.
בעיית מקורות תנועה באתרי Single Page Application
כולכם בטח מכירים את דוח מקורות התנועה בגוגל אנליטיקס. נראה לי שזה הדוח הכי נפוץ, שכל מי שמשתמש במערכת נכנס אליו לפחות פעם בשבוע כדי לדעת מאיפה הגולשים שלו מגיעים.
אבל איך גוגל אנליטיקס יודעת מאיפה הגולש שלנו הגיע?
אני לא אכנס לזה לעומק כרגע (דיברתי על זה בהרחבה גם בפוסט הזה), אבל בגדול גוגל אנליטיקס לוקחת את ה-document location שדברנו עלינו קודם, ובודקת אם הוא מכיל פרמטר של gclid (=תנועה מאדוורדס) או UTM (=תנועה מתוייגת).
במידה והוא לא מכיל את אחד מהנ”ל, היא עוברת לבדוק מה מופיע במשתנה בשם document.referrer, שבד”כ מכיל את כתובת ה-URL שממנה הגענו לעמוד הנוכחי.
למשל: באתר רגיל, כאשר גולש מגיע מקמפיין אדוורדס, יש לו פרמטר gclid ב-document location שגורם לאנליטיקס לסווג אותו תחת מקור תנועה google / cpc. כאשר הגולש יעבור לעמוד אחר באותו אתר, יווצר טראקר חדש עם document location חדש (שמכיל את העמוד החדש b.html ללא הפרמטר של gclid), וכשגוגל אנליטיקס תבדוק את ה-document.referrer היא תראה שהוא זהה לדומיין שבו הגולש נמצא כרגע, ולכן תתיחס לזה כאל סשן אחד, ו”תשמור” על מקור התנועה המקורי:
לעומת זאת, אם אותו גולש היה מגיע מאדוורדס לאתר SPA, בואו נראה מה היה קורה:
הגולש נוחת בעמוד הראשון עם פרמטר gclid, נוצר טראקר שמכיל document location עם פרמטר gclid, ולכן גוגל אנליטיקס תייחס לגולש את מקור התנועה google / cpc – עד כאן הכל סבבה.
כאשר הגולש יעבור ל”עמוד” הבא, התג של אנליטיקס יישלח שוב פעם (בגלל הטריגר המיוחד שיצרנו בחלק הראשון של הפוסט, זוכרים?). כמו כן יווצר טראקר חדש שמכיל document location חדש, אבל ליתר בטחון נשלח virtual pageview עם עמוד b.html.
[שימו לב שהטראקר נוצר שוב רק בגלל שאנחנו עם GTM. בהטמעה hard coded הטראקר ישאר אותו דבר ותהיה לנו בעיה אחרת, אבל זה כבר לפוסט אחר]
עכשיו גוגל אנליטיקס הולכת לבדוק מה מקור התנועה של עמוד b.html:
האם יש פרמטרים ב-document location? שלילי. עוברת לבדיקה הבאה.
מה יש ב-document.referrer? אהה, הוא מכיל google.com ואין gclid ולכן גוגל אנליטיקס תתן לביקור הזה מקור תנועה google / organic!
בנוסף, מכיוון שמקור התנועה השתנה מ-google / cpc ל-google / organic, עמוד b.html יספר בתור סשן חדש ונקבל פיצול סשנים!
אם זה לא היה ברור מספיק אני אסכם את זה במשפט אחד – מכיוון שבאתרי SPA העמוד הבא לא באמת נטען, הרפרל (document.referrer) המקורי לא משתנה ולכן גורם לקטיעת סשנים ושיבושים בדוח מקורות התנועה כאשר מדובר בטראפיק שמגיע מאדוורדס או עם פרמטרים של UTM.
מה עושים כדי לפתור?
כשהתמודדתי עם הנושא בפעם הראשונה, שמרתי את ה-UTM ואת ה-gclid בנפרד ואז שלחתי אותם בתור פרמטרים ביחד עם תג האנליטיקס. זה אמנם עבד מצוין, אבל ברוב המקרים אתם תשתמשו ב-UTM / gclid סטנדרטיים ולכן הפתרון הבא יהיה הרבה יותר פשוט עבורכם:
הוסיפו תג מסוג Custom HTML, ושימו בו את הקוד הבא:
1 2 3 | <script> if (!fullURL) var fullURL = window.location.href.split('#')[0]; </script> |
לאחר מכן צרו variable מסוג JS Variable שיקח את הערך מהמשתנה fullURL:
כעת דחפו את המשתנה באופן ידני ל-document location (באמצעות השדה location תחת fields to set) בכל פעם שהתג של האנליטיקס (pageview או events) שלכם נשלח:
ולבסוף הגדירו את התג של ה-Custom HTML בתור Setup Tag לתג של האנליטיקס, כדי לוודא שהמשתנה הזה יהיה זמין עוד לפני שהתג של האנליטיקס יישלח:
כאשר הגולש יגיע עם gclid או UTM לעמוד הראשון, ה-Custom HTML Tag יישלח וישמור את ה-URL המלא, כולל הפרמטרים, בתוך משתנה JavaScript (רק במידה והמשתנה לא קיים כבר, כלומר רק בעמוד הראשון). לאחר מכן יישלח התג של האנליטיקס, שישתמש במשתנה שיצרנו וידחוף אותו בתור ה-document location.
מה שיקרה זה שגוגל אנליטיקס יקח את מקור התנועה מה-location הקבוע ולא ילך לחפש אותו ב-document.referrer.
קיצור זמן באמצעות Google Analytics Settings variables
את השדה של location (וכמובן גם את ה-page) עליכם להוסיף בכל אחד מהתגים שקשורים לגוגל אנליטיקס, אבל כדי שלא תצרכו לעבוד קשה מדי תוכלו להשתמש בפיצ’ר החדש של Google Analytics Settings variables.
כל שעליכם לעשות הוא לפתוח את הדרופ דאון של Google Analytic Settings:
להגדיר את ההגדרות שאתם רוצים להחיל על כל התגים, בדיוק כפי שהייתם עושים את זה אילו היה מדובר בתג בודד (במקרה שלנו מדובר במספר המזהה של האנליטיקס, ה-virtual pageview ועכשיו גם השליחה של ה-location):
ואז לחזור לתג שלכם ולבחור את ה-variable החדש:
וזהו.
סיכום
הפוסט יצא ארוך, אבל זה לא בגלל שהפתרון מסובך אלא פשוט בגלל שרציתי להסביר לכם בצורה מפורטת איך הדברים עובדים, כדי שלא תעשו סתם כמו תוכים.
האמת היא שבהתחלה רציתי להוסיף עוד חלק שמדבר על ה-scopes של Custom Dimensions/Metrics בעבודה עם גוגל תג מנג’ר, אבל זה נושא חשוב שדורש פוסט בפני עצמו, אז פשוט תרשמו לניוזלטר כדי שלא תפספסו אותו כשהוא יצא 😉
* עדכון: עידן בן אור האלוף כתב פוסט משובח על קידום אורגני של אתרי אנגולר – ממליץ לכם לקרוא אותו
קודם כל – תודה על המאמר! לא הצלחתי למצוא מקור מספיק טוב ע”מ לפתור את הבעיה.
יש לי שאלה (ועוד כמה) – האם במצב preview אני אמור לראות את התג אנליטיקס נורה לאחר כל ‘מעבר עמוד’?
במידה והטמעת את האיוונט באמצעות dataLayer.push כמו שהראיתי
סגור, תודה רבה!
אגב, אם אני לא טועה בשורה:
dataLayer.push({‘event’:’virtualPageview’})
יש רק את קטגוריה בעוד שגם action הוא required, בJS זה יעבוד, האם זה פתיר בשימוש בריאקט?