Track UTMs in Saleskick
UTM attribution overview
This guide explains how to track UTMs and full HandL attribution data in Saleskick with HandL UTM Grabber V3. It helps you capture UTM source, medium, campaign, term, content, click IDs, referrer, landing page data, and first-touch fields, then pass them into the Saleskick iframe so they appear on submissions and in automations.
Prerequisites
- HandL UTM Grabber V3 installed and active on your WordPress site
- A Saleskick form embed code from Saleskick > Integrations > Embed
- UTM Grabber loaded on the same page before the Saleskick script runs (the plugin does this automatically on WordPress)
How it works
Saleskick ships a JavaScript embed that opens your form in a modal iframe. By default that iframe URL does not include your stored attribution cookies. The adapted embed below:
- Reads tracked parameters from the global
handl_utmobject (UTM Grabber V3) - Waits until
first_handlIDis available so first-touch data is included - Merges those values with any parameters already in the page URL
- Appends the merged query string to the Saleskick iframe
srcbefore the form loads
After a visitor submits, Saleskick stores the parameters under Application > URL Parameters in the submission detail view. The same data is exposed to automations as {{submission.shareQueryParams}} for webhooks and CRM integrations.
Step 1 — Paste the adapted embed code
Replace your default Saleskick embed with the code below. Update the constants at the top (FORM_SRC, button text, colors, etc.) to match your form.
Important: This version uses handl_utm (UTM Grabber V3). Do not use window.HandL.getAll() — that API belongs to a different tracking platform.
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;600;700&display=swap" rel="stylesheet">
<div id="saleskick-button-container" class="saleskick-button-container"></div>
<script>
(function () {
const FORM_SRC = "https://app.saleskick.com/form-YOUR-FORM-ID/your-form-slug";
const FORM_ORIGIN = "https://app.saleskick.com";
const BUTTON_TITLE = "Get Funded";
const BUTTON_COLOR = "#0f0e1d";
const BUTTON_TEXT_COLOR = "#ffffff";
const SHOW_TITLE = false;
const MODAL_TITLE_HTML = "Schedule Your Call";
const TITLE_FONT = "Inter";
const TITLE_FONT_SIZE = "24";
const TITLE_COLOR = "#1a1a1a";
const PRIMARY_COLOR = "#6366f1";
const BUTTON_FONT = "Roboto";
const ICON_HTML = '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-left: 8px;"><circle cx="12" cy="12" r="10"/><path d="M8 12h8"/><path d="m12 16 4-4-4-4"/></svg>';
const IFRAME_HEIGHT = "600px";
const UTM_GRABBER_DEBUG = true;
const UTM_GRABBER_LOG_PREFIX = "[Saleskick UTM Grabber]";
const UTM_GRABBER_INITIAL_DELAY_MS = 3000;
const UTM_GRABBER_RETRY_INTERVAL_MS = 250;
const UTM_GRABBER_MAX_WAIT_MS = 6000;
function logUtmGrabber(level, message, details) {
if (!UTM_GRABBER_DEBUG && level === "debug") return;
if (!window.console) return;
const logger = console[level] || console.log;
if (details !== undefined) {
logger.call(console, UTM_GRABBER_LOG_PREFIX, message, details);
} else {
logger.call(console, UTM_GRABBER_LOG_PREFIX, message);
}
}
function getSearchKeys(search) {
try {
return Array.from(new URLSearchParams(search || "").keys());
} catch (e) {
return [];
}
}
function getUrlSummary(urlString) {
try {
const url = new URL(urlString, document.location.href);
return {
urlWithoutSearch: url.origin + url.pathname + url.hash,
searchKeys: getSearchKeys(url.search),
};
} catch (e) {
const fallbackUrl = String(urlString || "");
return {
urlWithoutSearch: fallbackUrl.split("?")[0],
searchKeys: getSearchKeys(fallbackUrl.indexOf("?") !== -1 ? "?" + fallbackUrl.split("?").slice(1).join("?") : ""),
};
}
}
function getUtmGrabberDiagnostics() {
return {
handlUtmAvailable: typeof handl_utm !== "undefined",
trackedParamCount: typeof handl_utm !== "undefined" && handl_utm ? Object.keys(handl_utm).length : 0,
cookiesAvailable: typeof Cookies !== "undefined",
currentSearchKeys: getSearchKeys(document.location.search),
};
}
function isFirstHandlIDReady() {
try {
if (typeof handl_utm === "undefined" || !handl_utm) return false;
const firstHandlID = handl_utm.first_handlID;
return firstHandlID && typeof firstHandlID === "string" && firstHandlID.length > 0;
} catch (e) {
return false;
}
}
function getTrackedParams() {
const params = {};
if (typeof handl_utm !== "undefined" && handl_utm) {
Object.assign(params, handl_utm);
}
if (typeof Cookies !== "undefined" && typeof handl_utm_all_params !== "undefined") {
handl_utm_all_params.forEach(function (param) {
if (!params[param] && Cookies.get(param)) {
params[param] = Cookies.get(param);
}
});
}
return params;
}
function getUrlParams() {
const diagnostics = getUtmGrabberDiagnostics();
logUtmGrabber("debug", "Starting URL param merge.", diagnostics);
if (typeof handl_utm === "undefined") {
logUtmGrabber("warn", "handl_utm is missing; using document.location.search only.", diagnostics);
return document.location.search;
}
let trackedParams = {};
try {
trackedParams = getTrackedParams();
} catch (e) {
logUtmGrabber("error", "Reading handl_utm threw; using document.location.search only.", {
...diagnostics,
error: e && (e.stack || e.message || String(e)),
});
return document.location.search;
}
const params = new URLSearchParams(document.location.search);
const mergedKeys = [];
const skippedKeys = [];
Object.entries(trackedParams).forEach(function ([key, value]) {
if (value !== undefined && value !== null && value !== "") {
params.set(key, value);
mergedKeys.push(key);
} else {
skippedKeys.push(key);
}
});
const result = params.toString();
logUtmGrabber("debug", "Finished URL param merge.", {
...diagnostics,
trackedKeys: Object.keys(trackedParams),
mergedKeys,
skippedKeys,
finalSearchKeys: getSearchKeys(result),
});
return result ? "?" + result : "";
}
function mergeFormUrl(baseUrl, extraSearch) {
if (!extraSearch || extraSearch === "?") return baseUrl;
try {
const url = new URL(baseUrl);
const extraParams = new URLSearchParams(extraSearch);
extraParams.forEach(function (value, key) {
url.searchParams.set(key, value);
});
return url.toString();
} catch (e) {
logUtmGrabber("error", "Unable to parse FORM_SRC with URL(); falling back to string merge.", {
baseUrl,
extraSearchKeys: getSearchKeys(extraSearch),
error: e && (e.stack || e.message || String(e)),
});
return baseUrl + (baseUrl.indexOf("?") !== -1 ? "&" + extraSearch.slice(1) : extraSearch);
}
}
function assignIframeSrcWhenReady(startedAt) {
const elapsedMs = Date.now() - startedAt;
if (!isFirstHandlIDReady() && elapsedMs < UTM_GRABBER_MAX_WAIT_MS) {
logUtmGrabber("debug", "first_handlID not ready yet; retrying before iframe src assignment.", {
...getUtmGrabberDiagnostics(),
elapsedMs,
retryInMs: UTM_GRABBER_RETRY_INTERVAL_MS,
maxWaitMs: UTM_GRABBER_MAX_WAIT_MS,
});
setTimeout(function () {
assignIframeSrcWhenReady(startedAt);
}, UTM_GRABBER_RETRY_INTERVAL_MS);
return;
}
if (!isFirstHandlIDReady()) {
logUtmGrabber("warn", "first_handlID was still not ready after waiting; assigning iframe with fallback params.", {
...getUtmGrabberDiagnostics(),
elapsedMs,
maxWaitMs: UTM_GRABBER_MAX_WAIT_MS,
});
}
const extraSearch = getUrlParams();
const mergedUrl = mergeFormUrl(FORM_SRC, extraSearch);
iframe.src = mergedUrl;
logUtmGrabber("info", "Iframe src assigned.", {
elapsedMs,
extraSearchKeys: getSearchKeys(extraSearch),
mergedUrl: getUrlSummary(mergedUrl),
});
}
const iframe = document.createElement("iframe");
iframe.className = "saleskick-iframe";
const utmGrabberWaitStartedAt = Date.now();
setTimeout(function () {
assignIframeSrcWhenReady(utmGrabberWaitStartedAt);
}, UTM_GRABBER_INITIAL_DELAY_MS);
iframe.width = "100%";
iframe.height = IFRAME_HEIGHT;
iframe.style.border = "none";
iframe.style.borderRadius = SHOW_TITLE ? "0 0 8px 8px" : "8px";
iframe.style.display = "none";
iframe.style.opacity = "0";
iframe.style.transition = "opacity 500ms ease";
iframe.style.background = "#ffffff";
iframe.setAttribute("frameborder", "0");
const button = document.createElement("button");
button.className = "saleskick-button";
button.type = "button";
button.innerHTML = BUTTON_TITLE + ICON_HTML;
button.style.cssText = 'display: inline-flex; align-items: center; justify-content: center; background: ' + BUTTON_COLOR + '; color: ' + BUTTON_TEXT_COLOR + '; padding: 12px 24px; font-family: "' + BUTTON_FONT + '", sans-serif; font-size: 30px; border: 3px solid #1ebcb7; border-radius: 50px; font-weight: 500; cursor: pointer; transition: all 0.2s ease; margin: 2rem 0;';
button.onmouseenter = function () { button.style.opacity = "0.9"; };
button.onmouseleave = function () { button.style.opacity = "1"; };
const modal = document.createElement("div");
modal.className = "saleskick-modal";
modal.style.cssText = "position:fixed;inset:0;background:rgba(15,23,42,0.55);display:none;align-items:center;justify-content:center;padding:24px;z-index:9000;opacity:0;transition:opacity 500ms ease;";
const modalCard = document.createElement("div");
modalCard.className = "saleskick-modal-card";
modalCard.style.cssText = "background:#fff;border-radius:20px;padding:0;width:min(95vw,1400px);min-width:800px;box-shadow:0 20px 50px rgba(15,23,42,0.25);position:relative;transform:translateY(12px);transition:transform 500ms ease;";
const popupCloseButton = document.createElement("button");
popupCloseButton.type = "button";
popupCloseButton.className = "saleskick-close-2 close-2";
popupCloseButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6L6 18"/><path d="M6 6l12 12"/></svg>';
popupCloseButton.style.cssText = "position:absolute;top:8px;right:8px;background:none;border:none;color:#666;cursor:pointer;padding:6px;z-index:10;";
const loadingOverlay = document.createElement("div");
loadingOverlay.className = "saleskick-loading-overlay";
loadingOverlay.textContent = "Loading...";
loadingOverlay.style.cssText = "position:absolute;inset:0;display:none;align-items:center;justify-content:center;background:rgba(255,255,255,0.9);font-weight:600;font-size:18px;z-index:1;";
let isLoaded = false;
function showSaleskickForm() {
iframe.style.display = "block";
iframe.style.opacity = "0";
button.style.display = "none";
loadingOverlay.style.display = isLoaded ? "none" : "flex";
modal.style.display = "flex";
document.body.style.overflow = "hidden";
requestAnimationFrame(function () {
modal.style.opacity = "1";
modalCard.style.transform = "translateY(0)";
iframe.style.opacity = "1";
});
}
function hideSaleskickForm() {
iframe.style.opacity = "0";
modal.style.opacity = "0";
modalCard.style.transform = "translateY(12px)";
loadingOverlay.style.display = "none";
button.style.display = "inline-flex";
document.body.style.overflow = "";
window.setTimeout(function () {
modal.style.display = "none";
iframe.style.display = "none";
}, 500);
}
const container = document.getElementById("saleskick-button-container") || document.body;
container.style.textAlign = "center";
container.appendChild(button);
modalCard.appendChild(popupCloseButton);
modalCard.appendChild(iframe);
modalCard.appendChild(loadingOverlay);
modal.appendChild(modalCard);
document.body.appendChild(modal);
button.addEventListener("click", showSaleskickForm);
popupCloseButton.addEventListener("click", hideSaleskickForm);
modal.addEventListener("click", function (event) {
if (event.target === modal) hideSaleskickForm();
});
iframe.addEventListener("load", function () {
isLoaded = true;
loadingOverlay.style.display = "none";
});
window.addEventListener("message", function (event) {
if (event.origin !== FORM_ORIGIN) return;
const data = event.data || {};
if (data.type === "saleskick-form-redirect" && typeof data.url === "string") {
window.location.href = data.url;
}
});
})();
</script>
The full production embed from Saleskick may include additional modal styling and mobile responsive behavior. When adapting your own copy, only change the attribution block: replace any window.HandL / HandL.getAll() references with handl_utm as shown above.
Step 2 — Test with UTMs in the landing URL
Visit your landing page with test UTMs, for example:
https://yoursite.com/landing-page?utm_source=fb&utm_medium=paid&utm_campaign=test
Open the browser console and look for [Saleskick UTM Grabber] log messages. Submit a test lead through the Saleskick form.
Step 3 — Verify parameters in Saleskick
Open the submission in Saleskick and go to the Application tab. Under URL Parameters you should see values such as:
utm_source,utm_medium,utm_campaign,utm_term,utm_contentfbclid,gclid, or other click IDs when presenthandlID,first_handlID,handl_ref,handl_landing_page,handl_urltraffic_source,organic_source_str,user_agent
If parameters are missing, confirm UTM Grabber is active, cookies are not blocked, and the page was loaded with UTMs before opening the Saleskick modal.
Next step
See Send Saleskick UTMs via Automation or Webhook to forward shareQueryParams to your CRM or backend.