באחד הפרוייקטים האחרונים שלי הלקוח ביקש כי אעביר את ה UTM Parameters איתם מגיע המשתמש מהקמפיינים השונים לעמודים אחרים באתר. אם נדייק, הבקשה הייתה כי אותם פרמטרים יועבר כשהלקוח לוחץ ספציפית על אחד הקישורים או ההנעות לפעולה המובילות לאפליקציה אינטרנטית הנמצאית תחת דומיין אחר.
מכיוון וזו בקשה שכיחה (במיוחד בדפי נחיתה שמכילים CTA לאפליקציה חיצונית), אשתף אתכם בסקריפט בו אני משתמש ואתאר כיצד הוא עובד.
מה הסקריפט עושה?
הסקריפט סורק את כל הקישורים באתר, וכשהוא מוצא קישור המוביל לאותה אפליקציה חיצונית הוא בודק אם הקישור כבר מכיל utm parameters.
אם אלו אינם קיימים בקישור, הוא מוסיף את אותם utm parameters איתם הגיע המשתמש – כלומר את הפרמטרים הקיימים בכתובת ה-URL הנוכחית.
דוגמה תסביר זאת טוב יותר. נניח והגעתי לדף נחיתה כלשהו עם הפרמטרים הבאים:
https://lp.co.il/?utm_source=google&utm_medium=cpc&utm_campaign=name-campaign&utm_term=keyword&utm_content=fb-bannerונניח שקיים בדף הנחיתה קישור כלשהו לאפליקציה שלנו, לצורך הדוגמה בכפתור מסויים קיים הקישור הבא:
https://app.co.il/שימוש בסקריפט זה ישנה קישור זה לקישור הבא:
https://app.co.il/?utm_source=google&utm_medium=cpc&utm_campaign=name-campaign&utm_term=keyword&utm_content=fb-bannerהסקריפט
(function () {
const targetDomain = "app.co.il";
const pageParams = new URLSearchParams(window.location.search);
const utmEntries = [...pageParams.entries()].filter(([key]) => key.startsWith("utm_"));
if (utmEntries.length === 0) return;
document.querySelectorAll("a[href]").forEach(link => {
try {
const url = new URL(link.href);
if (!url.hostname.includes(targetDomain)) return;
utmEntries.forEach(([key, value]) => {
if (!url.searchParams.has(key)) {
url.searchParams.set(key, value);
}
});
link.href = url.toString();
} catch (e) {}
});
})();איך זה עובד
- שורה 2 – הגדירו את
targetDomainלדומיין החיצוני אליו תרצו להעביר את הפרמטרים. רק קישורים התואמים hostname זה ישתנו. - שורות 3-4 – קוראים את כתובת העמוד הנוכחי ומחלצים את כל הפרמטרים שמתחילים ב-
utm_. - שורה 6 – אם אין פרמטרי UTM בכתובת, הסקריפט מסתיים מיידית.
- שורות 8-18 – עוברים על כל קישור
<a>בעמוד. לכל אחד, מפרסרים את ה-URL עםURLconstructor, בודקים את ה-hostname, ומשתמשים ב-searchParams.set()להוספת פרמטרי UTM חסרים.
הסקריפט משתמש ב-URL API במקום שרשור מחרוזות. זה חשוב כי searchParams.set() מטפל אוטומטית ב-URL encoding, מונע כפילויות, וממקם את הפרמטרים לפני hash fragment בצורה נכונה.
אם אתם משתמשים בגוגל תג מנג׳ר, הוסיפו את הסקריפט כתגית Custom HTML והגדירו אותה לרוץ על טריגר DOM Ready. אחרת, מקמו את הסקריפט בסוף ה-body של העמוד.
נקודות חשובות
- הסקריפט משפיע רק על קישורים ל-
targetDomainהמוגדר. כל שאר הקישורים נשארים ללא שינוי. - קישורים שכבר מכילים פרמטרי UTM ידולגו – הסקריפט לא ידרוס attribution קיים.
- בלוק
try/catchמדלג בשקט על קישוריmailto:,tel:וכתובות לא-HTTP אחרות שזורקות שגיאה בפרסור עםURLconstructor. - הסקריפט רץ פעם אחת בטעינת העמוד. אם העמוד מוסיף קישורים דינמית (SPA, AJAX), תצטרכו להריץ את הפונקציה שוב לאחר הוספת הקישורים.
שמירת UTMs בין ניווטים באתר
הסקריפט למעלה עובד כאשר פרמטרי UTM קיימים בכתובת העמוד הנוכחי. אבל מה קורה כשהמשתמש נוחת בדף הבית עם UTMs, מנווט לעמוד פנימי, ורק אז לוחץ על ה-CTA לאפליקציה החיצונית?
הפרמטרים אבדו כי כתובת העמוד הפנימי לא מכילה אותם.
ניתן לפתור זאת עם sessionStorage. הגרסה המשודרגת שומרת את הפרמטרים כשהמשתמש מגיע לראשונה ומחילה אותם בכל עמוד:
(function () {
const targetDomain = "app.co.il";
const utmKeys = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"];
const params = new URLSearchParams(window.location.search);
const freshUtms = utmKeys.filter(key => params.has(key));
if (freshUtms.length > 0) {
utmKeys.forEach(key => sessionStorage.removeItem(key));
freshUtms.forEach(key => sessionStorage.setItem(key, params.get(key)));
}
const utms = utmKeys
.filter(key => sessionStorage.getItem(key))
.map(key => [key, sessionStorage.getItem(key)]);
if (utms.length === 0) return;
document.querySelectorAll("a[href]").forEach(link => {
try {
const url = new URL(link.href);
if (!url.hostname.includes(targetDomain)) return;
utms.forEach(([key, value]) => {
if (!url.searchParams.has(key)) {
url.searchParams.set(key, value);
}
});
link.href = url.toString();
} catch (e) {}
});
})();sessionStorage נשמר למשך חיי הטאב בדפדפן. ברגע שהמשתמש סוגר את הטאב, הנתונים נמחקים.
זה בדיוק הסקופ הנכון עבור attribution של קמפיינים – לא נרצה שפרמטרים מביקור שבוע שעבר ידרסו את הביקור הנוכחי.
לעולם אל תוסיפו פרמטרי UTM לקישורים פנימיים. UTMs על קישורים פנימיים דורסים את מקור התנועה המקורי ב-GA4 ויוצרים sessions מזויפים, מה שהופך את נתוני הקמפיינים ללא אמינים.
שאלות נפוצות
utm_source, utm_medium, utm_campaign, utm_term ו-utm_content - ממופים ישירות ל-session dimensions ב-GA4. הסקריפט שומר על פרמטרים אלו בהעברה לדומיין חיצוני.URL constructor ו-URLSearchParams מטפלים ב-encoding אוטומטית, מונעים כפילויות, וממקמים את ה-query string לפני hash fragments. שרשור מחרוזות עם += עלול לשבור כתובות שמכילות # hash, כי הפרמטרים מגיעים ל-fragment במקום ל-query string.sessionStorage. הנתונים נמחקים כשהמשתמש סוגר את הטאב, מה שמתאים לאופן שבו sessions עובדים באנליטיקס. localStorage נשמר לצמיתות, מה שאומר שמשתמש שחוזר ימים לאחר מכן עדיין ישא ערכי UTM ישנים שלא משקפים את מקור התנועה הנוכחי.targetDomain הבודד במערך של דומיינים ובדקו מול כולם. לדוגמה: const targetDomains = ["app.co.il", "checkout.co.il"]; ואז השתמשו ב-targetDomains.some(d => url.hostname.includes(d)) במקום בדיקת includes() בודדת.תגובות ושאלות יתקבלו בברכה – תמיד שמח לשמוע רעיונות לשיפור 🙂


לא משתמשים ב-var כמעט אף פעם. במקרה הזה const יתאים.
קיבלת const 🙂
יופי, אגב גם utm_params יכול להיות const. אם שמרת מערך בתוך קבוע אז אפשר לעדכן אותו.