Wix
Wix form fields are React-controlled and Wix won't let you set a field's Name, so values written straight to the DOM get reverted. The fix: match fields by their title and add a small helper script that writes through React's value setter.
Add the tag to your site
In Settings → Custom Code, add the loader to Head, loaded on all pages, then publish.
<script src="https://attr.boggsmtk.com/v1/tag.js?k=YOUR_LICENSE_KEY"></script>
Swap YOUR_LICENSE_KEYfor the client's key from the dashboard.
Title each field to match the field map
In the Wix form editor, set each field's Field Title to exactly the MTK variable it should hold — e.g. mtk_ft_source or mtk_session_count. The helper script matches on the title, so it must match your field-map key character-for-character.
Add the companion Body-End script
Back in Settings → Custom Code, add the script below to Body - End, on all pages. It reads the mtk_attributiondataLayer event, matches each field by title, hides its wrapper, and writes the value through React's setter so the form state accepts it. Trim the FIELDS list to just the titles you added, or leave it as-is.
<script>
(function () {
// Every field the tool can write. Trim to just the ones you actually
// added to the form — matched against each field's title, exactly.
var FIELDS = [
// First touch (frozen, write-once)
'mtk_ft_channel', 'mtk_ft_source', 'mtk_ft_campaign', 'mtk_ft_term',
'mtk_ft_content', 'mtk_ft_placement', 'mtk_ft_landing',
// Last touch (refreshed each session)
'mtk_lt_channel', 'mtk_lt_source', 'mtk_lt_campaign', 'mtk_lt_term',
'mtk_lt_content', 'mtk_lt_placement', 'mtk_lt_landing',
// Click IDs
'mtk_lt_gclid', 'mtk_lt_gbraid', 'mtk_lt_wbraid', 'mtk_lt_msclkid',
// Journey
'mtk_touch_path', 'mtk_touch_path_json', 'mtk_session_count', 'mtk_pageview_count',
// Timing / conversion
'mtk_time_to_conversion', 'mtk_conversion_timestamp', 'mtk_conversion_datetime',
// Meta CAPI params
'mtk_fbclid', 'mtk_fbc', 'mtk_fbp'
];
var hidden = {};
function labelOf(el) {
var l = el.id && document.querySelector('label[for="' + el.id + '"]');
return ((l && l.textContent) || el.getAttribute('aria-label') || '').trim();
}
// climb to the largest wrapper that contains only this one field, hide it
function hideWrapper(el) {
var node = el;
while (node.parentElement) {
var p = node.parentElement;
if (p.tagName === 'FORM' || p.querySelectorAll('input, textarea').length > 1) break;
node = p;
}
node.style.display = 'none';
}
// set value so React's form state accepts it (not just the DOM)
function setReactValue(el, value) {
var proto = el.tagName === 'TEXTAREA' ? HTMLTextAreaElement : HTMLInputElement;
Object.getOwnPropertyDescriptor(proto.prototype, 'value').set.call(el, value);
if (el._valueTracker) el._valueTracker.setValue(value === '' ? '\u0000' : '');
el.dispatchEvent(new Event('input', { bubbles: true }));
el.dispatchEvent(new Event('change', { bubbles: true }));
}
(function tick() {
var data = (window.dataLayer || []).find(function (e) { return e.event === 'mtk_attribution'; });
var settled = !!data;
document.querySelectorAll('form input, form textarea').forEach(function (el) {
var key = labelOf(el);
if (FIELDS.indexOf(key) === -1) return;
if (!hidden[el.id]) { hideWrapper(el); hidden[el.id] = true; }
if (data && data[key] != null) {
if (el.value !== String(data[key])) setReactValue(el, String(data[key]));
} else {
settled = false;
}
});
setTimeout(tick, settled ? 2000 : 150);
})();
})();
</script>