Cellbrook

Google Sheets guide · Calendars

How to export Google Calendar attendees to Google Sheets

Google Calendar shows who is invited to an event and who has replied, but it only offers to export that list for very large events. This guide gives you a free script that writes one row per guest into a sheet, with each person’s reply, shows what the no-code route can and can’t export, and covers the privacy side of keeping a guest list.

Add CalendarRows to Google SheetsFree to install from the Google Workspace Marketplace

Updated · 11 min read · By the Cellbrook team

The short answer

For most events, Google Calendar has no export for the guest list. Google’s own Export guest responses to Sheets button exists, but its help page describes it for events with 200 or more guests, and you need edit rights to the event. For a normal meeting or class you can copy the guest list by hand, or download the calendar as an .ics file, which holds an attendee line for every guest but isn’t a tidy table. The practical way to get a table for many events at once is a short Google Apps Script that reads your events, loops over each event’s guests, and writes one row per guest into a sheet.

That is what the script below does. It lists, for every event in a date range you choose, each guest’s name, email address and reply. The reply is the useful part: YES, NO, MAYBE, or INVITED if they haven’t answered. It takes about five minutes to set up, it is free, and it does not need CalendarRows or anything else.

If you don’t want a script and you only need the email addresses, CalendarRows can import a calendar into a tab with a Guests column. We explain below what that does and doesn’t include.

What you get, and what you don’t

The script gives you a flat table. Every guest of every event becomes its own row, so a workshop with 30 guests makes 30 rows that all carry the workshop’s title and start time. That shape is what pivot tables, filters and COUNTIF want.

ColumnContainsExample
EventThe event titleSpring workshop
StartWhen the event starts2026-11-10 10:00
All dayTRUE for all-day eventsFALSE
NameThe guest’s name, when Google has oneSam Rivera
EmailThe guest’s email addresssam@example.com
ReplyOWNER, YES, NO, MAYBE or INVITEDYES

A few limits are worth knowing before you build a process on this:

  • You only see what Google shows you. If the organiser hid the guest list from guests, an event you were invited to can come back with no guests. Events on your own calendar always show their guests to you.
  • Groups may show as one address. If someone invited a mailing list or group, the script may list only that address, not the people behind it. Google shows a group’s members only to people with permission to see them.
  • Replies are as of the moment you run it. It is a snapshot. Run it again to refresh.
  • Repeating events appear once per occurrence inside your date range, each with its own set of guests.
  • Rooms count as guests. Meeting rooms and other resources show up with an address ending in resource.calendar.google.com.

The free script

Open the spreadsheet where you want the list, choose Extensions → Apps Script, delete the sample code, paste in the script below and click Save. Before you run it, change the settings at the top: the calendar, the first day, the day to stop before, and optionally a word to search for.

// Lists who is invited to each event in a date range, with each person's reply, one row per guest.
// Writes to a tab named "Attendees". The tab is rewritten each run, so copy rows elsewhere to keep them.
const ATT_CALENDAR_ID = 'primary';   // or a Calendar ID from Settings and sharing > Integrate calendar
const ATT_FROM = '2026-11-01';       // first day to include (YYYY-MM-DD)
const ATT_TO = '2026-12-01';         // day to stop before (YYYY-MM-DD), so this covers all of November
const ATT_SEARCH = '';               // optional: only events whose text contains this, e.g. 'workshop'
const ATT_TAB_NAME = 'Attendees';

function exportAttendees() {
  const ss = SpreadsheetApp.getActive();
  const sheet = ss.getSheetByName(ATT_TAB_NAME) || ss.insertSheet(ATT_TAB_NAME);
  const cal = ATT_CALENDAR_ID === 'primary' ? CalendarApp.getDefaultCalendar() : CalendarApp.getCalendarById(ATT_CALENDAR_ID);
  if (!cal) throw new Error('Calendar not found. Check ATT_CALENDAR_ID.');
  const from = parseDayAtt_(ATT_FROM), to = parseDayAtt_(ATT_TO);
  if (!from || !to || to <= from) throw new Error('Check ATT_FROM and ATT_TO: use YYYY-MM-DD and put the end after the start.');
  const options = ATT_SEARCH ? { search: ATT_SEARCH } : {};
  const events = cal.getEvents(from, to, options);
  const rows = [];
  let noGuests = 0;
  events.forEach(function (e) {
    const guests = e.getGuestList(true);   // true = include the organiser
    if (!guests.length) { noGuests++; return; }
    guests.forEach(function (g) {
      rows.push([e.getTitle(), e.getStartTime(), e.isAllDayEvent(), g.getName() || '', g.getEmail(), String(g.getGuestStatus())]);
    });
  });
  const header = [['Event', 'Start', 'All day', 'Name', 'Email', 'Reply']];
  sheet.clearContents();
  sheet.getRange(1, 1, 1, 6).setValues(header);
  if (rows.length) sheet.getRange(2, 1, rows.length, 6).setValues(rows);
  sheet.getRange(1, 8).setValue('Events in range: ' + events.length + ', without guests: ' + noGuests + ', guest rows: ' + rows.length);
  sheet.getRange(2, 8).setValue('Exported: ' + new Date().toString());
}

