Pasang Form Order (Embed)
Cara memasang form order AdForm di website sendiri — snippet iframe siap salin, embed.js untuk tinggi otomatis, atribut kontainer, dan cara menangkap kejadian setelah form terkirim.
Form order AdForm dipasang di situs Anda sebagai <iframe>, ditemani satu berkas skrip embed.js yang berjalan di halaman induk. Ini kontrak publik yang memang ditujukan untuk integrator — untuk sebagian besar kebutuhan, Anda tidak perlu memanggil API sama sekali.
Skrip embed.js mengerjakan empat hal, dan hanya empat hal:
- Menyesuaikan tinggi iframe otomatis mengikuti isi form.
- Menyalakan Meta Pixel dan Google Tag Manager di halaman induk sesuai setelan produk, lalu meneruskan event dari form ke sana.
- Membuat iframe otomatis dari elemen kontainer ber-atribut
data-ef-product. - Mengirim satu pemberitahuan ke AdForm bahwa form terpasang di halaman ini.
#Cara paling cepat: iframe langsung
Ini bentuk yang dihasilkan AdForm sendiri, dan yang kami sarankan.
<iframe src="https://adform.id/t/34/kaos-polos-hitam"
style="width:100%;min-height:700px;border:none;"
loading="eager" scrolling="no" frameborder="0"></iframe>
<script src="https://adform.id/embed.js"></script>Ganti 34 dengan ID tenant Anda dan kaos-polos-hitam dengan slug produk. Jangan merangkai URL ini dengan tangan. Ambil bentuk jadinya dari dashboard, atau dari response API pada field embed.iframe_with_pixel — lihat API Produk. Slug bisa berubah (misalnya bertambah akhiran angka saat bentrok), dan URL yang salah hanya menampilkan halaman kosong.
Letakkan <script> sekali saja per halaman, meskipun ada beberapa form. Boleh diletakkan setelah iframe atau di akhir <body>.
#Kalau form dipasang di domain form Anda sendiri
Tenant yang memakai domain form sendiri memakai bentuk URL yang lebih pendek:
<iframe src="https://form.contohtoko.id/kaos-polos-hitam"
style="width:100%;min-height:700px;border:none;"
loading="eager" scrolling="no" frameborder="0"></iframe>
<script src="https://form.contohtoko.id/embed.js"></script>Aturan yang tidak boleh dilanggar:
embed.jsharus dimuat dari domain yang sama dengansrciframe.
embed.jsmenentukan iframe mana yang boleh ia atur dengan membandingkansrciframe terhadap alamat dari mana skrip itu sendiri dimuat. Kalau iframe menunjukform.contohtoko.idtetapi skripnya dimuat dariadform.id, iframe tidak dikenali dan tinggi otomatis tidak jalan — form akan terpotong di 700px. Ini penyebab nomor satu keluhan "form saya kepotong".
#Cara kedua: kontainer data-ef-product
embed.js juga bisa membuat iframe sendiri dari elemen kosong. Berguna kalau Anda memasang lewat page builder yang menyulitkan penulisan <iframe> langsung.
<div data-ef-product="kaos-polos-hitam"
data-ef-src="https://form.contohtoko.id"></div>
<script src="https://form.contohtoko.id/embed.js"></script>#Atribut yang didukung
| Atribut | Wajib | Isi |
|---|---|---|
data-ef-product | ✅ | Slug produk. Nilai kosong berarti kontainer dilewati. |
data-ef-src | ⬜ | Alamat dasar form. Kalau tidak diisi, diambil dari alamat embed.js yang sedang berjalan. |
data-ef-tenant | ⬜ | Nama tenant, ditambahkan sebagai query tenant=. |
data-ef-init | — | Diisi skrip, bukan Anda. Ditandai 1 setelah kontainer diproses supaya tidak dibuat dua kali. |
URL yang dibentuk berpola <data-ef-src>/<slug>?embed=1, ditambah tenant= bila data-ef-tenant diisi.
Batasan yang perlu Anda tahu. Pola satu segmen di atas hanya menghasilkan produk yang benar kalau
data-ef-srcmenunjuk domain form milik tenant — di sana tenant dikenali dari nama domainnya. Padaadform.id, alamat satu segmen diartikan sebagai etalase tenant, bukan produk, sehingga form produk tidak muncul. Kalau form Anda dilayani dariadform.id, pakai iframe langsung dengan bentuk/t/{tenant_id}/{slug}.
Iframe yang dibuat mendapat width:100%, min-height:700px, border:none, display:block, scrolling="no", frameborder="0", dan allow="clipboard-write".
#Kontainer yang muncul belakangan
Kontainer dipindai saat DOM siap, lalu diulang pada detik ke-1 dan ke-3, dan dipantau terus lewat MutationObserver. Jadi kontainer yang disisipkan belakangan oleh page builder, tab, atau modal tetap terpasang tanpa Anda memanggil apa pun.
#Mengatur ukuran
Lebar sepenuhnya milik Anda. Iframe memakai width:100%, jadi yang menentukan adalah elemen pembungkusnya:
<div style="max-width:520px;margin:0 auto;">
<iframe src="https://adform.id/t/34/kaos-polos-hitam"
style="width:100%;min-height:700px;border:none;"
loading="eager" scrolling="no" frameborder="0"></iframe>
</div>
<script src="https://adform.id/embed.js"></script>Tinggi diurus embed.js. Alurnya:
- Anda memberi
min-height:700pxsebagai tinggi sementara supaya halaman tidak melompat saat form dimuat. - Form mengukur dirinya sendiri dan mengirim tinggi sebenarnya ke halaman induk.
embed.jsmenyetelstyle.heightiframe ke nilai itu dan menghapusmin-height.- Langkah 2–3 berulang setiap isi form berubah tinggi — memilih varian, membuka rincian ongkir, menampilkan halaman sukses.
Yang perlu dihindari:
- Jangan menyetel
heighttetap lewat CSS dengan!important. Itu mengalahkan penyesuaian otomatis dan form akan terpotong. - Jangan memasang
overflow:hiddendengan tinggi tetap pada pembungkus. - Jangan memberi
scrolling="yes"— form dirancang untuk ikut menggulung bersama halaman induk, bukan menggulung di dalam kotaknya sendiri. - Boleh menaikkan
min-heightawal kalau form Anda panjang (misalnyamin-height:900px) supaya pergeseran tata letak awal lebih kecil.
#Atribusi iklan
Kalau pengunjung datang dari iklan, parameter fbclid, gclid, dan utm_* ada di URL halaman induk, bukan di dalam iframe.
- Mode kontainer (
data-ef-product):embed.jsotomatis meneruskanfbclid,gclid,utm_source,utm_medium,utm_campaign,utm_content, danutm_termdari URL halaman induk ke URL iframe. - Mode iframe langsung: parameter tidak diteruskan otomatis, karena
srcsudah tertulis tetap di HTML Anda. Form masih berusaha membaca parameter itu daridocument.referrersebagai cadangan, tetapi cara itu bergantung pada kebijakanReferrer-Policysitus Anda dan tidak selalu berhasil.
Kalau atribusi iklan penting bagi Anda dan Anda memakai iframe langsung, tambahkan sendiri parameternya ke src saat halaman dirender di sisi server, atau pakai mode kontainer.
#Tracking pixel di halaman induk
Saat form dimuat, ia memberi tahu halaman induk pixel dan container mana yang dipakai produk tersebut. embed.js lalu:
- Memuat SDK Meta Pixel di halaman induk kalau
window.fbqbelum ada, lalu menjalankanfbq('init', ...)untuk setiap ID pixel yang belum diinisialisasi di halaman itu. - Memuat Google Tag Manager di halaman induk sekali, dengan ID yang sudah dibersihkan ke pola
GTM-XXXXXXX. - Meneruskan setiap event dari form ke
fbqdan kedataLayerhalaman induk.
Tiga hal yang perlu Anda perhatikan:
- Kalau situs Anda sudah punya Meta Pixel sendiri, SDK tidak dimuat ulang, tetapi ID pixel milik produk AdForm tetap diinisialisasi berdampingan dengan milik Anda. Event AdForm akan tercatat di kedua pixel yang aktif.
- Kalau situs Anda sudah punya GTM sendiri,
embed.jstidak memeriksanya. Container GTM milik produk akan dimuat sebagai container kedua. Kalau Anda tidak menginginkannya, kosongkan setelan GTM di produk AdForm dan urus tag dari container Anda sendiri. - Kalau situs Anda memakai Content-Security-Policy, izinkan
https://connect.facebook.netdanhttps://www.googletagmanager.compadascript-src, kalau tidak keduanya diblokir tanpa pesan yang jelas.
Event konversi membawa eventID yang sama dengan yang ditembakkan di dalam iframe, supaya Meta menghitungnya satu kali meskipun diterima dari dua tempat. Jangan menembakkan ulang event konversi Anda sendiri dengan nama yang sama tanpa eventID — itu membuat hitungan ganda.
#Menangani kejadian setelah form terkirim
Form berkomunikasi dengan halaman induk lewat postMessage. Anda boleh memasang pendengar sendiri di samping embed.js.
#Pesan yang dikirim form
type | Kapan | Isi |
|---|---|---|
ef-tracking-init | Sekali saat form selesai dimuat. | pixelIds (array), pixelId (string, kompatibilitas lama), gtmId, productName, productId. |
ef-tracking-event | Setiap event tracking, termasuk saat halaman dilihat dan saat pesanan berhasil dibuat. | eventName, params, eventID, pixelIds, pixelId, gtmId. |
embed-form-resize | Setiap tinggi form berubah. | height (angka, piksel). |
adform_gtm_redirect | Tepat sebelum pengunjung dialihkan ke WhatsApp. | gtm_trigger (nilai dari setelan produk). |
#Mengenali "pesanan berhasil dibuat"
Gunakan ef-tracking-event dan periksa eventID:
- Saat form dimuat, event
PageViewdikirim denganeventIDkosong. - Saat pesanan berhasil disimpan, event konversi dikirim dengan
eventIDberisi ID pesanan dalam bentuk string.
Nama event konversinya mengikuti setelan produk dan bukan nilai tetap — bawaannya AddToCart, tetapi pemilik akun bisa menggantinya. Jangan mencocokkan nama event; cocokkan pada eventID yang tidak kosong.
Isi params pada event konversi: content_name (nama produk), content_ids (array berisi ID produk), content_type ("product"), value (total pesanan, integer rupiah), dan currency ("IDR").
#Contoh lengkap, siap salin
<div style="max-width:520px;margin:0 auto;">
<iframe src="https://adform.id/t/34/kaos-polos-hitam"
style="width:100%;min-height:700px;border:none;"
loading="eager" scrolling="no" frameborder="0"></iframe>
</div>
<script src="https://adform.id/embed.js"></script>
<script>
(function () {
// Harus sama persis dengan origin pada src iframe di atas.
var ADFORM_ORIGIN = 'https://adform.id';
var sudahDicatat = {}; // ID pesanan yang sudah diproses
window.addEventListener('message', function (event) {
// Wajib: abaikan pesan dari origin lain.
if (event.origin !== ADFORM_ORIGIN) return;
var d = event.data;
if (!d || d.type !== 'ef-tracking-event') return;
// eventID kosong = PageView, bukan pesanan.
var orderId = d.eventID;
if (!orderId) return;
// Pesan bisa datang lebih dari sekali. Jaga agar idempoten.
if (sudahDicatat[orderId]) return;
sudahDicatat[orderId] = true;
var p = d.params || {};
console.log('Pesanan AdForm dibuat', {
order_id: orderId,
produk: p.content_name,
total: p.value, // integer rupiah, mis. 150000
currency: p.currency, // "IDR"
});
// Di sini tempat Anda menjalankan kode sendiri: konversi Google Ads,
// event analitik internal, atau menampilkan pesan di halaman induk.
// Kerjakan segera — halaman bisa berpindah beberapa detik lagi.
});
})();
</script>#Halaman bisa berpindah setelah submit — kerjakan segera
Ini yang paling sering membuat integrator kehilangan event:
- Produk yang mengarahkan ke WhatsApp menampilkan hitung mundur tiga detik, lalu mengalihkan seluruh tab (bukan hanya iframe) ke tautan WhatsApp.
- Produk dengan pembayaran online mengalihkan seluruh tab ke halaman pembayaran AdForm.
Karena itu kode di dalam pendengar Anda harus berjalan seketika. Kalau perlu mengirim data ke server sendiri, pakai navigator.sendBeacon() atau fetch() dengan keepalive: true — request fetch biasa bisa terputus saat halaman berpindah.
Jangan pula berasumsi pengunjung kembali ke halaman Anda setelah itu.
#Pemberitahuan pemasangan
Sekali per iframe, embed.js mengirim satu beacon ke /api/embed_ping.php di domain form, berisi alamat halaman tempat form dipasang. Ini yang membuat pemilik akun bisa melihat daftar situs tempat form-nya terpasang. Kirimannya bersifat fire-and-forget, tidak memblokir apa pun, dan gagal diam-diam kalau diblokir. Tidak ada data pengunjung yang ikut dikirim.
#Kalau ada yang tidak beres
| Gejala | Penyebab yang paling sering |
|---|---|
| Form terpotong di 700px | embed.js dimuat dari domain berbeda dengan src iframe. Samakan keduanya. |
| Form terpotong meski domain sama | Ada CSS di situs Anda yang memaksa height tetap pada iframe, seringkali dari tema atau page builder. |
| Iframe kosong / halaman putih | URL salah. Ambil ulang dari dashboard atau dari embed.iframe_with_pixel. Perhatikan slug bisa berubah. |
Kontainer data-ef-product tidak jadi iframe | data-ef-src menunjuk adform.id. Mode kontainer hanya cocok untuk domain form tenant sendiri. |
| Pixel tidak menyala | Cek Content-Security-Policy situs Anda, dan pastikan ID pixel benar-benar terisi di setelan produk. |
Pendengar message Anda tidak jalan | Nilai ADFORM_ORIGIN tidak sama persis dengan origin src iframe, termasuk skema dan subdomain. |
| Form menolak pesanan saat diuji berkali-kali | Pembatasan anti-spam per IP, atau kuota pesanan paket gratis. Lihat Batas Penggunaan. |
#Yang tidak didukung
- Mengirim pesanan langsung ke endpoint AdForm tanpa form. Tidak ada kontrak publik untuk itu, dan kami tidak berencana membukanya — jalur yang didukung adalah memasang form-nya.
- Menata ulang tampilan form dari halaman induk. Isi iframe berada di origin lain; CSS Anda tidak bisa menembus ke dalamnya. Tampilan form diatur dari dashboard AdForm.
- Mengisi otomatis field form dari halaman induk. Belum ada kontrak
postMessageuntuk arah induk ke form. - Membaca isi form dari halaman induk. Hanya keempat pesan di tabel di atas yang dikirim keluar.
Butuh salah satunya? Kabari lewat Pusat Bantuan, sertakan alur yang Anda inginkan dan alasannya.