How to Sync Multiple Google Calendars with Apps Script [Clasp Version]
Sync multiple Google Calendars with Google Apps Script
Introduction
“Work account, personal account, freelance account… My calendars are scattered everywhere and I can’t keep track of my schedule.”
If you use multiple Google accounts, you’ve probably experienced this frustration. While Google Calendar lets you “view” calendars from other accounts, there’s no built-in feature to consolidate them into a single unified calendar.
Google Calendar Sync is a Google Apps Script solution that solves this problem.
Account B's Calendar ──┐
Account C's Calendar ──┼──▶ Account A's Main Calendar
Account D's Calendar ──┘
This guide walks you through setting up Calendar Sync using Clasp for a modern development workflow.
Prefer a browser-only setup? Check out the Manual Setup Guide.
Who This Guide Is For
- Users who want to understand what’s happening behind the scenes while syncing calendars
- Developers familiar with Node.js/npm
- Those comfortable with command-line operations
Features Overview
Automatic Sync
Runs every 15 minutes on a schedule, plus immediately when calendar events change. Once set up, it runs automatically without intervention.
Incremental Sync (Sync Token)
Uses Google Calendar’s Sync Token to fetch only changed events. No need to retrieve all events every time, significantly reducing API quota usage.
Privacy Modes
Control how much information gets synced with three levels:
| Mode | Synced Information | Use Case |
|---|---|---|
busy | Time slots only (shows “Busy”) | Work calendar to personal account |
title-only | Title + time | Team calendar to manager |
full | All information | Between your own accounts |
Color Coding
Set different colors for each source calendar so you can tell at a glance which account an event came from.
Setup Instructions
Prerequisites
- Node.js >= 22.0.0
- npm
Step 1: Share Your Calendars
For each source account (B, C, D…), do the following:
- Log in to Google Calendar
- Hover over the calendar name in the left sidebar, click ⋮ → Settings and sharing
- In “Share with specific people or groups,” click + Add people and groups
- Enter Account A’s email address
- Set permission to “See all event details”
- Click Send
Step 2: Initial Setup (Account A, one time only)
-
Enable the Apps Script API
-
Clone the repository and install dependencies:
git clone https://github.com/khides/calender-sync-gas.git
cd calender-sync-gas
npm install
- Log in with your Google account:
npm run login
Step 3: Deploy
# Create GAS project
npm run create
# Push code & enable Calendar API
npm run deploy
# Open project in browser
npm run open
Step 4: Configure and Initial Sync
npm run open opens the Apps Script editor in your browser.
4-1. Configure Source Calendars
- Click Config.gs in the left sidebar
- Change
calendarIdin thesourceCalendarsarray to actual email addresses:
calendarId: 'your-actual-account@gmail.com', // ← Change to actual email
- For multiple accounts: Add entries following the commented samples
sourceCalendars: [
{
calendarId: 'account-b@gmail.com',
label: 'Account B',
privacyMode: 'busy',
enabled: true,
colorId: '1'
},
{ // ← Don't forget the comma
calendarId: 'account-c@gmail.com',
label: 'Account C',
privacyMode: 'busy',
enabled: true,
colorId: '2'
}
]
4-2. How to Run Functions
To run functions in the Apps Script editor:
- Click the function dropdown at the top (shows “Select function”)
- Select the function name you want to run
- Click the Run button (▶)
┌─────────────────────────────────────────────────────────┐
│ [Select function ▼] [▶ Run] [🐛 Debug] │
│ │
│ ↑ Select function here and click Run │
└─────────────────────────────────────────────────────────┘
4-3. Run Initial Setup
Execute these functions in order:
-
Select
validateSetupfrom Code.gs and run- First run will show authorization prompt
- Click “Review Permissions” → Select account → “Advanced” → “Go to [Project Name] (unsafe)” → “Allow”
- Check execution log (bottom panel) shows “Accessible” for all calendars
-
Select
setupTriggersand run- Sets up automatic sync triggers
-
Select
manualSyncand run- Runs the initial sync
- Verify events appear in Account A’s calendar
Configuration Options
Privacy Modes
| Mode | Display |
|---|---|
busy | Shows “[Label] Busy” only |
title-only | Title and time only (no description/location) |
full | Copies all information |
Color IDs
| ID | Color |
|---|---|
| 1 | Lavender |
| 2 | Sage |
| 3 | Grape |
| 4 | Flamingo |
| 5 | Banana |
| 6 | Tangerine |
| 7 | Peacock |
| 8 | Graphite |
| 9 | Blueberry |
| 10 | Basil |
| 11 | Tomato |
npm Scripts
| Command | Description |
|---|---|
npm run login | Log in with Google account |
npm run create | Create GAS project |
npm run push | Push code |
npm run deploy | Push + enable API |
npm run open | Open editor in browser |
npm run watch | Watch files and auto-push changes |
Operations & Maintenance
Available Functions
| Function | Description |
|---|---|
manualSync() | Run sync manually |
validateSetup() | Validate settings and access |
setupTriggers() | Set up automatic triggers |
clearTriggers() | Remove all triggers |
showStatus() | Show sync status |
forceFullSync() | Run full sync for all calendars |
resetAllData() | Reset all sync data |
removeAllSyncedEvents() | Delete all synced events |
Troubleshooting
Cannot Access Calendar
- Verify the calendar is properly shared from the source account
- Check if Account A has subscribed to the calendar (Calendar > Other calendars > Subscribe)
- Verify the calendar ID in
Config.gsis correct
Sync Not Working
- Run
showStatus()to check status - Verify triggers are configured
- Check execution logs for errors
Sync Token Error
sync token invalidated, running full sync
This is normal behavior. It means Google reset the token, so the script fell back to a full sync.
Quotas and Limits
| Item | Limit | Mitigation |
|---|---|---|
| Event creation/day | 5,000 | Minimized with incremental sync |
| Script execution time | 6 min | Handled with pagination |
| Trigger time/day | 90 min | Efficient with sync tokens |
Technical Details
A brief explanation of what happens behind the scenes.
Incremental Sync with Sync Tokens
Google Calendar issues a Sync Token each time you fetch the event list. Pass this token on the next sync, and only events changed since the last fetch are returned.
This eliminates the need to fetch and compare all events every time, reducing API quota usage by over 90%. Tokens expire after a period (typically ~7 days), but the script automatically falls back to a full scan when this happens.
Event Mapping
Synced events include metadata linking them to their source events. This enables:
- Source event updated → Destination automatically updated
- Source event deleted → Destination automatically deleted
- Destination event accidentally deleted → Recreated on next sync
This ensures consistent state management.
Dual Trigger Strategy
Two types of triggers work together to balance real-time responsiveness with reliability:
| Trigger | Advantage | Disadvantage |
|---|---|---|
| Calendar trigger | Fires immediately (<1 min) | May fail due to permissions |
| 15-minute timer | Reliable execution | Up to 15-min delay |
Usually syncs immediately, with guaranteed recovery within 15 minutes if anything fails.
Summary
Google Calendar Sync lets you consolidate calendars scattered across multiple Google accounts into one.
- Share calendars from source accounts
- Deploy with Clasp
- Configure source calendars in Config.gs
- Run initial sync
Once set up, sync runs automatically. If you’re struggling to manage too many calendars, give it a try.
Source Code
Sync multiple Google Calendars with Google Apps Script