Unified task synchronization from Google Tasks, Alexa, and Microsoft To-Do to Todoist
- About
- Features
- Quick Start
- Installation
- Configuration
- Usage
- Architecture
- Wiki
- Contributing
- Credits
- License
Todoist Bridge is a Node.js daemon that synchronizes tasks between multiple platforms and Todoist. It runs as a background service, polling your task sources at configurable intervals and automatically creating, updating, and completing tasks.
You can use any combination of the following sources:
| Source | Sync Direction | Description |
|---|---|---|
| Google Tasks | One-way → Todoist | Sync task lists from Google Tasks |
| Alexa Reminders | One-way → Todoist | Sync reminders from Alexa devices |
| Alexa Shopping List | One-way → Todoist | Sync your Alexa shopping list |
| Microsoft To-Do | Bi-directional ↔ Todoist | Two-way sync with Microsoft To-Do lists |
Enable only what you need - each source is independently configurable.
Why Todoist Bridge?
- Centralize your tasks: Consolidate tasks from multiple sources into Todoist
- Modular sources: Use Google Tasks, Alexa, or both - your choice
- Hands-free operation: Set it up once and forget about it
- Flexible mapping: Map specific lists to specific projects with custom tags
- Self-hosted: Your data stays on your infrastructure
| Feature | Description |
|---|---|
| Google Tasks Sync | Full sync of tasks including subtasks, due dates, and descriptions |
| Alexa Reminders | Sync reminders from all Alexa devices to Todoist |
| Alexa Shopping List | Keep your shopping list in sync |
| Microsoft To-Do Sync | Bi-directional sync with Microsoft To-Do (great for shared lists) |
| Completion Sync | Complete tasks on either platform, syncs to the other |
| Shared List Support | Filter shared Microsoft lists to only sync your items |
| Custom Tags | Apply labels to synced tasks for easy filtering |
| Flexible Mapping | Map any source list to any Todoist project or Inbox |
| Subtask Support | Single-level subtask hierarchy preserved |
| Completed Tasks | Optional retroactive import of completed tasks |
| Delete After Sync | Optionally remove tasks from source after syncing |
| Conflict Resolution | Last-write-wins for bi-directional sync conflicts |
| SQLite State | Reliable change detection with local database |
| Graceful Shutdown | Clean handling of SIGTERM/SIGINT signals |
# Pull the image
docker pull ghcr.io/graysoncadams/todoist-bridge:latest
# Create directories
mkdir -p ./data ./credentials
# Create config file (see Configuration section)
cp config.example.yaml config.yaml
# Edit config.yaml with your settings
# Run the container
docker run -d \
--name todoist-bridge \
-v $(pwd)/config.yaml:/app/config.yaml:ro \
-v $(pwd)/credentials:/app/credentials \
-v $(pwd)/data:/app/data \
ghcr.io/graysoncadams/todoist-bridge:latestDocker provides the simplest deployment path with automatic updates and isolation.
docker pull ghcr.io/graysoncadams/todoist-bridge:latestSee Docker Compose for a complete example.
Create a docker-compose.yml:
services:
todoist-bridge:
image: ghcr.io/graysoncadams/todoist-bridge:latest
container_name: todoist-bridge
restart: unless-stopped
volumes:
- ./config.yaml:/app/config.yaml:ro
- ./credentials:/app/credentials
- ./data:/app/data
ports:
- "3000:3000" # Google OAuth web form (first run only)
- "3001:3001" # Alexa auth proxy (first run only, if using Alexa)
environment:
- LOG_LEVEL=info
- TZ=America/New_YorkNote: Ports are only needed for initial authorization. After tokens/cookies are saved, you can remove the port mappings. For Alexa, also set
proxy_hostin config.yaml to your Docker host's IP.
Run with:
docker compose up -d
docker compose logs -fRequirements:
- Node.js 20.0.0 or higher
- npm
# Clone the repository
git clone https://github.com/GraysonCAdams/todoist-bridge.git
cd todoist-bridge
# Install dependencies
npm install
# Build
npm run build
# Configure
cp config.example.yaml config.yaml
# Edit config.yaml
# Run
npm startFor development:
npm run devTodoist Bridge uses a YAML configuration file with environment variable overrides.
Choose one or more sources to sync. Each source can be enabled or disabled independently.
Google Tasks only:
todoist:
api_token: "your-todoist-api-token"
sources:
google:
enabled: true
lists:
- source_list_id: "YOUR_GOOGLE_LIST_ID"
todoist_project_id: "YOUR_TODOIST_PROJECT_ID"
alexa:
enabled: falseAlexa only:
todoist:
api_token: "your-todoist-api-token"
sources:
google:
enabled: false
alexa:
enabled: true
amazon_page: "amazon.com"
lists:
- source_list_id: "all"
todoist_project_id: "YOUR_TODOIST_PROJECT_ID"Both sources:
todoist:
api_token: "your-todoist-api-token"
sources:
google:
enabled: true
lists:
- source_list_id: "YOUR_GOOGLE_LIST_ID"
todoist_project_id: "YOUR_TODOIST_PROJECT_ID"
alexa:
enabled: true
lists:
- source_list_id: "all"
todoist_project_id: "YOUR_ALEXA_PROJECT_ID"Microsoft To-Do (bi-directional):
todoist:
api_token: "your-todoist-api-token"
sources:
google:
enabled: false
alexa:
enabled: false
microsoft:
enabled: true
client_id: "your-azure-app-client-id"
tenant_id: "consumers" # Use "consumers" for personal Microsoft accounts
lists:
- list_name: "Groceries"
todoist_project_id: "inbox"
tags: ["grocery"]
assign_to_self: true # Set reminders on tasks with due times
exclude_others_assignments: true # Ignore items from other users# Todoist configuration
todoist:
api_token: "your-todoist-api-token"
# Sources to sync from
sources:
# Google Tasks (one-way sync to Todoist)
google:
enabled: true
poll_interval_minutes: 5
credentials_path: "./credentials/google-credentials.json"
token_path: "./credentials/google-token.json"
lists:
- source_list_id: "abc123"
todoist_project_id: "456789" # or "inbox"
include_completed: false
delete_after_sync: false
tags:
- "google-tasks"
# Alexa Reminders (one-way sync to Todoist)
alexa:
enabled: false
poll_interval_minutes: 5
cookie_path: "./credentials/alexa-cookie.json"
amazon_page: "amazon.com"
proxy_port: 3001
proxy_host: "192.168.1.140" # Your Docker host IP (for external access)
fail_silently: true
max_retries: 3
lists:
- source_list_id: "all"
todoist_project_id: "789012"
tags:
- "alexa"
# Shopping list sync
sync_shopping_list:
enabled: false
todoist_project_id: "123456"
tags:
- "shopping"
# Microsoft To-Do (bi-directional sync with Todoist)
microsoft:
enabled: false
client_id: "your-azure-app-client-id"
tenant_id: "consumers" # Use "consumers" for personal accounts
token_path: "./credentials/microsoft-token.json"
poll_interval_minutes: 3
lists:
- list_name: "Groceries"
todoist_project_id: "inbox"
tags: ["grocery"]
assign_to_self: false # Set reminders on tasks with due times
exclude_others_assignments: true # Ignore items from other users
# Global sync settings
sync:
sync_completed_once: true
# Storage
storage:
database_path: "./data/sync.db"
# Logging
logging:
level: "info" # trace, debug, info, warn, error| Variable | Description | Default |
|---|---|---|
TODOIST_API_TOKEN |
Todoist API token | - |
DATABASE_PATH |
SQLite database path | ./data/sync.db |
POLL_INTERVAL_MINUTES |
Sync interval | 5 |
LOG_LEVEL |
Log verbosity | info |
Google Cloud Console Setup:
- Go to Google Cloud Console
- Create a new project or select an existing one
- Enable the Google Tasks API
- Go to APIs & Services > Credentials
- Create OAuth credentials > Desktop app (not "Web application")
- Download the credentials JSON
- Save as
./credentials/google-credentials.json
Authorization Flow:
On first run, you'll be prompted to authorize with Google:
Interactive mode (CLI/Terminal):
- A URL will be printed to the console
- Open the URL in your browser
- Sign in with your Google account
- Grant access to Google Tasks
- Google displays an authorization code - copy it
- Paste the code in the terminal when prompted
- The token is saved for future runs
Docker mode (Non-interactive):
- Check the container logs for the Google authorization URL
- Open the URL in your browser and authorize
- Google displays an authorization code - copy it
- Visit
http://localhost:3000/auth(or your Docker host) - Paste the authorization code in the web form
- The token is saved for future runs
Note: For Docker, ensure port 3000 is exposed for the initial authorization:
ports: - "3000:3000"
- A proxy server starts on the configured port (default: 3001)
- Open
http://localhost:3001in your browser (or your Docker host IP) - Sign in with your Amazon account
- Cookies are saved for future runs
Note for Docker: When running in Docker, set
proxy_hostin your config to your Docker host's IP address (e.g.,192.168.1.140) so the authentication redirects work correctly. Also expose the proxy port:# config.yaml sources: alexa: proxy_port: 3001 proxy_host: "192.168.1.140" # Your Docker host IP# docker-compose.yml ports: - "3001:3001"
Azure App Registration Setup:
- Go to Azure Portal > App registrations
- Click New registration
- Configure the app:
- Name:
Todoist Bridge(or any name you prefer) - Supported account types: Select "Personal Microsoft accounts only" (recommended for personal To-Do)
- Name:
- Click Register (leave Redirect URI blank)
- Copy the Application (client) ID - you'll need this for config
- Go to API permissions > Add a permission:
- Select Microsoft Graph
- Choose Delegated permissions
- Add:
Tasks.ReadWrite,User.Read - Click Add permissions
- Go to Authentication:
- Under Advanced settings, set Allow public client flows to Yes
- Click Save
Important: Use
tenant_id: "consumers"in your config for personal Microsoft accounts (@outlook.com, @hotmail.com, etc.)
Device Code Authentication Flow:
Microsoft To-Do uses Device Code Flow, which works in any environment (CLI, Docker, headless servers):
- On first run, the app displays a message like:
To sign in, use a web browser to open https://microsoft.com/devicelogin and enter the code: ABCD1234 - Open that URL in any browser (can be on your phone or another computer)
- Enter the code shown in your terminal
- Sign in with the Microsoft account that has the To-Do lists you want to sync
- Grant the requested permissions (Tasks.ReadWrite, User.Read)
- Return to your terminal - authentication completes automatically
- Token is saved to
./credentials/microsoft-token.jsonfor future runs
Which account gets linked? Whatever Microsoft account you sign into during step 4 is the one that gets linked. This is how you choose which To-Do lists to sync - by signing into the correct account.
Shared Lists: If you're syncing a shared Microsoft To-Do list, sign in with your own account. Enable
exclude_others_assignments: trueto ignore items added by other users.
See the Wiki: Finding IDs for detailed instructions on obtaining:
- Google Task List IDs
- Todoist Project IDs
Google Tasks / Alexa → Todoist:
| Source | Todoist | Notes |
|---|---|---|
| Title | Content | Direct mapping |
| Notes/Description | Description | Direct mapping |
| Status | is_completed | Mapped appropriately |
| Due Date | due_date | Date only |
| Parent | parent_id | Single level subtasks |
Microsoft To-Do ↔ Todoist (bi-directional):
| Microsoft To-Do | Todoist | Notes |
|---|---|---|
| title | content | Syncs both directions |
| body.content | description | Syncs both directions |
| status | is_completed | Completion syncs both ways |
| dueDateTime | due_date | Date and time preserved |
| importance | priority | high→P1, normal→P4, low→P4 |
| reminderDateTime | (via due) | Mapped to Todoist due time |
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Google Tasks │ │ Alexa Skills │ │ Microsoft To-Do │
│ API │ │ API │ │ Graph API │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
│ (one-way) │ (one-way) │ (bi-directional)
│ │ ↕
└───────────────────────┼───────────────────────┘
│
┌──────▼──────┐
│ Todoist │
│ Bridge │
└──────┬──────┘
│
┌──────▼──────┐
│ SQLite │
│ State DB │
└──────┬──────┘
│
┌──────▼──────┐
│ Todoist │
│ API │
└─────────────┘
| Component | Description |
|---|---|
src/index.ts |
Main entry point and daemon loop |
src/config.ts |
Configuration loading and validation |
src/storage.ts |
SQLite state management |
src/auth/ |
Authentication for Google, Todoist, Alexa |
src/clients/ |
API client wrappers |
src/sources/google/ |
Google Tasks source (one-way) |
src/sources/alexa/ |
Alexa source (one-way) |
src/sources/microsoft/ |
Microsoft To-Do source (bi-directional) |
src/utils/ |
Logger and retry utilities |
Detailed documentation is available in the Wiki:
- Home - Overview and quick start
- Installation - Detailed installation guide
- Google Setup - Google Cloud and OAuth configuration
- Alexa Setup - Amazon Alexa integration
- Microsoft To-Do Setup - Azure AD app registration and bi-directional sync
- Finding IDs - How to find list and project IDs
- Docker Deployment - Container deployment guide
- Troubleshooting - Common issues and solutions
Contributions are welcome. Please open an issue to discuss proposed changes before submitting a pull request.
- Fork the repository
- Create a feature branch (
git checkout -b feature/improvement) - Commit your changes (
git commit -am 'Add improvement') - Push to the branch (
git push origin feature/improvement) - Open a Pull Request
Todoist Bridge is built on the work of these projects:
| Project | Description | License |
|---|---|---|
| googleapis | Google APIs Node.js Client | Apache-2.0 |
| todoist-api-typescript | Official Todoist TypeScript SDK | MIT |
| alexa-remote2 | Alexa Remote Control | MIT |
| @azure/msal-node | Microsoft Authentication Library | MIT |
This project is licensed under the MIT License. See LICENSE for details.
MIT License
Copyright (c) 2024
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.