function parseDayAtt_(s) {
  const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(String(s).trim());
  return m ? new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3])) : null;
}

What the settings do:

  • ATT_CALENDAR_ID: 'primary' is your main calendar. For another calendar, open Settings and sharing for it in Google Calendar and copy the Calendar ID from Integrate calendar.
  • ATT_FROM and ATT_TO: the range, written as YYYY-MM-DD. The end day is not included, so 2026-12-01 as the end covers all of November.
  • ATT_SEARCH: leave empty for everything, or put a word such as 'workshop' to keep only events whose text contains it. Google matches it against the event’s text.
  • ATT_TAB_NAME: the tab the script writes to. It creates the tab if it doesn’t exist.

The script reads the events once, skips events with no guests (and counts them), and writes the rows in one go. A note in column H says how many events it found, how many had no guests and how many guest rows it wrote, so you can tell “nobody was invited” from “the range was wrong”.

We tested the logic with stand-ins for the Calendar and Sheets services. The tests cover an event with several guests and a mix of replies, an event with no guests, an all-day event, an event outside the range, running the script twice (the tab is replaced, not added to), the search setting, a calendar ID that doesn’t exist, and a date typed in the wrong format. Stand-ins are not Google itself, so run it once on a small range and compare it with what Calendar shows for one event.

Run it

  1. In the function menu above the editor, choose exportAttendees and click Run.
  2. Google asks you to authorise the script. It needs to read your calendars and edit your spreadsheet. Because you wrote (pasted) the script yourself, Google shows a warning that the app isn’t verified: click Advanced, then Go to (your project name), and allow it. This is normal for personal scripts.
  3. Switch back to the spreadsheet. A tab named Attendees now has your list.

The tab is rewritten each time you run the script, so keep your own notes and formulas on other tabs and point them at Attendees!A:F. To keep a copy of today’s list, copy the tab (right-click the tab → Duplicate) before the next run.

If you want the list to refresh by itself, open Triggers (the clock icon), click Add Trigger, choose exportAttendees, event source Time-driven, and pick Day timer. For an event that fills up over several weeks, a daily refresh is usually enough.

What to do with the list

Because every row is one guest, a few formulas answer the questions people usually ask. These assume the tab is called Attendees, with the data starting at row 2.

You want…Formula or tool
Guests on one event=COUNTIF(Attendees!A:A, "Spring workshop")
Confirmed guests on one event=COUNTIFS(Attendees!A:A, "Spring workshop", Attendees!F:F, "YES")
Who has not replied=FILTER(Attendees!D2:E, Attendees!F2:F="INVITED")
Each person once, even if invited to several events=UNIQUE(Attendees!E2:E)
How many events each person was invited toA pivot table with Email as rows and a count of Event as values
Replies per eventA pivot table: Event as rows, Reply as columns, a count of Email as values
Hide meeting roomsAdd a filter on the Email column that excludes text containing resource.calendar.google.com

A common use is a headcount. Before a class or a workshop, run the export for that week, make a pivot of Event by Reply, and you have the numbers for catering or a room booking. Another is a reminder list: filter for INVITED to see who still hasn’t answered, and follow up with them directly from your own mail.

Without a script: CalendarRows

CalendarRows is our add-on for moving events between Google Calendar and Google Sheets. It imports a calendar and date range into a new tab, and the columns you can tick include Guests, which fills in the email addresses of the people invited, separated by commas. Rooms and other resources are left out.

  1. Install CalendarRows from the Google Workspace Marketplace (the button below), then choose Extensions → CalendarRows → Open CalendarRows.
  2. Open the From Calendar tab, pick the calendar and the date range.
  3. Tick the columns you want. Guests is off by default, so tick it.
  4. Click Import. The events arrive in a new tab, with the guests in one cell per event.

