A Notion Worker that syncs your Google Contacts into a managed Notion database every 3 hours.
- One-way sync: Google → Notion (contacts removed in Google are removed from Notion on the next full sync)
- Hosted by Notion: no servers or cron jobs to run yourself
- OAuth: Google authorization is handled by the Workers runtime
Beta: Notion Workers is in beta. APIs, CLI commands, and hosting behavior may change. See the Workers documentation.
- A Notion workspace with Workers enabled (Business or Enterprise; workspace owner must enable Workers)
- Node.js 22+
- The Notion CLI (
ntn) - A Google Cloud project with the People API enabled
git clone https://github.com/simosme/notion-google-contacts-worker.git
cd notion-google-contacts-worker
npm installcurl -fsSL https://ntn.dev | bash
ntn loginOn Windows, follow the CLI installation docs if the install script is not available.
From the project directory:
ntn workers deployThis registers the worker with your Notion workspace. OAuth credentials are not required yet.
-
Create or select a Google Cloud project.
-
Enable the People API.
-
Configure the OAuth consent screen (External or Internal as appropriate).
-
Create an OAuth 2.0 Client ID (application type: Web application).
-
Get the Notion redirect URL:
ntn workers oauth show-redirect-url
-
Add that URL as an Authorized redirect URI on your Google OAuth client.
-
Copy the Client ID and Client secret.
Required OAuth scope (requested by this worker):
https://www.googleapis.com/auth/contacts.readonly
ntn workers env set GOOGLE_CLIENT_ID=your-client-id GOOGLE_CLIENT_SECRET=your-client-secret
ntn workers deployntn workers oauth start googleAuthComplete the browser flow to grant read access to your contacts.
Preview without writing to Notion:
ntn workers sync trigger contactsSync --previewRun a real sync immediately:
ntn workers sync trigger contactsSyncCheck sync status:
ntn workers sync statusAfter the first successful sync, Notion creates a Google Contacts database in your workspace. The worker runs automatically every 3 hours.
Each Google contact becomes one row with:
| Notion property | Source |
|---|---|
| Name | Primary display name |
| Contact ID | Google resourceName (stable key) |
| Primary email | |
| Phone | Primary phone |
| Company | Primary organization (name and title) |
| Photo URL | Primary photo URL |
npm run check # TypeScript type-check
npm run build # Emit dist/Pull secrets for local testing (includes a refreshed OAuth token):
ntn workers env pullSee .env.example for variable names. Never commit .env.
- Schedule:
3h(every 3 hours), configured on thecontactsSynccapability insrc/index.ts. - Mode:
replace— each full sync cycle paginates through all Google contacts; records not seen in that cycle are deleted from Notion. - Pagination: 100 contacts per API page; the sync resumes with
pageTokenuntilhasMoreis false.
For very large address books, consider switching to incremental mode and Google’s syncToken API (see People API contacts guide).
ntn workers deploy
ntn workers sync trigger contactsSync
ntn workers sync trigger contactsSync --preview
ntn workers sync status
ntn workers sync state reset contactsSync
ntn workers capabilities disable contactsSync
ntn workers capabilities enable contactsSync
ntn workers runs logs <runId>- Do not commit
GOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET, or.env. - Each user deploys this worker to their own Notion workspace and authorizes their own Google account.
- OAuth tokens are stored by the Notion Workers runtime, not in this repository.
MIT — see LICENSE.