# Wedding RSVP form on your own wedding website

> An RSVP form for a wedding website you built yourself: one reply per invitation, a meal per named guest, a deadline and a list of who hasn't replied.

Published 2026-10-25 · https://ikiform.com/guides/event-registration/wedding-rsvp

Give each invitation its own RSVP link that carries an invitation code and the guests' names, and let the form show one name and meal choice per guest. Every reply posts to Ikiform, so you get an email for each and a CSV to hand the caterer. Match replies to your guest list in a spreadsheet to see who hasn't answered, and pause the form after your deadline.

## What's different about a wedding

A meetup counts strangers. A wedding counts a guest list you already have, invitation by invitation. Four things follow from that:

- **One reply per invitation, not per person.** A couple or a family answers together.
- **Named guests, not a guest count.** You invited Ada and Sam, not `2`. Plus-ones are on the invitation or they aren't.
- **A meal per person.** The caterer needs fish, beef and vegetarian totals, plus children's plates.
- **A hard deadline and a chase list.** The venue wants numbers by a date, and the useful list is who hasn't replied.

Wedding website services such as Zola, The Knot and Joy have RSVP tools built around a guest list, with lookups by name. If you're using one of them for your site, use its RSVP. This page is for a wedding site you made yourself, on Squarespace, Carrd, Framer or plain HTML, where you want the RSVP on your own page.

Ikiform has no guest list lookup and no repeating groups, so the form can't know who is on an invitation by itself. The trick is to put that knowledge in the link.

Diagram: From the guest list to the caterer's numbers, with personal RSVP links

1. Your guest list sheet has one row per invitation: a short code, the household name and the guests' names.
2. A formula turns each row into a personal RSVP link that carries the code and the names.
3. You print the link as a QR code on the invitation, or send it in a message.
4. The RSVP page reads the link and shows one name and one meal choice per guest, then posts to Ikiform.
5. You export the replies as CSV and import them next to the guest list.
6. Matching codes shows which invitations haven't replied, so you know who to chase.
7. Counting each meal across the replies gives the caterer's totals.

The guest list stays in your sheet. The link carries only enough of it to make the form personal.

## Make a link for each invitation

In your guest list sheet, put a short code in column A, such as `okafor` or `nguyen-family`, the household in B, and the guests' first names in C, separated by commas. This formula in D builds the link:

`Guest list, column D`:

```text
="https://ada-and-sam.example/rsvp?party=" & A2 & "&names=" & ENCODEURL(C2)
```

Print each link as a QR code on the invitation, or paste it into a message. Keep codes lowercase with hyphens; the field's pattern refuses anything else, which catches a mistyped code early.

## The form

Paste this into your wedding page, or into an embed block on a builder. It reads `party` and `names` from the link, adds one name and meal row per guest, up to four, and hides itself after the deadline. With no names in the link, it shows a single row to fill in.

`rsvp.html`:

```html
<form id="rsvp" action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <input type="hidden" name="party" id="party">
  <div id="guests"></div>
  <label>Email for updates <input name="email" type="email" autocomplete="email" required></label>
  <label>A song that gets you dancing <input name="song" maxlength="120"></label>
  <label>Anything we should know? <textarea name="note" rows="3" maxlength="1000"></textarea></label>
  <input type="hidden" name="_redirect" value="https://ada-and-sam.example/thank-you">
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden>
  <button type="submit">Send our RSVP</button>
</form>
<p id="closed" hidden>RSVPs closed on 1 May. Message us if your plans have changed.</p>

<template id="guest-row">
  <fieldset>
    <legend></legend>
    <label>Name <input data-part="name" maxlength="80" autocomplete="off"></label>
    <label>Meal
      <select data-part="meal">
        <option value="beef">Beef</option>
        <option value="fish">Fish</option>
        <option value="vegetarian">Vegetarian</option>
        <option value="child">Child's menu</option>
        <option value="not_coming">Can't come</option>
      </select>
    </label>
  </fieldset>
</template>

<script>
  const DEADLINE = new Date("2027-05-01T23:59:00+01:00");
  const params = new URLSearchParams(location.search);
  const party = (params.get("party") ?? "").toLowerCase();
  const names = (params.get("names") ?? "").split(",").map((name) => name.trim()).filter(Boolean).slice(0, 4);
  const rsvp = document.getElementById("rsvp");

  if (Date.now() > DEADLINE.getTime()) {
    rsvp.hidden = true;
    document.getElementById("closed").hidden = false;
  } else {
    document.getElementById("party").value = party;
    const rows = names.length ? names : [""];
    rows.forEach((name, index) => {
      const n = index + 1;
      const row = document.getElementById("guest-row").content.cloneNode(true);
      row.querySelector("legend").textContent = name || "Your name";
      const input = row.querySelector('[data-part="name"]');
      input.name = `guest_${n}_name`;
      input.value = name;
      input.required = n === 1;
      row.querySelector('[data-part="meal"]').name = `guest_${n}_meal`;
      document.getElementById("guests").append(row);
    });
  }
</script>
```

