Keep-it-markdown or KIM converts Google Keep notes to markdown using the unofficial Python Keep API without having to use Google Takeout to export notes first. KIM can now also import markdown notes back to Keep. The script will execute on Windows, MacOS or Linux.
The overall goal is to utilize Google Keep as an easy way to capture raw notes on all devices or additionally using the browser plugin. Then, notes can be queried for export to markdown files directly into notetaking apps such as Obsidian, Logseq, Apple Notes, Joplin and/or Notion, or used directly with Typora.
Advanced Users: see the INSTALL.md to skip over these installation details for simple step-by-steps
Install assumes you have some familiarity with running scripts through a terminal or command line. KIM is a command line script that requires Python 3.10 or greater and utilizes the unofficial gkeepapi. (If you have Python versions 3.10+ and have login issues you may need to review Advanced Docker Setup below)
NOTE: Be aware that 'unofficial' implies that Google could change the API at any time that might stop the script from working!
You only need to run installation steps 1 through 6 one time.
Install Python (there are plenty of tutorials online for installation instructions) on you PC or Mac. If you have an older version of Python (3.8 or 3.9) installed and you want to leave it, you can install pyenv to run multiple versions. Start your command prompt, shell or terminal and verify your python version by running:
> python --version
If you had Python 2 installed already you may need to type 'python3' instead of just 'python' for the rest of these steps to use version 3.10+.
Download this project's zip file into any new directory of you choice. Select the most current release noted at the top right of this page and download 'Source code' using this link:
https://github.com/djsudduth/keep-it-markdown/releases
Unzip the files within your chosen directory.
Make sure you are in your KIM directory and install all needed dependencies with:
> pip install -r requirements.txt
(you may need to use 'pip3' instead of 'pip' if you have both python versions 2 and 3 installed) This will install the additional libraries needed to run KIM. You only need to do this once. If you have Anaconda as your Python base you may need to find tutorials on how to get pip and install dependencies. Advanced users may want to setup a virtual environment for this.
KIM requires a Google Keep authentication token in order to run. The token can only be retrieved once you have a Google page OAuth cookie. Install the Chrome extension called 'Cookie Tab Viewer'. Change the directory to where you installed KIM.
Here's the tricky part - you need to get your OAuth token from a Google cookie. To get the OAuth token - follow the "Second way" instructions here (but get the cookie value using the Chrome extension once you've pressed "I agree" on the Google page in the Second way method): https://github.com/rukins/gpsoauth-java?tab=readme-ov-file
Copy the cookie called oauth_token using the Chrome Cookie Tab Viewer from the cookies in your local browser. Then, run the script
> python get_token.py
You will be prompted for your Google email account name, OAuth token, and Android ID
The AndroidID can just be a random value like: abcdef123
So, when you get the prompt when running the script:
Email: your google ID
OAuth Token: oauth2_4/......rest of token
Android ID: abcdef123
The Keep token should be displayed - it should look like:
"aas_et/FKcp.............lots of characters.....................BjQ="
Copy that token and save it in a safe place! If it didn't work your OAuth token may have expired (takes about 5 min to expire). Run this step again until you get the token.
You now need to save your Keep token within the KIM secure keyring
> python kim.py -t <your long token value here>
If you entered your Google email and token correctly, you should see a successful login with the statement -> "You've succesfully logged into Google Keep!"
If this step keeps failing see 'Key Callouts' #9 below, and have issues with the login - see Advanced Docker Setup below
Congrats! You can now run KIM. Simply start by running:
> python kim.py
After logging in you should see:
> Enter a case sensitive keyword or label search or '--all' to convert Keep notes to md or '--x' to exit:
Entering a query term and pressing Enter will execute your first export of a note or set of notes as individual markdown files from your active note list.
NOTE: first time you execute, exported md files will be created in a default KIM sub-directory called 'mdfiles' within your install directory. Images are exported into 'media' within the default directory. This can be changed later.
For the first test, use a keyword query that returns and converts only a few notes at most (you can do the search in Keep first to see how many notes will be returned by your query/convert term).
You can convert to md by using a single word, a phrase or by a label. All queries to convert ignore notes in archive and trash unless you use the option flags below. KIM will stay active to do more conversions until you just press --x or Ctrl-C.
At first launch KIM will create a settings.cfg file in the directory where you chose to install KIM. You can modify these settings with a text editor:
google_userid = your-google-account-id (allows you to bypass typing in your id)
output_path = path to where the output md files are created (if empty it is your install directory). Windows users use forward slashes, e.g. -> c:/md-files/export.
media_path = location of the exported media files (images, audio) relative to your output_path. If the output_path is /mdexport and media_path is media/data, the media full path will be /mdexport/media/data. Media paths cannot start with /, mount or drive letter.
(For import settings, see the -i switch below)
All KIM options can be discovered using
> python kim.py --help
Also see EXAMPLES.md for many option combinations
Searching for notes by labels just requires the # character in front of the search term like '#MyLabel'. On some operating systems like Linux you may need to enclose the term in quotes.
Exported note titles use Keep titles in conversion as best it can. In many cases Keep notes do not have titles and by default KIM will use the create date-time as the title. If you wish to use the beginning body content for blank Keep titles use
> python kim.py -c
if the note has no title or text in the body then the date will be used as default.
KIM by default does not overwrite markdown files when exporting, principally because Keep notes can have the same titles. KIM will try to rename duplicate notes. However, notes can be overwritten with
> python kim.py -o
all exported md files will be overwritten. However, if 2 or more Keep notes have the same title, the create date will be appended on the note to be unique.
If you want to skip or ignore notes that have already been exported then
> python kim.py -s
will skip exporting Keep notes to markdown that already exist in the destination directory. If 2 or more Keep notes have the same title and a markdown file already exists with that name, a new export will be created for any exports that do not exist. (Note that overwrite and skip cannot be used at the same time)
Many markdown applications cannot work with special characters in labels/tags (such as brackets, parentheses, asterisks, etc). By default, KIM will strip out all special characters and replace them with dashes(-). If you need to preserve labels in their original form, use the -p option:
> python kim.py -p
Apple notes with media links will only import if both the note and media are combined within a MacOS folder. With this switch KIM will create individual folders for each markdown file that has media - otherwise just a file is created. Markdown titles are also added to allow Apple Notes to have titles. You can enable this feature with
> python kim.py -an
Notion requires the markdown files to be wrapped as a ZIP file first to import media successfully. Once imported Notion will show all files under the folder name. Tags/labels are not supported with Notion import. You can enable this feature with
> python kim.py -no
Some markdown systems prefer to have bullets prepended on each paragraph within a note. KIM will attempt to prepend a dash to any Keep note that has 2 linefeeds as well as the first line. You can enable this feature with
> python kim.py -l
Joplin tags do not use the hashtag format. They are provided as front matter comments within the notes. With this switch KIM will prepend notes with the Joplin front matter comments to preserve tags and dates. You can enable this feature with
> python kim.py -j
KIM now supports filtering your export by either the created date (-cd) or edited date (-ed). This can be combined with the other options to export notes only after or before specific dates. Only the greater-than > or less-than < filters are available. You must provide the <|> preceeding the date. The date must be in the form YYYY-MM-DD. For example, you can filter on any notes created before Dec 9, 2022 with:
> python kim.py -cd "< 2022-12-09"
Or, you can filter on any notes edited after Oct 31, 2023 with:
> python kim.py -ed "> 2023-10-31"
(Note that Linux users my have to use single quotes)
If you have a large number of notes it can be confusing which ones have already been exported. With this switch any exported notes will be moved to the Keep archive. You can enable this feature with
> python kim.py -m
KIM can run through your own script by using the -b flag. For example, running:
> python kim.py -b 'my search term'
or
> python kim.py -b --all
will execute KIM without input prompts as long as you have your Google ID in the setting.cfg file and you have stored your Keep access token by running KIM once manually on your device. Be sure the -b flag is the last of all option flags when combining them.
KIM can suppress any screen prompts or status messages using the -q flag. Silent or quiet mode will pipe all output to at file called kim.log in the install diretory. This is useful for batch mode execution. You must have settings.cfg setup with your google id so the user prompt will not display. This works both for exporting and importing:
> python kim.py -q -b '#mylabel'
Sometimes you need to find Keep notes that do not have labels. Keep doesn't offer this type of search. Use the -n flog to output a report of all notes missing labels. No notes are exported - only a list of notes is provided:
> python kim.py -n -b --all
KIM by default appends labels as hashtags at the end of notes. However, Keep can create labels either from the menu or by using hashtags embedded within the note text. KIM can remove any duplicate tags at the end of exported notes using the -d flag. This will allow in-line tags in notes so that apps like Obsidian and Logseq won't have duplicates appended:
> python kim.py -d
NOTE: If you've used inline hashtagging within notes that have unusual characters, this option will not modify the hashtag within the note. Use the -p option to preserve labels and hashtags in their original form without modification
KIM has an option to export only Keep archive notes. All other note types are ignored with this option
> python kim.py -a
Archive export can be combined with the -o and -b options.
KIM has an option to modify pre-existing Keep note-to-note links that are in markdown format such as [Other Keep Note](https://keep.google.com/#NOTE/dks7r23ksdf...UI9kshweriuhv) to just [[Other Keep Note]]
> python kim.py -w
This is very useful if want to use Wikilinks for note-to-note links in Obsidian or Joplin.
KIM supports converting embedded hashtags to Keep labels that haven't been added to the note. For example, you may have a note like ("Today I found an interesting article #readlater") - and, #readlater is not a label yet. This allows you to convert that tag automatically to either an existing label or a new label. Number of notes to alter is limited to a few and no notes are exported.
> python kim.py -h
KIM supports importing markdown note files back into Keep using
> python kim.py -i
**WARNING! Google may lock you out of your account if
$ claude mcp add keep-it-markdown \
-- python -m otcore.mcp_server <graph>