# Formulir Framer: kapan menambahkan backend formulir, dan caranya

> Formulir Framer sudah mengirim ke email, Sheets, atau webhook; tambahkan Ikiform sebagai webhook untuk kiriman yang tersimpan dan tersaring, notifikasi tim, dan lebih banyak tujuan.

Terbit 2026-10-25 · https://ikiform.com/id/guides/website-builder-forms/framer-forms

Formulir bawaan Framer mengirim setiap kiriman ke email, Google Sheets, atau webhook, dengan perlindungan spam bawaan, jadi untuk satu inbox atau satu sheet Anda mungkin tidak butuh yang lain. Tambahkan Ikiform sebagai tujuan webhook saat Anda ingin setiap kiriman disimpan dengan status spam, divalidasi terhadap field Anda, dikirim lewat email ke tim, dan diteruskan ke beberapa webhook bertanda tangan. Karena Framer mengirim dari server-nya, longgarkan pemeriksaan origin formulir atau taruh relay kecil di antaranya yang memverifikasi tanda tangan Framer.

## Apa bedanya di Framer

Framer satu-satunya builder di panduan ini yang tidak punya batas untuk dihindari. Formulirnya bisa mengirim ke email, Google Sheets, atau webhook apa pun, dan Framer punya perlindungan spam bawaan yang menandai atau memblokir kiriman mencurigakan. Webhook-nya bertanda tangan: setiap request membawa header `Framer-Signature`, yaitu HMAC-SHA256 dari body dan id kiriman, serta `Framer-Webhook-Submission-Id`. Framer mencoba ulang hingga lima kali saat endpoint Anda tidak menjawab `2xx`, dan tidak mengikuti redirect.

Jadi jujurlah tentang alasan Anda menambahkan backend formulir. Berikut yang dicakup masing-masing:

| Yang Anda inginkan | Framer saja | Dengan Ikiform sebagai webhook |
| --- | --- | --- |
| Kiriman di satu inbox atau satu sheet | Ya | Ya, plus dashboard |
| Catatan yang bisa dicari dengan tanda spam, dan ekspor CSV | Inbox atau sheet Anda adalah catatannya | Ya |
| Pemeriksaan sisi server untuk tipe, panjang, dan opsi | Tidak | Ya, dengan definisi field |
| Notifikasi ke beberapa orang, dengan Reply ditujukan ke pengirim | Tujuan email | Hingga 10 penerima, dengan reply-to |
| Beberapa alat diisi dari satu formulir, masing-masing dengan percobaan ulang | Satu webhook per tujuan yang Anda tambahkan | Hingga 3 endpoint bertanda tangan, dengan percobaan ulang dan log pengiriman |
| Backend yang sama di Framer, Webflow, dan situs berbasis kode | Tidak | Ya |

Jika baris pertama sudah cukup, tetap pakai tujuan bawaan Framer. Sisa halaman ini untuk saat itu tidak cukup.

## Kendalanya: Framer mengirim dari server-nya

Tujuan webhook berarti server Framer yang mengirim post, bukan browser pengunjung. Tiga hal berubah di sisi Ikiform:

- **Tanpa origin.** Post dari server tidak membawa header `Origin`, jadi dengan **Allowed domains** diatur, setiap post dianggap datang dari situs yang salah.
- **Alamat IP bersama.** Ikiform menghitung rate limit per alamat IP, dan setiap post datang dari beberapa alamat Framer, bukan dari alamat pengunjung Anda.
- **Tanpa honeypot.** Framer hanya mengirim input yang Anda buat, dan formulirnya tidak bisa menjalankan pemeriksaan manusia Ikiform.

Anda bisa menerimanya, atau memperbaikinya dengan relay. Kedua jalur ada di bawah.

Diagram: Formulir Framer yang mengirim ke Ikiform secara langsung, dan lewat relay bertanda tangan

1. Langsung: pengunjung mengirim formulir Framer, server Framer mengirimnya sebagai JSON tanpa header Origin, dan Ikiform menerimanya dengan Allowed domains kosong dan rate limit Relaxed.
2. Relay: server Framer menandatangani setiap post dengan secret Anda dan mengirimnya ke Worker yang Anda deploy.
3. Worker menghitung ulang tanda tangan Framer. Post tanpa tanda tangan valid mendapat 401 dan tidak diteruskan.
4. Post yang valid diteruskan ke Ikiform dengan secret key Anda dan id kiriman Framer sebagai idempotency key, jadi percobaan ulang Framer tidak pernah menyimpan salinan kedua.

Relay hanya berisi selusin baris logika. Sebagai gantinya, formulir bisa mempertahankan allowed domains yang ketat, karena hanya Worker Anda yang memegang secret key.

## Opsi 1: Ikiform sebagai webhook

1. Di Framer, beri setiap input nama huruf kecil: `name`, `work_email`, `company`, `team_size`. Framer memakai nama itu sebagai key JSON.
2. Pilih formulir, dan di sebelah **Send To** pilih **Add…** > **Webhook**. Tempel endpoint Anda. Biarkan secret kosong; Ikiform tidak memeriksa `Framer-Signature`.
3. Di pengaturan formulir Ikiform, biarkan **Allowed domains** kosong, biarkan **Spam check** mati, dan atur **Rate limit** ke **Relaxed**.
4. Publikasikan. Framer hanya mengirim webhook dari situs yang dipublikasikan.

