Event registration

Event registration7 min read

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.

Preet SutharFounder, Ikiform

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.

From the guest list to the caterer's numbers, with personal RSVP linksguestlistsheetone rowperinvitationpersonallink?party=okafor&names=Ada,SamRSVPpagea mealfor eachnameIkiformstores,emailsyouCSVexportrepliestabnext tothe guestlistnotrepliedchasethesemealtotalsfor thecatererformulaQR or messagepostimportmatchFrom the guest list to the caterer's numbers, with personal RSVP linksguest list sheetone row per invitationpersonal link?party=okafor&names=Ada,SamRSVP pagea meal for each nameIkiformstores, emails youCSV exportreplies tabnext to the guest listnot repliedchase thesemeal totalsfor the catererformulaQR or messagepostimportmatch
  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.

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
="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
<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.

Preview

Runs Ikiform's validator in your browser. Nothing is sent.

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
=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
=COUNTIF(Replies!G2:N, "fish")
NumberHow
People comingAdd the counts for beef, fish, vegetarian and child
Can't comeCOUNTIF the same range for not_coming
Children's platesCOUNTIF for child, which most caterers price separately
Dietary notesRead 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

ProblemWhat to do
422 with party: Use the link from your invitationThe 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 namesThe link lost its names part, often when a messaging app shortened it. Send the full link or the QR code.
422 validation_failedThe 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 spamThe 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

Stuck on a step, or want a guide for your situation? Email hello@ikiform.com.