Pek çok form platformu (Typeform, Tally, Paperform, JotForm, vb.) formları iframe veya embed script ile web sitelerine entegre eder. Bu durum dönüşüm takibi için bir sorun oluşturur: iframe farklı bir domain’de çalıştığı için ana sayfadaki GTM container’ı iframe içindeki etkinlikleri doğrudan yakalayamaz.
Bu rehberde iframe içindeki form etkinliklerini window.postMessage API’si ile yakalayıp GTM’e aktarma yöntemini ele alacağız. Yöntem platforma bağımsızdır ve herhangi bir iframe form için uygulanabilir.
Sorun: iframe ve Cross-domain Sınırları
Bir form iframe ile embed edildiğinde:
- iframe farklı bir origin’de çalışır (ör.
tally.so,typeform.com,paperform.co) - Ana sayfa iframe’in DOM’una erişemez (same-origin policy)
- iframe içindeki cookie’ler üçüncü taraf çerez kısıtlamalarına tabidir (Safari, Firefox)
- GTM container’ı yalnızca ana sayfada çalışır, iframe içindeki olayları göremez
Çözüm: window.postMessage
window.postMessage API’si, farklı origin’lerdeki window nesneleri arasında güvenli mesaj taşımayı sağlar. iframe içindeki form platformu bir etkinlik gerçekleştiğinde (form gönderimi, sayfa değişimi, vb.) ana sayfaya mesaj gönderir. Ana sayfadaki listener bu mesajı yakalar ve dataLayer.push() ile GTM’e aktarır.
Genel Akış
iframe (form platformu)
↓ form gönderildi
↓ window.parent.postMessage({ event: "formSubmitted" }, "*")
↓
parent page (ana sayfa)
↓ window.addEventListener("message", handler)
↓ origin kontrolü
↓ dataLayer.push({ event: "form_submitted" })
↓
GTM
↓ Custom Event trigger: "form_submitted"
↓ GA4 Event / Google Ads Conversion / diğer etiketler
Platform Bazlı postMessage Desteği
Bazı form platformları zaten otomatik olarak postMessage event’i gönderir:
Tally: Tally.FormSubmitted, Tally.FormLoaded, Tally.FormPageView event’lerini otomatik gönderir. Detaylar için Tally Dönüşüm Takibi Rehberi yazısına bakabilirsiniz.
Typeform: TypeformSubmit ve TypeformQuestionPassed event’lerini dataLayer ile gönderir. Detaylar için Typeform Dönüşüm Takibi Rehberi yazısına bakabilirsiniz.
Paperform: Form gönderiminde SubmittedForm, ödeme başlangıcında StartedCheckout, form doldurmaya başlandığında StartedSubmission event’lerini gönderir.
Otomatik postMessage desteği olmayan platformlar için iframe içinden manuel olarak mesaj göndermeniz gerekir.
Yöntem 1: Parent Page Erişimi Var
Parent sayfanın koduna erişiminiz varsa, doğrudan listener ekleyebilirsiniz.
Adım 1: iframe İçinden Mesaj Gönderme
Form platformunun “form gönderim sonrası script” alanına (varsa) şu kodu ekleyin:
<script>
window.parent.postMessage(
{
message: "form_submitted",
},
"<parent-page-hostname>",
);
</script>
<parent-page-hostname> formu embed ettiğiniz sitenin origin’idir (ör. https://example.com).
Adım 2: Parent Sayfada Listener
Ana sayfada, iframe’den gelen mesajı dinleyip GTM’e aktarın:
window.addEventListener("message", function (event) {
// Origin kontrolü: yalnızca güvendiğiniz kaynaktan gelen mesajları kabul edin
if (
event.origin === "https://form-platform.com" &&
event.data.message === "form_submitted"
) {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: "iframe_form_submitted",
});
}
});
Origin kontrolü güvenlik açısından kritiktir. event.origin değerini her
zaman kontrol edin. Herhangi bir origin’den gelen mesajı kabul etmek XSS riski
oluşturur.
Adım 3: GTM Trigger ve Tag
GTM’de:
- Trigger: Custom Event, event adı
iframe_form_submitted - Tag: GA4 Event, Google Ads Conversion veya istediğiniz platform etiketi
Yöntem 2: Yalnızca GTM Erişimi Var
Parent sayfanın koduna doğrudan erişiminiz yoksa aynı listener’ı GTM Custom HTML etiketi içinde çalıştırabilirsiniz.
GTM container’ında yeni bir Custom HTML etiketi oluşturun:
<script>
(function () {
try {
if (typeof window.addEventListener !== "undefined") {
window.addEventListener("message", function (event) {
// Güvendiğiniz form platformunun origin'ini belirtin
var trustedOrigins = [
"https://tally.so",
"https://form.typeform.com",
"https://your-form-id.paperform.co",
];
if (trustedOrigins.indexOf(event.origin) !== -1) {
// Platform bazlı event kontrolü
var eventName = null;
// Tally
if (event.data && event.data.event === "Tally.FormSubmitted") {
eventName = "tally_form_submitted";
}
// Typeform
else if (event.data && event.data.event === "TypeformSubmit") {
eventName = "typeform_form_submitted";
}
// Genel postMessage
else if (event.data && event.data.message === "form_submitted") {
eventName = "iframe_form_submitted";
}
if (eventName) {
window.dataLayer.push({ event: eventName });
}
}
});
}
} catch (err) {
console.log(err);
}
})();
</script>
Bu etiketi All Pages trigger’ı ile tetikleyin. Böylece her sayfada listener aktif olur ve iframe’den gelen form event’leri yakalanır.
Paperform Özel Durumu
Paperform, embed formlar için şu yapıyı kullanır:
<div data-paperform-id="<form-id>"></div>
<script>
(function () {
var script = document.createElement("script");
script.src = "https://paperform.co/__embed";
document.body.appendChild(script);
})();
</script>
Paperform Configure > Analytics altında Google Analytics ID ve Facebook Pixel ID alanları sunar. Ancak GTM için doğrudan dataLayer push yapılmaz. Bu nedenle postMessage yöntemi gereklidir.
Successful submission scripts alanına şu kodu ekleyin:
<script>
window.parent.postMessage(
{
message: "form_submitted",
},
"https://your-site.com",
);
</script>
Cross-domain Uyarıları
iframe form tracking yaparken dikkat edilmesi gerekenler:
- Origin kontrolü: Her zaman
event.origindeğerini kontrol edin - Üçüncü taraf çerezler: Safari ve Firefox iframe içindeki çerezleri engelleyebilir. Bu durumda GA4/GTM iframe içinde çalışmaz, postMessage yöntemi daha güvenilirdir
- Referral exclusion: Form platformunun domain’ini GA4 referral exclusion listesine ekleyin
- Consent: GDPR/ePrivacy gereksinimlerini göz önünde bulundurun. Consent alınmadan tracking kodu çalıştırmayın
Cross-domain tracking detayları için Google Analytics ve Google Tag Manager Domain Yönetimi yazısına bakabilirsiniz.
Test ve Doğrulama
- Tarayıcı konsolunda
window.addEventListener('message', (e) => console.log(e.origin, e.data))ile gelen mesajları izleyin - GTM Preview modunda form gönderin, dataLayer’da event’in göründüğünü doğrulayın
- İlişkili tag’lerin tetiklendiğini kontrol edin