Track meeting attendance and no-shows
Log RSVPs against actual turnout for Northwind events — spot the chronic no-shows.
Published Sep 2, 2025
Northwind runs a lot of internal meetings — production briefs, client calls, the Monday all-hands — and the calendar is full of RSVPs that turn out to mean almost nothing. Half the “yes” replies never show up, the “maybe” column is quietly the largest, and nobody has the data to push back on a chronic no-shower without sounding accusatory.
This script logs every guest on yesterday’s events and their RSVP status to a spreadsheet. Run it daily and within a fortnight you have a real record — who accepted, who declined, who left it on “maybe” until the last minute. It does not measure attendance directly, but combined with a single “showed up” checkbox column it gives you the evidence to have the conversation.
What you’ll need
- A Google Sheet to act as the RSVP log. Note its ID from the URL and paste it
into the
RSVP_LOG_IDconstant below. Headers in row 1 of the first tab:Start,Event,Guest,RSVP status. - Access to the calendar you want to track. The script reads the user’s default
calendar via
CalendarApp.getDefaultCalendar(). - Nothing else — no API keys, no add-ons.
The script
// The spreadsheet that holds the RSVP log. The first tab gets appended to.
const RSVP_LOG_ID = '1abcRsvpLogId';
// Milliseconds in a day — used to walk back from "now" to "yesterday".
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
/**
* Logs every guest on yesterday's calendar events, with their RSVP status,
* as one row per guest in the RSVP log spreadsheet.
*/
function logRsvps() {
const today = new Date();
const yesterday = new Date(today.getTime() - ONE_DAY_MS);
// 1. Pull every event that started in the last 24 hours.
const events = CalendarApp.getDefaultCalendar().getEvents(yesterday, today);
const rows = [];
// 2. Flatten each event into one row per guest — start time, title,
// guest email and their RSVP status (YES / NO / MAYBE / INVITED).
for (const event of events) {
for (const guest of event.getGuestList()) {
rows.push([
event.getStartTime(),
event.getTitle(),
guest.getEmail(),
guest.getGuestStatus(),
]);
}
}
// 3. Nothing to append? Bail out before opening the spreadsheet.
if (!rows.length) {
Logger.log('No events with guests yesterday — nothing logged.');
return;
}
// 4. Append all rows in one setValues call — much faster than row-by-row.
const sheet = SpreadsheetApp.openById(RSVP_LOG_ID).getSheets()[0];
sheet.getRange(sheet.getLastRow() + 1, 1, rows.length, 4).setValues(rows);
Logger.log('Logged ' + rows.length + ' RSVP rows.');
}
How it works
logRsvpsbuilds a 24-hour window ending at the current moment, which is “yesterday” for a script that runs early each morning.- It calls
getEvents(yesterday, today)on the default calendar to fetch every event that overlapped that window. - For each event, it walks the guest list and pushes one row per guest: start time, event title, guest email, and the RSVP status string.
- If the window had no events with guests, it logs a message and returns — no need to open the spreadsheet for an empty append.
- Otherwise it opens the RSVP log, finds the next empty row with
getLastRow() + 1, and writes every new row in a singlesetValuescall.
Example run
After a Monday with two meetings, the log looks like this:
| Start | Event | Guest | RSVP status |
|---|---|---|---|
| 2025-09-01 09:00 | Production brief | [email protected] | YES |
| 2025-09-01 09:00 | Production brief | [email protected] | MAYBE |
| 2025-09-01 09:00 | Production brief | [email protected] | INVITED |
| 2025-09-01 14:00 | Client call: Fabrikam | [email protected] | YES |
| 2025-09-01 14:00 | Client call: Fabrikam | [email protected] | NO |
A fortnight of rows lets you pivot by guest and count YES versus MAYBE versus INVITED. The pattern shows up quickly — the people who reply, the people who never click the button, and the chronic “maybes” who clog up your headcount.
Trigger it
Run this once a day, early, so it covers the previous 24 hours before anyone starts editing today’s calendar:
- In the Apps Script editor, open Triggers (the clock icon).
- Add a trigger for
logRsvps, time-driven, day timer, between 5am and 6am. - Save and approve the calendar and spreadsheet authorisation prompts.
Watch out for
- RSVP status is what guests clicked, not whether they actually attended.
Add a
Showed upcolumn to the log and tick it manually (or with a second script that reads attendance from another source) if you want the full picture. - A daily window can miss long-running events that started two days ago and
ended yesterday.
getEventsreturns events that overlap the window, so this is rare in practice — but if your team books week-long blocks, widen the window to seven days and de-duplicate on event ID. getGuestStatus()returnsINVITEDfor guests who never responded. That is useful signal in its own right; treat it as “no reply” rather than a no.- The script appends — it never deduplicates. If you run it twice on the same day you will get duplicate rows. A simple guard is to record the event ID too and skip rows already present in the log.
Related
Send a feedback survey after each event
Email attendees a survey link automatically after Northwind workshops or trainings.
Updated Oct 24, 2025
Build a team-capacity view from calendars
Show how booked the Northwind team is this week — meeting hours per person.
Updated Oct 20, 2025
Flag meetings that could have been emails
Detect short, agendaless, oversized meetings — the smell of bad calendar hygiene.
Updated Oct 12, 2025
Send tiered deadline countdown reminders
Email Northwind teammates at 7, 3, and 1 days out from a Sheet of upcoming deadlines.
Updated Sep 30, 2025
Archive past events to a log sheet
Keep a searchable Northwind meeting history — every event logged with title, attendees, duration.
Updated Sep 26, 2025