user = os.environ['ANKI_USER']
passw = os.environ['ANKI_PASS']Core API
OO API
data_path
def data_path(
):
Return the default Anki data folder for this OS.
data_path()Path('/app/data/.local/share/Anki2')
data_path().ls()[Path('/app/data/.local/share/Anki2/User 1')]
profiles
def profiles(
):
List available Anki profile names.
profiles()['User 1']
Collection.open
def open(
profile:NoneType=None
):
Open a collection by profile name (creates if needed).
Class method to open a collection by profile name. Handles backend reuse, creates profile folder if needed, and stores profile_path for auth persistence.
col = Collection.open()
col.profile_pathPath('/app/data/.local/share/Anki2/User 1')
Collection.load_auth
def load_auth(
):
Load SyncAuth from profile folder, or None if not found.
Collection.save_auth
def save_auth(
auth
):
Persist SyncAuth to profile folder.
Auth persistence methods: save_auth writes the SyncAuth protobuf to disk, load_auth reads it back. The endpoint is crucial — AnkiWeb may redirect you to a different sync server.
Collection.sync
def sync(
user:NoneType=None, passw:NoneType=None, media:bool=True, upload:bool=False
):
Full sync implementation: loads saved auth (or logs in), handles endpoint changes, re-authenticates on failure, and manages full upload/download when required.
# First sync requires credentials
col.sync(user=user, passw=passw)
# Subsequent syncs use saved auth
col.sync()close_all
def close_all(
):
Close all open Anki backends (nuclear option for crash recovery).
Nuclear option for crash recovery — scans all Python objects to find and close any open Rust backends.
col.models- Basic
- Basic (and reversed card)
- Basic (optional reversed card)
- Basic (type in the answer)
- Cloze
- Image Occlusion
Markdown representations for decks. DeckManager lists deck names, DeckNameId shows name/id, DeckTreeNode shows name with due counts.
col.sched.deck_due_tree().children[0]Default: 0 new, 0 learn, 4 review
col.decks- Default
Enables dict-style access: col.models['Basic'] returns the model dict, col.decks['Default'] returns the deck id.
mdl = col.models['Basic']
mdl['id']1764648511131
Note.__repr__
def __repr__(
):
Return repr(self).
note = col.new_note(mdl)
note['Front'], note['Back'] = 'hola', 'hello'
noteFront: hola | Back: hello
Deck
def Deck(
col, name
):
Initialize self. See help(type(self)) for accurate signature.
Wrapper class for a deck with convenient .add(), .due (new/learn/review counts), and .cards (list of card ids).
DeckManager.__getitem__
def __getitem__(
name
):
Collection.add
def add(
model:NoneType=None, deck:NoneType=None, tags:NoneType=None, fields:VAR_KEYWORD
):
Add a note with the given fields.
Convenient method to add a note with keyword arguments for fields. Defaults to Basic model and Default deck.
note2 = col.add(Front='hola', Back='hello', tags=['spanish'])Collection.add_deck
def add_deck(
name
):
Create a deck (use :: for nesting).
Creates a new deck. Use :: for nested decks (e.g. "Spanish::Vocab" creates Vocab inside Spanish).
col.add_deck('Spanish::Vocab')changes {
deck: true
browser_table: true
browser_sidebar: true
study_queues: true
mtime: true
}
id: 1767765050214
deck = col.decks['Spanish::Vocab']
deck.add(Front='adiós', Back='goodbye')
deck.dueVocab: 1 new, 0 learn, 0 review
col.remove_notes([note2.id])✓ 1 change(s)
col.decks.remove([col.decks.id_for_name('Spanish')])✓ 1 change(s)
col.sync()host_number: 5
Deck.__repr__
def __repr__(
):
Return repr(self).
Card.__repr__
def __repr__(
):
Return repr(self).
OpChangesWithCount.__repr__
def __repr__(
):
Return repr(self).
DeckTreeNode.__repr__
def __repr__(
):
Return repr(self).
DeckNameId.__repr__
def __repr__(
):
Return repr(self).
DeckManager.__repr__
def __repr__(
):
Return repr(self).
NotetypeNameId.__repr__
def __repr__(
):
Return repr(self).
ModelManager.__repr__
def __repr__(
):
Return repr(self).
col.close()Functional API
Collection.__exit__
def __exit__(
args:VAR_POSITIONAL
):
Collection.__enter__
def __enter__(
):
You can use Collection with Python’s with statement. This ensures the collection is always properly closed, even if an error occurs during your operations. No more orphaned database locks or forgotten cleanup calls.
with Collection.open() as col: note = col.add(Front='hola', Back='hello')add_card
def add_card(
profile:NoneType=None, model:NoneType=None, deck:NoneType=None, tags:NoneType=None, fields:VAR_KEYWORD
):
Add a card.
add_card lets you create a new card with a single function call. Just pass your field values as keyword arguments. By default it uses the Basic note type and Default deck, but you can specify any model, deck, or tags you like.
notezh = add_card(Front='你好', Back='hello')add_fb_card
def add_fb_card(
front:str, back:str, profile:str=None, model:str=None, deck:str=None, tags:str=None
):
Add a card with a Front and Back and return the id.
find_cards
def find_cards(
query:str, profile:str=None
):
Find cards matching query string. Returns list of Note objects.
find_cards searches your collection and returns a list of Card objects. Pass any Anki search query as the first argument. Common query patterns: - deck:Spanish — cards in a specific deck - tag:vocab — cards with a tag - front:hello — match field content - is:due — cards due for review - added:7 — added in the last 7 days
Combine with spaces (AND) or OR: deck:Spanish tag:verb finds Spanish cards tagged “verb”.
cards = find_cards("deck:Default")
cards[Card(1767765051346, nid=1767765051346, due=72, ivl=0, queue=0),
Card(1767765051358, nid=1767765051358, due=73, ivl=0, queue=0),
Card(1764800877095, nid=1764800877095, due=17, ivl=1, queue=2),
Card(1764800880971, nid=1764800880971, due=17, ivl=1, queue=2),
Card(1764800885201, nid=1764800885201, due=17, ivl=1, queue=2),
Card(1764800889323, nid=1764800889323, due=17, ivl=1, queue=2)]
cards[0]Card 1767765051346 (nid: 1767765051346, due: 72, ivl: 0d, queue: 0)
find_card_ids
def find_card_ids(
query:str, profile:str=None
):
Find card ids matching query string.
find_card_ids("deck:Default")[1767765051346, 1767765051358, 1764800877095, 1764800880971, 1764800885201, 1764800889323]
find_notes
def find_notes(
query:str, profile:str=None
):
Find notes matching query string. Returns list of Note objects.
find_notes searches your collection and returns a list of Note objects (rather than Card objects). The query language is the same as find_cards — all the same search patterns work. The difference is that find_notes returns one result per note, while find_cards may return multiple cards if a note generates more than one card (e.g., with Cloze or Basic-and-Reversed note types).
notes = find_notes("hello")
notes[Note(1767765051346, Front='hola', Back='hello', tags=[]),
Note(1767765051358, Front='你好', Back='hello', tags=[])]
note = notes[0]
noteFront: hola | Back: hello
find_note_ids
def find_note_ids(
query:str, profile:str=None
):
Find note ids matching query string.
find_note_ids("hello")[1767765051346, 1767765051358]
update_note
def update_note(
note:int, profile:str=None, tags:str=None, add_tags:str=None, fields:VAR_KEYWORD
):
Update an existing note’s fields and/or tags. Pass a Note object or note ID.
update_note modifies an existing note’s fields and/or tags. Pass either a Note object or a note ID, along with any fields you want to change as keyword arguments. For tags: - tags=['a','b'] — replaces all tags - add_tags='newtag' — adds without removing existing tags
update_note(note, Back="updated answer", tags='testtag')Front: hola | Back: updated answer | 🏷️ testtag
update_note(note, add_tags='moretagz')Front: hola | Back: updated answer | 🏷️ moretagz, testtag
update_fb_note
def update_fb_note(
note_id:int, front:str='', back:str='', profile:str=None, tags:str=None, add_tags:str=None
):
Update an existing note’s front/back fields and/or tags. Pass a Note object or note ID.
update_fb_note(note, front='I am new')Front: I am new | Back: updated answer | 🏷️ moretagz, testtag
get_note
def get_note(
note_id:int, profile:str=None
):
Retrieve a note by ID.
get_note(note.id)Front: I am new | Back: updated answer | 🏷️ moretagz, testtag
del_card
def del_card(
notes:int, profile:str=None
):
Delete card(s) by Note(s) or note id(s).
del_card([notezh, note])✓ 2 change(s)
sync
def sync(
profile:str=None, user:str=None, passw:str=None, media:bool=True
):
Sync collection, handling open/close automatically.
sync handles the entire sync lifecycle for you — opening the collection, authenticating with AnkiWeb, syncing, and closing up afterwards. The first time you sync, pass your AnkiWeb credentials; they’ll be saved for future use.
o = sync(user=user, passw=passw) # First time
# sync() # after thatanki_tools
def anki_tools(
):