This script allows you to import projects, sections, tasks, and sub-tasks into Todoist from a JSON file.
- Python 3.8 or higher
- A Todoist account with an API token
A virtual environment is an isolated Python environment that keeps your project dependencies separate from your system Python installation. This prevents conflicts between different projects and keeps your system Python clean.
Why use a virtual environment?
- Keeps project dependencies isolated
- Prevents conflicts between different projects
- Easier to manage dependencies per project
- Recommended Python best practice
# Navigate to the project directory
cd path/to/todoist
# Create a virtual environment (this creates a .venv folder)
python3 -m venv .venv
# Activate the virtual environment
source .venv/bin/activate
# Your terminal prompt should now show (.venv) at the beginningAfter activating the virtual environment, install the required library:
# Upgrade pip (optional but recommended)
python -m pip install --upgrade pip
# Install the Todoist API library
python -m pip install todoist-api-pythonImportant: You need to activate the virtual environment every time you open a new terminal session:
cd path/to/todoist
source .venv/bin/activateYou'll know it's activated when you see (.venv) at the start of your terminal prompt.
To deactivate (when you're done working):
deactivate- Log in to Todoist
- Go to Settings → Integrations
- Scroll down to API token
- Click Copy to copy your token
- Keep this token secure - don't share it publicly!
You can supply the Todoist API token in one of two ways. The script automatically loads .env if present (via python-dotenv) and also reads from environment variables.
Option A — .env file (recommended for local development):
- Create a file named
.envin the project directory with:
TODOIST_API_TOKEN=your-actual-token-here
- Install python-dotenv (once, inside your virtual environment):
python -m pip install python-dotenvOption B — Environment variable (no .env file):
export TODOIST_API_TOKEN=your-actual-token-hereThe script will use TODOIST_API_TOKEN if set; otherwise it will fall back to the placeholder in the file.
Create a project_data.json file in the project directory. Here's the required structure:
{
"project_name": "My Project Name",
"sections": [
{
"name": "Section Name",
"tasks": [
{
"content": "Task name",
"sub_tasks": [
{ "content": "Sub-task 1" },
{ "content": "Sub-task 2" }
]
},
{
"content": "Another task",
"sub_tasks": []
}
]
},
{
"name": "Another Section",
"tasks": [
{ "content": "Task without sub-tasks" }
]
}
]
}project_name: The name of your Todoist projectsections: Array of section objects- Each section has a
nameandtasksarray - Each task has a
content(the task name) sub_tasksis optional - use an empty array[]if a task has no sub-tasks- Tasks can have any number of sub-tasks
-
Make sure your virtual environment is activated:
source .venv/bin/activate -
Ensure your
project_data.jsonfile exists and is properly formatted (see JSON format above) -
(Optional) Verify your token is being loaded from .env:
python -c "from dotenv import load_dotenv; import os; load_dotenv('.env'); print(os.getenv('TODOIST_API_TOKEN'))" -
Run the script:
python import_to_todoist.py
-
Watch the output - the script will print progress as it creates:
- The project
- Sections
- Tasks and sub-tasks
The script automatically handles both new and existing projects:
- If the project doesn't exist: It creates a new project with the name specified in
project_data.json - If the project already exists: It finds the existing project by name and adds new sections and tasks to it
- The script searches your Todoist account for a project matching the name in
project_data.json - If found, it uses that existing project (no duplicates will be created)
- For each section in your JSON:
- If the section already exists, it uses the existing section
- If the section doesn't exist, it creates a new one
- All tasks from your JSON are added to the appropriate sections
Note: The script will always add tasks (even if similar tasks exist). If you run the script multiple times with the same tasks, you'll get duplicate tasks. This is intentional - it allows you to add new tasks to existing projects without accidentally skipping anything.
Project 'My Imported Project' not found. Creating new project...
Successfully created project with ID: 1234567890
Creating new section: 'Planning'...
- Adding task: 'Draft proposal'
- Adding sub-task: 'Outline'
- Adding sub-task: 'Review'
- Adding task: 'Collect requirements'
Creating new section: 'Execution'...
- Adding task: 'Implement feature A'
- Adding task: 'QA pass'
Project import completed successfully!
Found existing project: 'My Imported Project' (ID: 1234567890)
Adding new sections and tasks to existing project...
Found existing section: 'Planning' (ID: 9876543210)
- Adding task: 'New task for existing section'
Creating new section: 'Phase 3 - Marketing'...
- Adding task: 'Create marketing materials'
Project import completed successfully!
Solution: Make sure your virtual environment is activated (source .venv/bin/activate) and the library is installed (python -m pip install todoist-api-python)
Solution: Ensure your token is available via environment:
- Recommended: create
.envwithTODOIST_API_TOKEN=your-tokenin the same folder asimport_to_todoist.pyand installpython-dotenv(python -m pip install python-dotenv). - Or export it in your shell:
export TODOIST_API_TOKEN=your-token(in the same terminal session before running the script). - Note: The script loads
.envfrom the script's directory, regardless of your current working directory.
Solution: Your project_data.json file is empty or invalid. Check that it contains valid JSON (see JSON format section)
Solution: Make sure project_data.json is in the same directory as import_to_todoist.py
Checklist:
python -m pip show python-dotenvshows it is installed in your venv..envis in the same directory asimport_to_todoist.pyand contains a line exactly like:TODOIST_API_TOKEN=0123456789abcdef...(no quotes, no spaces around=)
- Verify load works:
If this prints your token, the script will see it as well.
python -c "from dotenv import load_dotenv; import os; load_dotenv('.env'); print(os.getenv('TODOIST_API_TOKEN'))"
Run deactivate (do not prefix with bash). If you don't see (.venv) in your prompt, the venv isn't active.
todoist/
├── README.md # This file
├── import_to_todoist.py # Main script
├── project_data.json # Your project data (create/edit this)
└── .venv/ # Virtual environment (created by you, don't edit)
# First time setup
cd path/to/todoist
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install todoist-api-python python-dotenv
# Set token (choose one):
# echo "TODOIST_API_TOKEN=..." > .env # Option A (.env)
# export TODOIST_API_TOKEN=... # Option B (env var)
# Every time you work on this
cd path/to/todoist (if not already in your project terminal)
source .venv/bin/activate
python import_to_todoist.py
# When done
deactivate