Daftar tunggu untuk SaaS baru6 menit baca
Cara menambahkan daftar tunggu ke situs Framer
Dua cara mengumpulkan pendaftaran daftar tunggu di Framer: formulir Framer dengan webhook ke Ikiform, atau code component yang mempertahankan batas per pengunjung dan pemeriksaan spam.
Formulir Framer tidak bisa mengirim ke URL luar, tetapi bisa mengirim setiap kiriman ke webhook, jadi jalur tanpa kode adalah formulir Framer dengan endpoint Ikiform Anda sebagai webhook. Untuk peluncuran publik, gunakan code component kecil: browser mengirim langsung, jadi rate limit per pengunjung, domain yang diizinkan, dan honeypot dari Ikiform tetap berfungsi.
Banyak halaman pra-peluncuran dibangun di Framer, karena halamannya sendiri bisa selesai dalam satu sore. Formulir daftar tunggu adalah bagian yang kurang jelas. Blok formulir Framer tidak bisa mengubah action-nya, jadi Anda memilih antara dua jalur yang berperilaku berbeda begitu trafik sungguhan datang.
Apa bedanya di Framer
- Tidak ada action kustom. Formulir Framer mengirim ke tujuan milik Framer: penyimpanannya sendiri, email, atau Webhook. Webhook adalah satu-satunya cara menjangkau backend luar tanpa kode.
- Webhook datang dari server Framer, bukan dari pengunjung. Ikiform melihat alamat IP Framer dan tidak ada header
Origin. Itu mematikan tiga perlindungan: domain yang diizinkan, rate limit per pengunjung, dan pemeriksaan manusia. - Percobaan ulang. Framer menganggap apa pun selain
2xxsebagai kegagalan dan mencoba ulang hingga lima kali. Framer tidak mengikuti redirect. Ikiform menjawab kiriman JSON dengan201, jadi pendaftaran yang tersimpan langsung dianggap sukses sejak percobaan pertama. - Code component adalah React sungguhan. Komponen ini berjalan di browser pengunjung di situs yang sudah dipublikasikan, jadi formulir di dalamnya mengirim seperti halaman web lain.
- Dengan jalur webhook, pengunjung mengirim formulir Framer dan server Framer meneruskan field-nya ke Ikiform sebagai JSON.
- Ikiform melihat server Framer sebagai pengirim, jadi tidak bisa membedakan pengunjung atau memeriksa di situs mana formulir itu berada.
- Dengan code component, browser pengunjung mengirim langsung ke Ikiform.
- Ikiform melihat IP setiap pengunjung dan domain Anda, jadi setiap perlindungan berlaku.
Pilih jalur
| Item | Formulir Framer dengan webhook | Code component |
|---|---|---|
| Setup | Dua field di sidebar kanan | Satu file kode, ditempel sekali |
| Gaya | Gaya dan state formulir Framer | Inline style yang Anda edit, atau class Anda sendiri |
| Rate limit per pengunjung | Tidak. Semua kiriman berbagi IP Framer | Ya, masing-masing 5 per menit |
| Domain yang diizinkan | Biarkan kosong | Isi dengan domain Framer dan domain kustom Anda |
| Honeypot | Tidak | Ya |
| Pemeriksaan manusia | Mati | Mati, karena mengirim dengan fetch |
| Pelacakan sumber | Tidak ada | ?ref= dari URL, atau default per instance |
Jalur webhook sudah cukup untuk halaman yang Anda bagikan ke beberapa ratus orang. Jika Anda akan membagikan halaman di tempat besar, gunakan code component: lonjakan pendaftaran bot lewat server Framer hanya bisa dihentikan oleh penilaian spam.
Jalur 1: formulir Framer dengan webhook
- Tambahkan formulir ke halaman dengan satu input Email. Di pengaturan input, atur namanya ke
email. Framer mengirim nama setiap input sebagai key JSON, dan Ikiform memakaiemailuntuk reply-to dan pemeriksaan domain sekali pakai. - Pilih formulirnya. Di samping Send To, pilih Add… › Webhook dan tempel endpoint Anda,
https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx. Signing secret bersifat opsional; Ikiform tidak memeriksa tanda tangan Framer. - Di Ikiform, biarkan Allowed domains kosong dan spam check mati. Jika salah satunya aktif, setiap kiriman Framer akan ditandai atau ditolak, karena tidak membawa origin dan tidak bisa menjalankan pemeriksaan browser.
- Atur rate limit ke Relaxed, atau Custom di hari peluncuran. Standard menghitung semua kiriman Framer sebagai satu pengunjung, dan seluruh formulir dibatasi 300 per menit.
- Atur gaya state sukses formulir di Framer. State ini muncul saat Ikiform menjawab
201.
Jalur 2: code component
Di panel Assets, buka Code, buat file kode bernama WaitlistSignup, lalu tempel ini. Seret ke halaman dan atur Form ID di panel properti.
import { addPropertyControls, ControlType } from "framer";
import { type CSSProperties, type FormEvent, useRef, useState } from "react";
const box: CSSProperties = {
font: "inherit",
padding: "12px 14px",
borderRadius: 10,
border: "1px solid rgba(0, 0, 0, 0.15)",
};
interface Props {
formId: string;
buttonLabel: string;
joinedText: string;
source: string;
}
export default function WaitlistSignup({ formId, buttonLabel, joinedText, source }: Props) {
const [status, setStatus] = useState<"idle" | "sending" | "joined">("idle");
const [error, setError] = useState("");
const key = useRef("");
async function onSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
const body = new FormData(event.currentTarget);
const ref = new URLSearchParams(window.location.search).get("ref");
body.set("ref", (ref || source).slice(0, 40));
key.current ||= crypto.randomUUID();
setStatus("sending");
setError("");
try {
const response = await fetch(`https://ikiform.com/f/${formId}`, {
method: "POST",
headers: { Accept: "application/json", "Idempotency-Key": key.current },
body,
});
const result = await response.json();
if (result.ok) return setStatus("joined");
setError(result.error.fields?.email?.[0] ?? result.error.message);
} catch {
setError("Couldn't reach the server. Try again.");
}
setStatus("idle");
}
if (status === "joined") return <p role="status" style={{ margin: 0 }}>{joinedText}</p>;
return (
<form onSubmit={onSubmit} style={{ display: "flex", flexWrap: "wrap", gap: 8, width: "100%" }}>
<input
name="email"
type="email"
placeholder="you@company.com"
aria-label="Email"
autoComplete="email"
required
style={{ ...box, flex: "1 1 220px" }}
/>
<input name="_gotcha" type="text" tabIndex={-1} autoComplete="off" hidden />
<button type="submit" disabled={status === "sending"} style={{ ...box, cursor: "pointer" }}>
{status === "sending" ? "Joining" : buttonLabel}
</button>
{error ? <p role="alert" style={{ flexBasis: "100%", margin: 0 }}>{error}</p> : null}
</form>
);
}
addPropertyControls(WaitlistSignup, {
formId: { type: ControlType.String, title: "Form ID", defaultValue: "frm_xxxxxxxxxxxxxxxx" },
buttonLabel: { type: ControlType.String, title: "Button", defaultValue: "Join the waitlist" },
joinedText: { type: ControlType.String, title: "Joined text", defaultValue: "You're on the list." },
source: { type: ControlType.String, title: "Source", defaultValue: "framer" },
});- Panel properti menampilkan label tombol, teks setelah bergabung, dan Source default. Taruh satu instance di hero dengan
herodan satu lagi di footer denganfooter, dan Anda akan melihat mana yang lebih banyak menghasilkan pendaftaran. ?ref=di URL halaman lebih diutamakan daripada default, jadi link kampanye menandai dirinya sendiri.- Idempotency key dibuat saat pengiriman pertama dan dipakai ulang pada percobaan ulang dari kunjungan yang sama, jadi ketukan ganda di ponsel hanya menyimpan satu pendaftaran.
windowhanya dibaca di dalam submit handler. Framer merender komponen di server lebih dulu, dan menyentuhwindowsaat render akan merusaknya.
Pengaturan Ikiform untuk komponen
Tambahkan ini di tab Fields formulir, agar email wajib diisi dan ref diizinkan:
{
"version": 1,
"title": "Waitlist",
"fields": [
{ "id": "email", "type": "email", "label": "Email", "required": true },
{ "id": "ref", "type": "text", "label": "Source", "validation": { "max_length": 40 } }
]
}- Di Allowed domains, tambahkan
your-project.framer.appdan domain kustom Anda. Jangan pernah menambahkanframer.appsaja; setiap situs Framer akan cocok. - Biarkan spam check mati. Komponen mengirim dengan
fetchdan tidak mengambil token, jadi formulir dengan pemeriksaan aktif akan menjawab403 challenge_required. - Pertahankan rate limit Standard. Setiap pengunjung kini dihitung masing-masing.
Pastikan berfungsi
- Publikasikan situsnya. Webhook dan code component hanya mengirim dari situs yang sudah dipublikasikan, bukan dari preview editor.
- Kirim formulir di domain
framer.appAnda, lalu lagi di domain kustom Anda. - Buka Submissions di dashboard. Kiriman baru ada di sana dengan setiap field yang Anda kirim.
- Untuk komponen, buka halaman dengan
?ref=testdan pastikan pendaftaran menampilkanrefsebagaitest. - Periksa inbox setiap penerima notifikasi. Masing-masing mendapat email berisi field-field tersebut, dan Reply ditujukan ke pengirim jika formulir punya field
email. - Tidak ada yang masuk? Ubah filter status di dashboard ke Spam. Spam mendapat jawaban sukses yang sama dengan kiriman asli.
Jebakan
| Masalah | Yang harus dilakukan |
|---|---|
Setiap pendaftaran webhook masuk spam dengan origin_mismatch | Allowed domains sudah diatur, sedangkan kiriman dari server Framer tidak punya origin. Kosongkan untuk formulir ini, atau beralih ke code component. |
| Framer melaporkan pengiriman webhook yang gagal | Ikiform menolak kirimannya: 403 challenge_required karena spam check aktif, atau 422 karena nama input bukan email. Perbaiki penyebabnya; percobaan ulang akan gagal dengan cara yang sama. |
429 rate_limited | Satu pengunjung mengirim melebihi rate limit formulir. Standard mengizinkan 5 per menit per pengunjung. Tunggu sesuai Retry-After, atau pilih Relaxed atau Custom untuk formulir yang mengirim dari satu IP bersama. |
Komponen menampilkan Unknown field "ref" | Definisi field tidak mencantumkan ref. Tambahkan seperti pada definisi di atas. |
403 origin_not_allowed, atau setiap kiriman masuk ke spam | Domain halaman tidak ada di Allowed domains formulir. Tambahkan, ditambah localhost untuk tes lokal. Subdomain dari domain yang tercantum diizinkan. |
Setup Framer lengkap, termasuk versi formulir kontak, ada di panduan dokumentasi Framer. Ekspor daftar dan pengiriman email peluncuran ada di panduan utama.
Pertanyaan
Tidak sebagai action formulir. Formulir Framer mengirim ke tujuan milik Framer sendiri, dan salah satunya adalah webhook ke URL https mana pun. Gunakan itu untuk Ikiform, atau render formulir Anda sendiri dengan code component.
Dengan jalur webhook, Framer mengirim dari servernya tanpa header Origin, jadi formulir yang mengatur Allowed domains menandai setiap kiriman sebagai origin_mismatch. Biarkan Allowed domains kosong untuk formulir webhook.
Framer menyatakan kiriman formulir tidak terbatas, jadi pendaftaran lewat webhook tidak terbentur batas Framer. Jalur code component sama sekali tidak memakai formulir Framer.
Tidak, tidak ada paket gratis. Pengujian gratis: Anda bisa mengirim 50 kiriman uji per bulan dari localhost sebelum membayar. Untuk go live, Pro mulai $6/bln untuk 500 kiriman, atau Anda bisa bayar sekali untuk 10.000 kiriman seharga $49 atau 50.000 kiriman seharga $149, dengan kredit yang tidak pernah kedaluwarsa.
Mentok di salah satu langkah, atau ingin panduan untuk situasi Anda? Email hello@ikiform.com.