🇯🇵 日本語版 README はこちら / Japanese README
A Google Apps Script project that provides bidirectional synchronization between Notion databases and Google Calendar.
Automatically sync tasks and schedules managed in Notion to Google Calendar.
- 🔄 Auto Sync: Automatically synchronizes Notion items with "Schedule" tags to Google Calendar every 15 minutes
- 📅 Date Processing: Supports all-day events, timed events, and period events
- 🛡️ Duplicate Prevention: Prevents duplicate creation using Event IDs
↔️ Bidirectional Sync: Reflects changes and deletions in Notion to the calendar
- Node.js (v16 or later)
- npm
- Google Account
- Notion Account
- Access Notion Developers
- Click "+ New integration"
- Enter integration name (e.g.,
GoogleCalendar-Sync) - Click "Submit"
- Copy and save the Internal Integration Token
- Open the Notion database to be synchronized
- Get the Database ID from the URL
https://notion.so/workspace/{database-id}?v={view-id}- The
{database-id}part is the database ID
- Get the "Schedule tag" Page ID
- Click on the Schedule tag → Get the page ID from the URL
- Click "⋯" at the top right of the database → "Add connections"
- Select and add the created integration
- Access Google Cloud Console
- Create a new project or select an existing one
- Enable Google Calendar API
- "APIs & Services" → "Library"
- Search for "Google Calendar API" and enable it
- Enable Google Apps Script API
- Follow the same procedure to enable
# Navigate to the project folder
cd SyncNotionGoogleCalendar
# Install dependencies
npm install
# Login to Google account with clasp
npm run login# Create a new GAS project (first time only)
npm run create
# Push code to Google Apps Script
npm run push- Access Google Apps Script
- Open the created project
- Left menu "Project Settings" → "Script properties"
- Add the following properties:
| Property Name | Value | Description |
|---|---|---|
NOTION_API_KEY |
secret_xxxxx... |
Notion Internal Integration Token |
NOTION_DATABASE_ID |
xxxxxxxxx... |
Target Notion Database ID |
SCHEDULE_TAG_ID |
xxxxxxxxx... |
"Schedule" tag Page ID |
CALENDAR_ID |
primary or specific calendar ID |
Target Google Calendar (optional) |
- Left menu "Services"
- Enable Google Calendar API (select v3)
To ensure proper synchronization, the following properties are required in the Notion database:
| Property Name | Type | Required | Description |
|---|---|---|---|
| Title | Title | ✅ | Event title |
| Action Day | Date | ✅ | Event date and time |
| Tags | Relation | ✅ | Relation containing "Schedule" tag |
| Status | Status | ❌ | Task status |
| Event ID | Text | ❌ | Google Calendar Event ID (automatically set) |
| URL | URL | ❌ | Related links |
Execute initial setup in Google Apps Script editor:
// Execute initialization function (first time only)
initialize();This function performs the following:
- Verifies script properties
- Tests Google Calendar API connection
- Sets up automatic sync trigger (15-minute intervals)
- Create a new page in the Notion database
- Enter event name in Title
- Set date and time in Action Day:
- All-day event: Date only (e.g.,
2023-12-25) - Timed event: Specify date and time (e.g.,
2023-12-25 14:30) - Period event: Set start and end date/time
- All-day event: Date only (e.g.,
- Add "Schedule" tag to Tags
- ✅ "Schedule" tag is included in
Tags - ✅
Action Dayis set - ✅
Action Dayis within sync range (30 days ago to 90 days ahead) - ❌ Items not meeting the above criteria are excluded from sync
- Automatic sync: Executes every 15 minutes
- Manual sync: Execute
manualSync()in Google Apps Script editor
| Notion Operation | Google Calendar |
|---|---|
| 📝 Create new | ➕ Create event |
| ✏️ Change title | 🔄 Update event |
| 📅 Change date/time | 🔄 Update event |
| ❌ Remove Schedule tag | 🗑️ Delete event |
| 🗑️ Delete page | 🗑️ Delete event |
Title: Meeting Preparation
Action Day: 2023-12-25
→ Google Calendar: 12/25 all-day event
Title: Team Meeting
Action Day: 2023-12-25 14:00 → 2023-12-25 15:30
→ Google Calendar: 12/25 14:00-15:30
Title: Business Trip
Action Day: 2023-12-25 → 2023-12-27
→ Google Calendar: 12/25-12/27 all-day event
- Synchronized Notion pages automatically have Event ID set
- This ID manages the connection with Google Calendar
- Pages with Event ID are already synchronized
Check sync status in Google Apps Script editor execution logs:
=== Sync Process Started ===
Retrieved 3 schedule items from Notion
Retrieved 5 events from Google Calendar
=== Sync Process Completed ===
Created: 1, Updated: 1, Deleted: 0
Error: Notion API Error (401): Unauthorized
Causes and Solutions:
- ❌ NOTION_API_KEY is not set correctly
- ✅ Verify the Internal Integration Token obtained from Notion Developers
- ✅ Set correctly in Google Apps Script script properties
- ❌ Integration not added to database
- ✅ Notion database → "⋯" → "Add connections" to add integration
Log: Retrieved 0 schedule items from Notion
Causes and Solutions:
- ❌ SCHEDULE_TAG_ID is incorrect
- ✅ Open "Schedule" tag page and verify page ID from URL
- ✅ Page ID is a 32-character string including hyphens
- ❌ No items with "Schedule" tag in database
- ✅ Create items in Notion and add "Schedule" tag
- ✅ Verify that Action Day is also set
Error: Google Calendar API is not enabled
Causes and Solutions:
- ❌ Calendar API not enabled in Google Apps Script
- ✅ Google Apps Script → "Services" → Add Google Calendar API v3
- ❌ Calendar API disabled in Google Cloud Console
- ✅ Google Cloud Console → APIs & Services → Library → Enable Google Calendar API
Log: Trigger not set
Causes and Solutions:
- ❌ Periodic execution trigger not set
- ✅ Google Apps Script → Triggers → Verify 15-minute interval trigger for
syncNotionWithGoogleCalendarfunction - ✅ Or execute
initialize()function to automatically set trigger
- ✅ Google Apps Script → Triggers → Verify 15-minute interval trigger for
Error: Valid Action Day is not set
Causes and Solutions:
- ❌ Notion Action Day property is empty
- ✅ Set appropriate date in Notion Action Day
- ❌ Action Day format is incorrect
- ✅ All-day:
2023-12-25 - ✅ Timed:
2023-12-25T14:30:00 - ✅ Period: Set start date → end date
- ✅ All-day:
Error: Insufficient permissions
Causes and Solutions:
- ❌ Calendar scope insufficient in Google Apps Script
- ✅ Approve required permissions when executing script
- ✅ Click "Review permissions" on "Authorization required" screen
Error: API call to calendar.events.insert failed with error: Calendar usage limits exceeded.
Causes and Solutions:
- ❌ Events outside the sync range were repeatedly created, exceeding Google Calendar API quotas
- ✅ Run
cleanupDuplicateEvents()to delete duplicate events (run repeatedly until complete) - ✅ Update to the latest version to apply the date range filter fix
- ✅ Run
- Google Apps Script → "Execute" → Run any function
- Check error details in "Execution log"
- Add
Logger.log()for detailed debugging
// Testing individual functions
function testNotionConnection() {
const items = getNotionScheduleItems();
Logger.log(`Number of items retrieved: ${items.length}`);
items.forEach(item => Logger.log(item.title));
}
function testCalendarConnection() {
const events = getGoogleCalendarEvents();
Logger.log(`Number of events retrieved: ${events.length}`);
}function checkConfiguration() {
const config = {
apiKey: CONFIG.NOTION_API_KEY ? 'Set' : 'Not set',
databaseId: CONFIG.NOTION_DATABASE_ID ? 'Set' : 'Not set',
scheduleTagId: CONFIG.SCHEDULE_TAG_ID ? 'Set' : 'Not set'
};
Logger.log(config);
}// Detect and delete duplicate events (resumable, run repeatedly until complete)
cleanupDuplicateEvents();
// Reset progress and start over
resetCleanupProgress();- Rate Limits: Notion API allows maximum 3 requests per second
- Time Zone: Set to
Asia/Tokyoby default - Sync Range: Only targets events from 30 days ago to 90 days in the future
- Duplicate Prevention: Prevents duplicate creation through Event ID linking
This project is licensed under the MIT License.
Contributions to this project are welcome!
- 🐛 Bug reports
- 💡 Feature suggestions
- 🔧 Pull requests
Please feel free to report details in GitHub Issues.

