Assign wedding table seating
14 guests at tables of 8 become 2 tables: the bride's family and the college friends fill the first, the groom's family and two guests with no group sit at the second, leaving 2 seats empty. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Table size
- 8
- Table count
- 2
- Guest count
- 14
- Empty seats
- 2
Guests who belong to the same group are seated at the same table whenever they fit, larger groups are placed first so they are not stranded by fragmented free seats, and any group that simply cannot fit at one table is reported as an error instead of being silently split. The result is a deterministic, ready-to-print seating chart.
A seating chart without the spreadsheet
Anyone who has planned a wedding knows the seating chart is the task that eats the last two weeks. The guest list is final, then an aunt calls, then a cousin cancels, and the carefully arranged tables fall apart. The wedding table seating chart generator removes the arithmetic from that loop.
You provide the list of guests, each tagged with the group they belong to — the bride's family, the groom's colleagues, the college friends — and the number of seats per table. The tool returns the tables, who sits at each one, and how many seats remain free. Change the list, run it again, and you get a fresh plan in milliseconds instead of an evening of dragging names around a document.
Because the algorithm is deterministic, the same input always produces the same chart, so you can compare two versions of the guest list with confidence that any difference comes from the data, not from chance.
How groups are kept together
The assignment uses a first-fit decreasing strategy, the standard approach for this kind of packing problem. First, guests are collected into their groups; a guest with no affiliation becomes a group of one, which is exactly right for plus-ones and colleagues who know nobody else. Groups are then ordered from largest to smallest, so the big family tables are claimed before the room fills up with couples and singles.
Each group is placed at the first table that still has enough free seats, and a new table opens only when no existing table can take the group whole.
Practical tips for a real wedding
Use groups that reflect how people actually want to sit, not every label you could invent: eight to fifteen meaningful affiliations is typical for a hundred-guest wedding. If your venue offers tables of different sizes, run the tool once per size and compare the empty seat counts — the output tells you exactly how many seats go unused, which is the number that matters when the caterer charges per place setting.
Couples who should sit together but belong to different circles can be given a shared group label to force the pairing. And remember the tool optimizes for cohesion and table count, not for politics: it will not know that two uncles should not share a table. Treat its output as a strong first draft, then move the two or three names your family knowledge says to move.
What you can do with it
Draft the reception seating chart
Turn a final guest list into a table plan in one call, and regenerate it instantly when RSVPs change.
Compare venue table sizes
Run the same list at tables of 8, 10 and 12 to see which layout wastes the fewest paid seats.
Seat a corporate dinner or gala
Keep departments and client teams together at banquet tables without hand-drawing the room.
FAQ
What about guests with no group?
Each unaffiliated guest is treated as a single-person group and is used to fill remaining seats after larger groups are placed.
Is the result always the same for the same list?
Yes. The algorithm is fully deterministic: identical input always yields an identical seating chart.
Does it minimize the number of tables?
It uses first-fit decreasing, a well-known packing heuristic that keeps group integrity first and typically uses very few tables, reporting the empty seat count so you can judge the layout.
What happens if one family is larger than a table?
The plan is not made and you get a clear message naming that group and its size. A family is never split across tables behind your back: that is a decision for you to make, not for the software.
How do I compare tables of different sizes?
Run the plan once for each table size your venue offers and compare the empty seats. That figure tells you how many places go unused, which matters when the caterer charges per place setting.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/life/wedding-guest-seating \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"guests":[{"name":"Ana","group":"Bride family"},{"name":"Luis","group":"Bride family"},{"name":"Marta","group":"College friends"},{"name":"Pablo","group":"College friends"},{"name":"Sofia"}],"table_size":8}'const res = await fetch("https://api.kit.forhosting.com/life/wedding-guest-seating", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"guests": [
{
"name": "Ana",
"group": "Bride family"
},
{
"name": "Luis",
"group": "Bride family"
},
{
"name": "Marta",
"group": "College friends"
},
{
"name": "Pablo",
"group": "College friends"
},
{
"name": "Sofia"
}
],
"table_size": 8
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/life/wedding-guest-seating",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"guests": [
{
"name": "Ana",
"group": "Bride family"
},
{
"name": "Luis",
"group": "Bride family"
},
{
"name": "Marta",
"group": "College friends"
},
{
"name": "Pablo",
"group": "College friends"
},
{
"name": "Sofia"
}
],
"table_size": 8
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/life/wedding-guest-seating", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"guests":[{"name":"Ana","group":"Bride family"},{"name":"Luis","group":"Bride family"},{"name":"Marta","group":"College friends"},{"name":"Pablo","group":"College friends"},{"name":"Sofia"}],"table_size":8}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"guests":[{"name":"Ana","group":"Bride family"},{"name":"Luis","group":"Bride family"},{"name":"Marta","group":"College friends"},{"name":"Pablo","group":"College friends"},{"name":"Sofia"}],"table_size":8}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/life/wedding-guest-seating", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"guests": [
{
"name": "Ana",
"group": "Bride family"
},
{
"name": "Luis",
"group": "Bride family"
},
{
"name": "Marta",
"group": "College friends"
},
{
"name": "Pablo",
"group": "College friends"
},
{
"name": "Sofia"
}
],
"table_size": 8
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "life.wedding_guest_seating",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_guests | 1000 |
max_groups | 200 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
The wedding table seating API takes a guest list — each guest with an optional group affiliation such as a family branch or a circle of friends — and a table size, and returns a complete table plan.
How groups are kept together
A group is never split across tables: if a single affiliation has more members than the table size, the API rejects the input with a clear error naming the group and its size, because a split family is a planning decision you should make yourself, not something software should decide silently.
Technical questions
What does it cost?
$0.002 per request. It is also free to run in your browser on this page with the same engine.
What happens if a group is bigger than a table?
The request fails with an invalid_input error naming the group and its size. Groups are never split automatically.
How many guests can it handle?
Up to 1000 guests and 200 distinct groups per request, far beyond any wedding.