Skip to content

Using the Zotero API

For a while I was accumulating articles I wanted to read in a collection in Zotero, which is where I keep track of articles, blog posts, etc. that I've read (see Markdown notes from Zotero).

I recently decided I had a better place to keep these (basically a text file of URLs), so needed to extract the URLS from Zotero, and then delete the items from the collection. The collection size was a few hundred, so not a job to do manually; but the Zotero API was something I wanted to have a look at anyway.

So this post describes getting the URLs for all of the items in a Zotero collection, and deleting the items, using the Zotero web API.

Pyzotero

Zotero provides a pyzotero package for interacting with the API, so first set up an appropriate virtual environment:

python3 -m venv .venv
source .venv/bin/activate

Then in a Python script:

import sys
from pyzotero import zotero, zotero_errors

Zotero authentication and library

You’ll need the ID of the library you want to access. Your personal library ID is available here, in the section marked "Your userID for use in API calls". You’ll also need an API key from the Zotero site. Setlibrary_type to "user":

PERSONAL_LIBRARY_ID = "<your-value-here>"
API_KEY = "<your-value-here>"
LIBRARY_TYPE = "user"

zot = zotero.Zotero(PERSONAL_LIBRARY_ID, LIBRARY_TYPE, API_KEY)

Zotero collections

Make a one-off call to return all the collections in your Zotero library:

for collection in zot.collections():
    print(collection)

And then set the ID of the collection you're interested in:

COLLECTION_KEY = "<your-value-here>"

Collection items

Now you can return the items from the collection; get these from the API in batches of up to 100:

limit = 100
unread_items = zot.collection_items(COLLECTION_KEY, limit=limit)

Then you just need a bit of logic to either print the URL if it seems valid, deleting the item from the Zotero collection with another API call; or skip it:

for item in unread_items:
    url = item["data"]["url"]
    if url.startswith("http"):
        print(url, flush=True)
        try:
            zot.delete_item(item)
        except zotero_errors.ResourceNotFound:
            print("Already deleted", file=sys.stderr, flush=True)
    else:
        print("Bad url: " + url, file=sys.stderr, flush=True)

This also handles a ResourceNotFound exception that seemed to occur occasionally. (I flushed the print statements because I wanted to monitor the output as it ran.)

That's it - running this a few times was enough to remove a collection of several hundred unread items I'd built up in Zotero to read later, and append the URLs to a file by redirecting the standard output of this script.