- Each guest's meal includes `Can't come`, so a household where one person can't make it still sends one reply.
- The name inputs are filled in but editable, so a guest can fix a spelling or name a child.
- The form posts the plain way and lands on your thank-you page through `_redirect`. Put the date, venue and a calendar link there; Ikiform doesn't email your guests.
- The deadline only hides the form in the browser. On the deadline, choose **Pause form** in Ikiform too, so a saved tab can't post. Paused forms answer `403 form_paused`.

Paste this definition on the form's **Fields** tab. Try it: an invitation code with a capital letter or a space fails the pattern, with the message you set.

Form: Wedding RSVP

- **Invitation code** (`party`, text, required)
- **Email for updates** (`email`, email, required)
- **Guest 1 name** (`guest_1_name`, text, required)
- **Guest 1 meal** (`guest_1_meal`, select, required)
- **Guest 2 name** (`guest_2_name`, text)
- **Guest 2 meal** (`guest_2_meal`, select)
- **Guest 3 name** (`guest_3_name`, text)
- **Guest 3 meal** (`guest_3_meal`, select)
- **Guest 4 name** (`guest_4_name`, text)
- **Guest 4 meal** (`guest_4_meal`, select)
- **A song that gets you dancing** (`song`, text)
- **Anything we should know?** (`note`, textarea)

Fields are in invitation order, so the CSV has each guest's name followed by their meal. Only the first guest is required.

## Who hasn't replied, and what to order

1. Export the RSVPs as CSV from **Submissions** and import them into a tab called `Replies` in the guest list spreadsheet.
2. If an invitation replied twice, keep its newest row: sort by `created_at`, newest first, and remove duplicates on the `party` column.
3. List invitations with no reply, with the codes in column A of the guest list and `party` in column E of Replies:

`Not replied`:

```text
=FILTER(A2:C, A2:A <> "", ISNA(MATCH(A2:A, Replies!E2:E, 0)))
```

Then count each meal for the caterer. Names never equal a meal value, so one range across all guest columns works:

`Fish plates`:

```text
=COUNTIF(Replies!G2:N, "fish")
```

| Number | How |
| --- | --- |
| People coming | Add the counts for `beef`, `fish`, `vegetarian` and `child` |
| Can't come | `COUNTIF` the same range for `not_coming` |
| Children's plates | `COUNTIF` for `child`, which most caterers price separately |
| Dietary notes | Read the `note` column. Allergies hide there |

> Notification emails arrive with each guest's email as reply-to, so you can answer questions straight from your inbox. Ikiform emails you and your partner, not your guests.

## Before you send the invitations

- Set **Allowed domains** to your wedding site's domain, and the builder's staging domain while you test.
- Ikiform doesn't merge or reject repeat submissions by email. An identical repeat within 24 hours only adds to the spam score. Deduplicate where the list lives, or when you export. The newest reply per code is the answer.
- Anyone with a link can change its code or names. That's fine for a wedding; your sheet decides who was invited, and the not-replied list shows anything odd.
- Older relatives may not use the form at all. Note phone and paper replies in your sheet so the counts stay complete.

## Check it before the invitations go out

1. Open your own invitation link on a phone. The names show, each with a meal choice.
2. Choose `Can't come` for one guest, send it, and land on your thank-you page.
3. Open **Submissions** in the dashboard. The new submission is there with every field you sent.
4. Check the inbox of each notification recipient. Each gets an email with the fields, and **Reply** goes to the submitter when the form has an `email` field.
5. Import the CSV, and check the not-replied list no longer shows your code.
6. Set the deadline to yesterday on a test copy and confirm the form hides.

## Gotchas

| Problem | What to do |
| --- | --- |
| `422` with `party: Use the link from your invitation` | The code has capitals, spaces or other characters. Fix the code in the sheet, or have the guest use their link. |
| A guest sees one empty row instead of names | The link lost its `names` part, often when a messaging app shortened it. Send the full link or the QR code. |
| `422 validation_failed` | The post doesn't match the form's field definition. `error.fields` names each field and the reason. Match the input `name` to the field id. |
| `403 origin_not_allowed`, or every post lands in spam | The page's domain isn't in the form's **Allowed domains**. Add it, plus `localhost` for local tests. Subdomains of a listed domain are allowed. |
| The browser lands on Ikiform's thank-you page instead of yours | `_redirect` is ignored unless its domain is in **Allowed domains** and it is an `https:` URL. Add the domain, or set **Redirect after submit** in the form's settings instead. |

## Questions

### Can guests see who else is coming?

No. RSVPs go to your Ikiform dashboard and your inbox. Nothing is published back to the site.

### Can the form send guests a confirmation email?

Not from Ikiform, which emails only you. Show the details on the thank-you page, or send each reply by webhook to an email tool and send the confirmation from there.

### How do I stop RSVPs after the deadline?

Hide the form on the page after the date, as the sample does, and choose Pause form in Ikiform. A paused form refuses new posts with 403 form_paused.

### What if a guest replies twice?

Both replies are stored. Keep the newest one per invitation code when you count, by sorting newest first and removing duplicates on the code.

### Is Ikiform free?

No, there is no free plan. Testing is free: you can send 50 test submissions a month from localhost before you pay. To go live, Pro starts at $6/mo for 500 submissions, or you can pay once for 10,000 submissions for $49 or 50,000 submissions for $149, with credits that never expire.

## More guides

- [Event registration](https://ikiform.com/guides/event-registration.md): Take RSVPs on your own event page: the form, guest limits, an honest headcount, closing when full and a check-in list, without a ticketing app.
- [Without Eventbrite](https://ikiform.com/guides/event-registration/without-eventbrite.md): Run registration for a free community event on your own site: session choices, a confirmation email from your own tool, room counts and a check-in list.
- [Volunteer signup](https://ikiform.com/guides/event-registration/volunteer-signup.md): A volunteer signup form where people pick shifts, with a phone number for the day, and a script that shows which shifts are short and builds the rota.