`URL webhook`:

```text
https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx
```

Ikiform menjawab `201` setelah kiriman tersimpan, yang dianggap Framer sebagai terkirim. `422 validation_failed` gagal dengan cara yang sama di kelima percobaan ulang, jadi perbaiki nama input alih-alih menunggu. Penilaian spam tetap berjalan di setiap post: tautan, frasa spam, alamat sekali pakai, dan pengulangan.

## Opsi 2: relay bertanda tangan

Deploy Cloudflare Worker yang memeriksa tanda tangan Framer dan meneruskan post yang valid dengan secret key Anda. Lalu formulir Ikiform bisa mencantumkan domain Framer Anda di **Allowed domains** dengan **Reject**, jadi apa pun yang bukan browser di situs Anda atau Worker Anda akan ditolak.

`src/index.ts`:

```ts
interface Env {
  FRAMER_SECRET: string;
  IKIFORM_SECRET_KEY: string;
}

const ENDPOINT = "https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx";
const encoder = new TextEncoder();

async function signatureFor(secret: string, body: ArrayBuffer, submissionId: string) {
  const key = await crypto.subtle.importKey(
    "raw",
    encoder.encode(secret),
    { name: "HMAC", hash: "SHA-256" },
    false,
    ["sign"],
  );
  const id = encoder.encode(submissionId);
  const message = new Uint8Array(body.byteLength + id.byteLength);
  message.set(new Uint8Array(body), 0);
  message.set(id, body.byteLength);
  const digest = new Uint8Array(await crypto.subtle.sign("HMAC", key, message));
  return `sha256=${[...digest].map((byte) => byte.toString(16).padStart(2, "0")).join("")}`;
}

function sameText(a: string, b: string) {
  const left = encoder.encode(a);
  const right = encoder.encode(b);
  return left.byteLength === right.byteLength && crypto.subtle.timingSafeEqual(left, right);
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    if (request.method !== "POST") return new Response(null, { status: 405 });
    const signature = request.headers.get("framer-signature") ?? "";
    const submissionId = request.headers.get("framer-webhook-submission-id") ?? "";
    const body = await request.arrayBuffer();
    if (!submissionId || !sameText(signature, await signatureFor(env.FRAMER_SECRET, body, submissionId))) {
      return new Response("Bad signature", { status: 401 });
    }

    const response = await fetch(ENDPOINT, {
      method: "POST",
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
        Authorization: `Bearer ${env.IKIFORM_SECRET_KEY}`,
        "Idempotency-Key": submissionId,
      },
      body,
    });
    if (response.ok) return new Response(null, { status: 204 });
    return new Response(await response.text(), { status: response.status });
  },
};
```

### Deploy

`Terminal`:

```bash
npx wrangler secret put FRAMER_SECRET
npx wrangler secret put IKIFORM_SECRET_KEY
npx wrangler deploy
```

- `FRAMER_SECRET` adalah secret yang Anda atur di tujuan webhook Framer. Framer mensyaratkan minimal 32 karakter dan tidak akan menampilkannya lagi, jadi buat, simpan, dan tempel di kedua tempat.
- `IKIFORM_SECRET_KEY` adalah secret API key dari dashboard Ikiform. Jangan pernah menaruhnya di Framer.
- Tanda tangannya adalah `sha256=` ditambah HMAC heksadesimal dari body mentah diikuti id kiriman. Baca body sekali sebagai byte dan gunakan byte yang sama untuk pemeriksaan dan penerusan.
- `Idempotency-Key` membuat percobaan ulang Framer memutar ulang jawaban pertama Ikiform alih-alih menyimpan duplikat. Key disimpan selama 24 jam.
- Worker meneruskan status dari Ikiform. Framer mencoba ulang jawaban apa pun yang bukan `2xx`, hingga lima kali, jadi `429` atau `5xx` mendapat kesempatan lagi, sedangkan `422` gagal dengan cara yang sama setiap kali sampai Anda memperbaiki nama input.

Lalu arahkan webhook Framer ke URL Worker alih-alih ke endpoint, dengan secret diisi.