Here is the honest comparison. CalendarRows is the quicker route when you want event details and the email addresses with no code, and the free plan imports up to 100 events at a time. It does not import each person’s reply, and it puts all guests of an event in one cell, so you can’t count them with a pivot table without splitting that cell first (=SPLIT(cell, ", ") does that). For replies and one row per guest, use the script above. The two don’t conflict, and you can use both in the same spreadsheet.

Handle the list with care

A sheet of names and email addresses is personal data, and it is easy to forget how many people can open a spreadsheet. A few habits keep it tidy:

  • Share narrowly. Share the file with named people, not with “anyone with the link”. Check Share after you run the export, since the sheet may already be shared for another reason.
  • Keep only what you need. If you only need counts, build the pivot table and delete the tab that has the addresses.
  • Don’t reuse the list for something else. People who were invited to a meeting haven’t agreed to receive your newsletter. If you plan to send marketing email, get agreement from the people on it.
  • Delete the data when you are finished. A past event’s list is rarely needed after the event.

Data protection rules differ by country and by organisation, and this guide is not legal advice. If the guests are customers, employees or students, ask whoever looks after privacy for your organisation before you keep a list for long.

Common problems

The Attendees tab only has the header. No event in your range has guests, or the range is wrong. Read the note in column H: it says how many events were found and how many had no guests. If events were found but none had guests, those are events with nobody invited. If zero events were found, check ATT_FROM, ATT_TO and the calendar ID.

“Check ATT_FROM and ATT_TO”. The date isn’t in YYYY-MM-DD form, or the end isn’t after the start. Use quotes and dashes, for example '2026-11-01'.

“Calendar not found”. The Calendar ID is wrong, or your account can’t see that calendar. Copy the ID again from Settings and sharing → Integrate calendar and make sure the calendar is shared with you.

The guest list is missing for events someone else organised. The organiser can turn off the setting that lets guests see the guest list. You can’t get around that from a script. Ask the organiser for the list.

Names are blank. Google only has a name for some addresses. The email is always there, so match on that.

The script says it needs authorisation every time. Open Executions in the editor to see the error. The usual cause is a permission that was cancelled halfway. Run the function once by hand and accept all the permissions it asks for.

The numbers differ from what I see in Calendar. The script uses the replies at the moment it ran. Run it again. For repeating events each occurrence has its own replies, so one person can be YES for Tuesday’s class and INVITED for next week’s.

Frequently asked questions

Can I export the guest list from Google Calendar?

Only for large events with Google’s own tool. Google Calendar has an Export guest responses to Sheets option, but its help page describes it for events with 200 or more guests and requires edit rights to the event. For smaller events you can copy the list by hand, run an Apps Script such as the one in this guide, or import the calendar into a sheet with an add-on that has a guests column.

Does the export include who accepted or declined?

The script in this guide does. It writes each guest’s reply as YES, NO, MAYBE or INVITED (no answer yet), and marks the organiser as OWNER. CalendarRows can import guest email addresses, but it does not import their replies.

Why is the guest list empty for some events?

Either the event has no guests, or you can’t see them. If the organiser turned off “See guest list” for guests, people invited to the event may not be able to read who else was invited, and the script then lists nothing for it. Events you organise always show their guests to you.

Can I export attendees from someone else’s calendar?

Only what you are allowed to see. Put the calendar’s ID in ATT_CALENDAR_ID. If it is shared with you as “free/busy only”, events have no titles or guests to read. If it is shared with “See all event details”, you get the guest list the event itself shows you.

Are meeting rooms listed as attendees?

Often, yes. Rooms and other resources are guests on the event, with an address that ends in resource.calendar.google.com. Sort the Email column or add a filter that hides those rows.

How do I get the number of attendees per event?

Add a pivot table to the Attendees tab: Event as the rows and a count of Email as the values. Or use a COUNTIF formula on the Event column. The Reply column can be a second pivot dimension to see how many said yes.

Is it okay to keep attendees’ email addresses in a spreadsheet?

It is personal data, so keep it to people who need it, share the sheet narrowly, and delete it when you are done. If you collect addresses to send marketing mail, you need the recipients’ agreement. Rules differ by country, so ask whoever handles privacy for your organisation if you are unsure.

Disclosure: we make CalendarRows, the Google Sheets add-on mentioned in this guide. The script here works without it, and we say where it does more than the add-on.

Google Sheets, Google Calendar and Google Workspace are trademarks of Google LLC. CalendarRows and Cellbrook are not affiliated with or endorsed by Google.