This guide walks you through setting up Smart Sync Google Calendars using the Apps Script Editor (UI-based method). This is the easiest way to get started — no command-line tools required!
By the end of this guide, you'll have:
- ✅ A Google Apps Script project that syncs multiple calendars
- ✅ Automatic triggers that keep calendars in sync
- ✅ A single "Busy Time" calendar showing all your events with prefixes like
[personal]and[work1]
Are you a developer who wants:
- Local file editing with your favorite editor (VS Code, Cursor, etc.)
- Version control integration
- AI assistant integration (Cursor, GitHub Copilot)
- Command-line deployment workflow
→ See the CLI Setup Guide for the CLI/clasp method.
Otherwise, continue below for the UI-based setup! ⬇️
You only need:
- A Google account
- Access to multiple Google Calendars (personal, work, etc.)
- 20 minutes of setup time
- Go to Google Apps Script
- Click "New project" (+ button in top-left)
- Click on "Untitled project" at the top and rename it to: Smart Sync Google Calendars
- You should see a default
Code.gsfile with a sample function — we'll replace this next
Now we'll add the three script files that make up the sync system.
- Click on
Code.gsin the left sidebar (if not already open) - Select all the default code (Cmd+A or Ctrl+A) and delete it
- Copy the entire contents of
scripts/SyncCalendarsIntoOne.gsfrom the repository - Paste it into the editor
- Rename the file:
- Click the three dots (⋮) next to
Code.gs - Select "Rename"
- Name it:
SyncCalendarsIntoOne
- Click the three dots (⋮) next to
- The
.gsextension will be added automatically
- Click the "+" button next to "Files" in the left sidebar
- Select "Script"
- Name it:
BatchRequests - Copy the entire contents of
scripts/BatchRequests.gsfrom the repository - Paste it into the new file
- Press Cmd+S (Mac) or Ctrl+S (Windows) to save
- Click the "+" button next to "Files" in the left sidebar
- Select "Script"
- Name it:
Config - Copy the template below and paste it into the new file:
// Configuration file - Your private calendar setup
// This file contains your calendar IDs and settings
// Calendars to merge from.
// The keys (e.g., "personal", "work1") become prefixes in event titles.
const CALENDARS_TO_MERGE = {
"personal": "your-personal@gmail.com",
"work1": "work@company1.com",
"work2": "work@company2.com",
// Add more calendars as needed
}
// The ID of the target calendar where all events will be synced
const CALENDAR_TO_MERGE_INTO = "your-target-calendar-id@group.calendar.google.com"
// Number of days in the past and future to sync
const SYNC_DAYS_IN_PAST = 30
const SYNC_DAYS_IN_FUTURE = 365
// Default title for events that don't have a title
const DEFAULT_EVENT_TITLE = "Busy"
// Unique character to identify synced events (don't change this)
// https://unicode-table.com/en/200B/
const SEARCH_CHARACTER = "\u200B"- Don't worry about the placeholder values yet — we'll fill in your actual calendar IDs in Step 3
- Press Cmd+S (Mac) or Ctrl+S (Windows) to save
You need the Calendar IDs for each calendar you want to sync. Here's how to find them:
- Open Google Calendar in a new tab
- Look at the left sidebar under "My calendars"
- Click the three dots (⋮) next to your main calendar
- Select "Settings and sharing"
- Scroll down to the "Integrate calendar" section
- Copy the "Calendar ID" (usually your email address like
user@gmail.com)
For each work calendar you want to sync:
First, ensure the calendar is shared with you:
- Open the work calendar's settings (same as above)
- Under "Share with specific people", verify your personal email is listed
- You need at least "See all event details" permission (not just "See only free/busy")
Then, get the Calendar ID:
- Follow the same steps as for your personal calendar
- The ID is typically the email address (e.g.,
work@company.com)
You need a target calendar where all synced events will appear.
Option A: Create a New Calendar
- In Google Calendar, click the "+" next to "Other calendars"
- Select "Create new calendar"
- Name it something like: "Busy Time" or "All Calendars"
- Optionally add a description
- Click "Create calendar"
- Find its Calendar ID using the steps from 3.1 above
- The ID will look like:
abc123def456...@group.calendar.google.com
Option B: Use an Existing Calendar
- Find the Calendar ID of your existing calendar
- Warning: All synced events will be added to this calendar
Now that you have all your calendar IDs, let's add them to your Config.gs file:
- Go back to the Apps Script Editor tab
- Click on
Config.gsin the left sidebar - Replace the placeholder values with your actual calendar IDs:
const CALENDARS_TO_MERGE = {
"personal": "john.doe@gmail.com", // ← Your actual personal calendar ID
"work1": "john.doe@company1.com", // ← Your first work calendar ID
"work2": "john.contractor@company2.com", // ← Your second work calendar ID
// Add more calendars as needed, or remove lines you don't need
}
const CALENDAR_TO_MERGE_INTO = "abc123def456...@group.calendar.google.com" // ← Your target calendar IDImportant Notes:
- The keys (
"personal","work1", etc.) become prefixes in synced event titles - Example: An event "Team Meeting" from "personal" becomes
[personal] Team Meeting - You can use any label you want (e.g.,
"home","consulting","client-work") - You can add or remove calendars as needed — just follow the same format
- Press Cmd+S (Mac) or Ctrl+S (Windows) to save
You can also customize these settings in Config.gs:
// How far back and forward to sync (in days)
const SYNC_DAYS_IN_PAST = 30 // Default: 30 days
const SYNC_DAYS_IN_FUTURE = 365 // Default: 365 days (1 year)
// What to show for events without a title
const DEFAULT_EVENT_TITLE = "Busy" // Default: "Busy"The script needs access to the Google Calendar API to sync events:
- In the Apps Script Editor, click "Services" (+ button) in the left sidebar
- Scroll down and find "Google Calendar API"
- Click on it, then click "Add"
- You should now see "Calendar" listed under "Services" in the left sidebar
Now let's test the script and authorize it to access your calendars:
- Make sure
SyncCalendarsIntoOne.gsis open in the editor - At the top of the editor, select
SyncCalendarsIntoOnefrom the function dropdown - Click the Run button (
▶️ )
First Run - Authorization Required:
- You'll see a dialog: "Authorization required"
- Click "Review permissions"
- A new window will open asking you to choose an account
- Select your Google account (the one hosting this script)
- You may see a warning: "Google hasn't verified this app"
- This is normal for personal scripts you create
- Click "Advanced"
- Click "Go to Smart Sync Google Calendars (unsafe)"
- This is safe because YOU are the developer
- Review the permissions requested:
- View and edit your calendars
- Connect to external services
- Click "Allow"
After Authorization:
- The script will run automatically
- Wait 10-30 seconds for it to complete
- Check the Execution log (View → Logs or Cmd/Ctrl + Enter)
- You should see output like:
Analysis: 15 create, 0 update, 0 delete, 0 skip 15 events created Smart sync complete: 15 created, 0 updated, 0 deleted, 0 unchanged
Let's confirm everything worked:
- Go to Google Calendar
- Find your target calendar in the left sidebar (e.g., "Busy Time")
- Make sure it's checked/visible
- Look for synced events with prefixes matching your config, like:
[personal] Team Meeting[work1] Client Call[work2] Design Review
- Verify that events from the past 30 days and future 365 days are synced
- Click on a synced event to verify:
- Title includes the calendar prefix
- Time matches the source event
- Location is included
- Conference links (Zoom, Meet) are preserved
Right now, the sync only runs when you manually click "Run". Let's set up automatic triggers so your calendars stay in sync automatically.
Calendar-based triggers run the sync automatically whenever any of your source calendars are updated. This provides near-instant syncing.
Set up one trigger per source calendar:
- In the Apps Script editor, click the clock icon (⏰) in the left sidebar
- Click "+ Add Trigger" (bottom-right)
- Configure the first trigger:
- Choose which function to run:
SyncCalendarsIntoOne - Choose which deployment should run:
Head - Select event source:
From calendar - Enter calendar details: Enter your first source calendar ID (e.g.,
john.doe@gmail.com) - Notification settings: Leave as default (or customize as needed)
- Choose which function to run:
- Click "Save"
- Repeat steps 2-4 for each of your other source calendars:
- Add a trigger for your second calendar (e.g.,
john.doe@company1.com) - Add a trigger for your third calendar (e.g.,
john.contractor@company2.com) - Continue for all calendars in your
CALENDARS_TO_MERGEconfig
- Add a trigger for your second calendar (e.g.,
Result: You should have one trigger per source calendar (typically 3-5 triggers total).
Note: The first time you save a trigger, you may be prompted to authorize the script again. This is normal — just follow the authorization flow.
If you prefer to sync on a schedule instead of event-based:
- Click the clock icon (⏰) in the left sidebar
- Click "+ Add Trigger"
- Configure:
- Choose which function to run:
SyncCalendarsIntoOne - Choose which deployment should run:
Head - Select event source:
Time-driven - Select type of time based trigger:
Minutes timer - Select minute interval:
Every 15 minutes(or your preference)
- Choose which function to run:
- Click "Save"
Note: Time-based triggers are simpler but less responsive than calendar-based triggers.
Let's verify the triggers are working:
- Go to Google Calendar
- Open one of your source calendars (personal or work)
- Create a test event:
- Title: "Test Event"
- Date/time: Tomorrow at 2:00 PM
- Save the event
- Wait 1-2 minutes for the trigger to fire
- Go to your target calendar (e.g., "Busy Time")
- Look for the synced event:
[personal] Test Event(or whatever prefix matches) - If you see it, success! Your automatic sync is working
- You can delete the test event from both calendars
Troubleshooting:
- If the event doesn't appear after 2-3 minutes, check the Executions page in Apps Script (left sidebar, clock with checkmark icon)
- Look for recent executions and any error messages
- See the Troubleshooting section below for common issues
You can monitor sync activity:
- In the Apps Script editor, click the "Executions" icon (clock with checkmark) in the left sidebar
- You'll see a list of recent sync runs with:
- Timestamp when they ran
- How long they took
- Status (Success or Failed)
- Click on any execution to view its detailed logs
- This is helpful for debugging if events aren't syncing as expected
Problem: No events appear in the target calendar after running the script.
Solutions:
- Check the execution log for errors (View → Logs in the editor)
- Verify all calendar IDs in
Config.gsare correct - Ensure work calendars are shared with your primary Google account with at least "See all event details" permission
- Confirm you have events in your source calendars within the sync window (past 30 days, future 365 days)
- Check that the Calendar API is enabled (Step 5)
Problem: Execution log shows "Calendar not found: 'calendar@example.com'"
Solutions:
- Double-check the Calendar ID in
Config.gs— make sure there are no typos or extra spaces - For work calendars, verify they are shared with your primary Google account
- Verify the sharing permission is "See all event details" (not just "See only free/busy")
- Try accessing the calendar in Google Calendar's web interface to confirm you can see it
Problem: Script keeps asking for authorization every time you run it.
Solutions:
- Make sure you completed the full authorization flow (Steps 6.4-6.10)
- When you see "Google hasn't verified this app", you must click "Advanced" → "Go to Smart Sync Google Calendars (unsafe)"
- Grant all requested permissions
- This is safe because you are the developer and owner of the script
Problem: Events appearing multiple times in the target calendar.
Solutions:
- The script includes advanced duplicate prevention using
LockServiceto handle concurrent executions. - This prevents race conditions when multiple triggers fire simultaneously (e.g. adding multiple events quickly).
- If you still see duplicates, delete all events from the target calendar and run the sync once manually to reset.
Problem: Events syncing with incorrect times or timezones.
Solutions:
- The script preserves the original timezone from source events
- Check your Google Calendar timezone settings (Settings → General → Your current time zone)
- Verify the source event has the correct timezone
- The synced event should match the source event exactly
Problem: Automatic sync isn't working even though triggers are set up.
Solutions:
- Check the Executions page for errors
- Verify triggers are configured correctly (clock icon in left sidebar)
- For calendar-based triggers, make sure the calendar ID is entered correctly
- Try creating a test event in a source calendar and wait 1-2 minutes
- Check that you've authorized the script to run automatically (authorization includes trigger permissions)
Problem: Script fails with quota or rate limit errors.
Solutions:
- Google Apps Script allows 5,000 calendar events created per day
- The smart sync only creates/updates changed events, so this is rarely an issue
- If you hit limits, reduce
SYNC_DAYS_IN_PASTorSYNC_DAYS_IN_FUTUREinConfig.gs - Check quota usage at the Google Cloud Console
Your Config.gs file contains sensitive information (calendar IDs, email addresses). When using the UI method:
- Your config stays in Google Apps Script — it's not stored anywhere else
- Only you can access it — it's tied to your Google account
- Google secures it — uses Google's authentication and authorization
The script only syncs specific event information:
- ✅ Event title (with calendar prefix)
- ✅ Start and end times (with timezone)
- ✅ Location
- ✅ Conference links (Zoom, Meet, etc.)
- ❌ Descriptions (NOT synced for privacy)
- ❌ Attendees (NOT synced for privacy)
- ❌ Free/transparent events (NOT synced)
The script uses Google Calendar's extended properties to track synced events:
sourceCalendarId- Which calendar the event came fromsourceEventId- Original event IDsourceLastModified- When it was last updated- This data is stored within your Google Calendar and never leaves Google's systems
Congratulations! Your calendar sync is now set up and running automatically. 🎉
You can now share your "Busy Time" calendar with others:
- Go to Google Calendar
- Find your target calendar in the left sidebar
- Click the three dots (⋮) next to it
- Select "Settings and sharing"
- Under "Share with specific people", add email addresses
- Choose permission level (usually "See only free/busy" is sufficient for family/colleagues)
- Or, share the calendar URL with iCloud or other calendar apps
If you need to add/remove calendars or change settings:
- Go back to the Apps Script Editor
- Open your project: "Smart Sync Google Calendars"
- Edit
Config.gswith your changes - Press Cmd+S or Ctrl+S to save
- Changes take effect immediately — the next sync will use the new settings
- If you added a new source calendar, remember to add a trigger for it (Step 8)
To keep an eye on your sync:
- Check the Executions page occasionally for errors
- Your target calendar should update within 1-2 minutes of changes in source calendars
- If you notice issues, check the Troubleshooting section above
If you want to switch to local file editing and version control for ongoing maintenance:
- Follow the CLI Setup Guide to set up clasp
- Pull your existing script to your local machine
- Edit files locally and deploy changes with
npm run deploy - Your triggers and config will remain intact
- Calendar API Documentation: Google Calendar API Docs
- Apps Script Documentation: Google Apps Script Docs
- Project Repository: GitHub
- For CLI Setup: See CLI Setup Guide
- For Code Updates: See Updating Deployments Guide
Need help? Check the Troubleshooting section above or review the execution logs in the Apps Script editor.