ποΈ Google Keep Skill is a CLI automation tool that interacts with Google Keep through an undetected headless Chrome browser powered by nodriver.
β‘οΈ Create, read, update, delete, and archive notes β all from the command line with structured JSON output. This acts as a solid primitive for LLM Agents and MCP (Model Context Protocol) Servers, providing bulletproof automation over Google Keep.
π Bot-proof: uses a real Chrome instance with a persistent session, bypassing Google's bot detection entirely.
- 2026-03-02 π Released v1.0.0 β Completely refactored the Basic CRUD (Create, Read, Update, Delete) and Archive functions. The tool now runs with maximum stability using in-memory reads, smart DOM selectors, native CDP/React interactions, and strict JS injection security.
The skill is constantly evolving! Upcoming updates will focus on granular operations:
- Granular List Editing: Modify, delete, or check a single item in an existing list (currently, the update command replaces the entire list).
- Partial Update: Ability to edit only the
titleof a note, preserving the original content in the cloud with 0% risk of formatting loss. - Colors and Labels (Tags): Full support for changing color palettes and adding metadata to existing notes.
- Pinning: Command to pin/unpin notes to the top.
ποΈ Full CRUD Operations: Create, read, update, delete, and archive notes β text or list type.
π List Support: Create checklist-style notes with individual items, each properly injected as separate list entries.
π Persistent Session: Login once manually; the session is saved and reused across all headless executions.
π Structured JSON Output: Every command returns clean, parseable JSON. Ideal for LLM Agents to parse and format into beautiful Markdown.
π₯οΈ Headless by Default: Runs without a visible browser window β perfect for server-side automation and CI/CD.
The skill follows a CLI β Browser Automation β DOM Interaction pattern, isolating authentication from note operations.
| Layer | Technology | Responsibility |
|---|---|---|
| π₯οΈ CLI Interface | argparse / Python | Parses commands and arguments, dispatches to async handlers. |
| π Browser Engine | nodriver (undetected Chrome) | Launches headless Chrome, manages tabs, executes CDP commands. |
| π Auth Layer | CDP Cookies / Chrome Profile | Persists Google session securely via OS-level `~/.config/google-keep-skill` directory with strict permissions. |
| π― DOM Interaction | JavaScript / CDP Input | Finds elements by aria-label and text content, injects values securely avoiding XSS payloads. |
| π€ Output | JSON (stdout) | Returns structured success/error responses for automation consumers to render. |
All commands are executed via the CLI. The backend works unconditionally across Google Keep's dynamic interface.
cd /path/to/google-keep-skill && uv run python scripts/keep.py <command>--visible: Appended before the command (e.g.,keep.py --visible update ...). Forcesnodriverto run the browser in visible mode (headful) instead of secretly executing in the background. Useful for debugging or visually confirming operations.
login: Opens Chrome for manual Google login (one-time setup). The session is bound to the robot's profile and ignored by Git.logout: Clears the currently saved active session data.check: Programmatically verifies if the saved session cookie is still valid without heavily interacting with the UI.
list [--limit N] [--filter "text"]- Passively extracts notes from the DOM grid. Supports case-insensitive text filtering. Returns notes classified as
text(Normal) orlist(Task Lists), always retrieving contents as arrays (lines). Automatically ignores Google Keep's "ghost notes".
- Passively extracts notes from the DOM grid. Supports case-insensitive text filtering. Returns notes classified as
read --title "T"- Actively scans the DOM to extract exclusively the note whose title exactly matches
"T", returning all its data and type into memory.
- Actively scans the DOM to extract exclusively the note whose title exactly matches
create --title "T" --content "C"- Creates a simple text note. Uses CDP interactions and async injection. Accepts the
\nliteral in thecontentparameter to elegantly simulate paragraph line breaks.
- Creates a simple text note. Uses CDP interactions and async injection. Accepts the
create-list --title "T" --items "A, B, C"- Creates a special list type note. The iterative parameter splits commas, typing item by item and simulating organic ENTERs to invoke Google's JavaScript/React chain and build the "checkboxes".
update --title "T" [--content "C"]- The Most Complex Command. Restructures both Normal and List Notes dynamically:
- Normal Text: Copies original state, actively clears canvas (
Ctrl+AandDeletevia organic keyboard events), and re-injects line by line. - Lists: Simulates
MouseEventflows on the exclusion nodes to zero out the list, and then sequentially injects the new--contentsimulatingcreate-listlogic.
- Normal Text: Copies original state, actively clears canvas (
- The Most Complex Command. Restructures both Normal and List Notes dynamically:
delete --title "T"/archive --title "T"- Extremely precise. They open the note in modal mode and interact lowly with the floating menu to delete/archive it instantly without relying on unstable screen coordinates grids.
When an LLM Agent or MCP server wraps this skill:
- Always format the output. Do not vomit the raw JSON to the user. Extract
data.notesand format lists as Markdown checklists (- [ ] Item) or Markdown unordered lists. - Handle session drops gracefully. If
success: falseand the message mentions "Session expired", clearly inform the user to run thelogincommand in the terminal. - Always read before updating. If required to append or edit an existing note, the agent MUST call
readfirst, rebuild the state in its context, and push the complete rewritten string intoupdate.
# 1. Text Note Creation
uv run python scripts/keep.py create --title "Meeting Notes" --content "Discuss roadmap\nReview budget\nAssign tasks"
# 2. List Note Creation
uv run python scripts/keep.py create-list --title "Groceries" --items "Milk, Bread, Coffee, Eggs"
# 3. Universal Listing
uv run python scripts/keep.py list
# 4. Listing With Filters (Returns max 5 tickets containing "meeting")
uv run python scripts/keep.py list --filter "meeting" --limit 5
# 5. Specific Local Scan
uv run python scripts/keep.py read --title "Meeting Notes"
# 6. Updating an Entire List (Resetting previous items)
uv run python scripts/keep.py update --title "Groceries" --content "Milk\nAlmond Milk\nSugar"
# 7. Updating the Content of a Text Note
uv run python scripts/keep.py update --title "Meeting Notes" --content "Updated content exclusively"
# 8. Clearing the Board (Delete and Archive)
uv run python scripts/keep.py delete --title "Old Note"
uv run python scripts/keep.py archive --title "Completed Task"| Storage | Path | Purpose |
|---|---|---|
| Chrome Profile | ~/.config/google-keep-skill/chrome-profile/ |
Full browser state (cookies, cache, localStorage). |
| Cookie Backup | ~/.config/google-keep-skill/cookies.json |
CDP cookie backup restored on each headless session. |
Important
These files are stored securely in the user's OS home directory with 0o700/0o600 permissions. They are completely decoupled from the skill codebase to prevent data leaks.
# Run the End-to-End test suite (requires active session)
uv run python scripts/test_crud.py- CSS selectors may break if Google updates the Keep UI
- Requires one-time manual login (session is persistent afterward)
- Only one Chrome instance can use the profile at a time
Ricardo Reichert
This project is released under the MIT License.