Form order AdForm dipasang di situs Anda sebagai ` ``` 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](/docs/api-products#ambil-snippet-embed-produk). Slug bisa berubah (misalnya bertambah akhiran angka saat bentrok), dan URL yang salah hanya menampilkan halaman kosong. Letakkan ` ``` > **Aturan yang tidak boleh dilanggar: `embed.js` harus dimuat dari domain yang sama dengan `src` iframe.** > > `embed.js` menentukan iframe mana yang boleh ia atur dengan membandingkan `src` iframe terhadap alamat dari mana skrip itu sendiri dimuat. Kalau iframe menunjuk `form.contohtoko.id` tetapi skripnya dimuat dari `adform.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 ` ``` **Tinggi** diurus `embed.js`. Alurnya: 1. Anda memberi `min-height:700px` sebagai tinggi sementara supaya halaman tidak melompat saat form dimuat. 2. Form mengukur dirinya sendiri dan mengirim tinggi sebenarnya ke halaman induk. 3. `embed.js` menyetel `style.height` iframe ke nilai itu dan **menghapus `min-height`**. 4. Langkah 2–3 berulang setiap isi form berubah tinggi — memilih varian, membuka rincian ongkir, menampilkan halaman sukses. Yang perlu dihindari: - **Jangan** menyetel `height` tetap lewat CSS dengan `!important`. Itu mengalahkan penyesuaian otomatis dan form akan terpotong. - **Jangan** memasang `overflow:hidden` dengan 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-height` awal kalau form Anda panjang (misalnya `min-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.js` otomatis meneruskan `fbclid`, `gclid`, `utm_source`, `utm_medium`, `utm_campaign`, `utm_content`, dan `utm_term` dari URL halaman induk ke URL iframe. - **Mode iframe langsung**: parameter **tidak** diteruskan otomatis, karena `src` sudah tertulis tetap di HTML Anda. Form masih berusaha membaca parameter itu dari `document.referrer` sebagai cadangan, tetapi cara itu bergantung pada kebijakan `Referrer-Policy` situs 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.fbq` belum ada**, lalu menjalankan `fbq('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 `fbq` dan ke `dataLayer` halaman induk. Tiga hal yang perlu Anda perhatikan: 1. **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. 2. **Kalau situs Anda sudah punya GTM sendiri**, `embed.js` tidak 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. 3. **Kalau situs Anda memakai Content-Security-Policy**, izinkan `https://connect.facebook.net` dan `https://www.googletagmanager.com` pada `script-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 `PageView` dikirim dengan `eventID` **kosong**. - Saat pesanan berhasil disimpan, event konversi dikirim dengan `eventID` berisi **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 ```html
``` ### 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](/docs/batas-penggunaan#batas-lain-yang-bisa-anda-temui). | ## 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 `postMessage` untuk 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](https://adform.id/pusat-bantuan.html), sertakan alur yang Anda inginkan dan alasannya.