> Setiap post kini datang dari Worker Anda. Versi sisi server mengirim dengan secret key, jadi Ikiform melewati **Allowed domains** dan pemeriksaan manusianya. Setiap post lalu datang dari IP server Anda, dan batas Standard 5 per menit per pengunjung menghitung semua pengunjung Anda bersama-sama. Pilih [rate limit](https://ikiform.com/id/docs/rate-limits.md) Relaxed atau Custom untuk formulir yang Anda kirim lewat server, dan simpan `IKIFORM_SECRET_KEY` di environment variable khusus server.

## Opsi 3: lewati formulir Framer

Code component merender formulir sungguhan dan mengirim dari browser pengunjung, jadi pemeriksaan origin, honeypot, dan rate limit per pengunjung bekerja seperti di situs mana pun. Anda kehilangan pengeditan formulir visual Framer untuk formulir itu. [Panduan dokumentasi Framer](https://ikiform.com/id/docs/guides/framer.md#code-component) berisi komponennya.

## Pastikan berfungsi di Framer

1. Publikasikan situs Framer dan kirim formulir di sana, bukan di preview editor.
2. Buka **Submissions** di dashboard. Kiriman baru ada di sana dengan setiap field yang Anda kirim.
3. Periksa bahwa nama field persis sama dengan nama input Anda, tanpa key tambahan dari Framer.
4. Untuk relay: kirim request ke Worker dengan `Framer-Signature` karangan dan pastikan jawabannya `401`.
5. Untuk relay: di detail kiriman, origin kosong dan statusnya received, bukan spam.
6. Cek inbox setiap penerima notifikasi. Masing-masing mendapat email berisi field, dan **Reply** terkirim ke pengirim formulir jika formulir punya field `email`.
7. Jika Anda menambahkan webhook, buka endpoint-nya di **Webhooks**. Pengiriman menampilkan `succeeded` dengan jawaban dari server Anda.

## Hal yang sering menjebak

| Masalah | Yang harus dilakukan |
| --- | --- |
| Setiap post webhook masuk spam dengan `origin_mismatch` | **Allowed domains** diatur sementara Framer mengirim langsung. Kosongkan, atau taruh relay di antaranya. |
| Worker menjawab `401` untuk post asli | Secret berbeda antara Framer dan Worker, atau ada yang membaca body sebagai teks dan mengubahnya. Tempel secret lagi dan hash byte mentahnya. |
| `429 rate_limited` saat peluncuran | Semua post berbagi alamat Framer atau Cloudflare. Pilih **Relaxed**, atau batas Custom. |
| `422 validation_failed` | Kiriman tidak cocok dengan definisi field formulir. `error.fields` menyebutkan setiap field dan alasannya. Samakan `name` input dengan ID field. |
| `403 challenge_required` | Spam check formulir diatur ke **Ikiform** dan kiriman `fetch` tidak membawa token. Ambil token dengan `challenge(formId)` dari `@ikiform/sdk` sebelum setiap pengiriman, atau matikan pemeriksaannya. |

## Pertanyaan

### Apakah saya butuh backend formulir untuk formulir Framer?

Tidak selalu. Framer sendiri mengirim kiriman ke email, Google Sheets, atau webhook. Tambahkan Ikiform saat Anda menginginkan catatan yang tersimpan dan tersaring, validasi sisi server, notifikasi tim dengan reply-to, atau beberapa webhook dengan percobaan ulang dari satu formulir.

### Apakah Ikiform memverifikasi tanda tangan webhook Framer?

Tidak. Ikiform mengautentikasi post berdasarkan origin atau secret API key Anda, bukan header Framer. Untuk memeriksa Framer-Signature, taruh relay kecil di antara Framer dan Ikiform yang memverifikasinya dan meneruskan dengan secret key Anda.

### Mengapa kiriman Framer saya ditandai sebagai spam?

Paling sering karena Allowed domains diatur. Post webhook Framer datang dari server-nya tanpa header Origin, jadi tidak cocok dengan domain mana pun. Kosongkan daftarnya, atau gunakan relay yang mengirim dengan secret key Anda.

### Apakah percobaan ulang Framer membuat kiriman duplikat?

Bisa saat mengirim langsung, jika pengiriman dicoba ulang setelah Ikiform menyimpannya. Relay mengirim id kiriman Framer sebagai idempotency key, jadi percobaan ulang memutar ulang jawaban pertama.

### Bisakah formulir menerima upload file?

Belum. Kiriman yang berisi file ditolak dengan 422 files_not_supported. Minta link ke file sebagai gantinya, seperti URL shared drive.

## Panduan lainnya

- [Melampaui formulir builder](https://ikiform.com/id/guides/website-builder-forms.md): Saat formulir Webflow, Netlify, Carrd, atau Framer mentok di batas atau kekurangan fitur, pertahankan formulir yang Anda desain dan arahkan ke backend formulir.
- [Batas kiriman Webflow](https://ikiform.com/id/guides/website-builder-forms/webflow-submission-limit.md): Paket gratis Starter Webflow berhenti mengumpulkan setelah 50 kiriman formulir per situs dan situs yang diekspor tidak mendapat apa-apa, jadi arahkan Form Block ke Ikiform.
- [Formulir Carrd](https://ikiform.com/id/guides/website-builder-forms/carrd-forms.md): Formulir kontak Carrd hanya mengirim email ke Anda dan formulir kustom butuh Pro Plus, jadi gunakan Send to URL di Plus atau embed HTML di Standard untuk menyimpan setiap kiriman.
- [Batas Netlify Forms](https://ikiform.com/id/guides/website-builder-forms/netlify-forms-limit.md): Paket Netlify lama menghitung kiriman formulir per situs dan meng-upgrade Anda otomatis, dan paket kredit bisa menjeda situs, jadi pindahkan formulir ke backend.
