Bernhard Bock

Migrate Joplin Web Clipper to raindrop.io

For saving stuff from the web, I basically have these requirements:

  • Sync my bookmarks / saved pages across all mobile and desktop devices
  • Have them searchable and tagged
  • Save pages offline, in case the page disappears

In the past, I was using Joplin Notes with the web clipper browser extension to save web pages and URLs offline and have them synced via Nextcloud.

That worked pretty well for all major desktop operating systems (I use macOS, Windows and Linux in parallel), but it fell short on both iOS and Android: Syncing works, but the mobile apps are not well integrated into mobile browsers. Browser extensions are not available and the sharing workflow doesn’t work well with the Joplin apps.

Since I discovered raindrop.io, I was using Raindrop Pro instead. While it is not open source, it has an open and well-documented API and polished mobile apps. In the “Pro” version, it also stores web pages and makes them searchable.

Of course, I dont want to loose my old data, so I needed to migrate stuff from Joplin to Raindrop. I exported the Joplin notebook as markdown files, and wrote a simple python script to import into Raindrop via API:

#!/usr/bin/env python3

from typing import Collection
from frontmatter import Frontmatter
from pathlib import Path
from raindropio import API, Collection, Raindrop

RAINDROP_ACCESS_TOKEN = "__PUT_YOUR_TOKEN_HERE__"

# this is the raindrop collection to which Joplin shall be imported
# create the collection in the UI of raindrop, get the ID from the URL
JOPLIN_COLLECTION = __PUT_YOUT_COLLECTION_ID_HERE__

raindrop = API(RAINDROP_ACCESS_TOKEN)
joplin_collection = Collection.get(api=raindrop, id=JOPLIN_COLLECTION)

webclips = Path("__PATH_TO_WEBCLIPS_EXPORT__")
for file in webclips.iterdir():
    post = Frontmatter.read_file(file)

    if "source" in post["attributes"]:
        print(post["attributes"]["source"])
    else:
        continue

    if "tags" in post["attributes"]:
        tags = post["attributes"]["tags"]
    else:
        tags = []

    bookmark = Raindrop.create(
        raindrop,
        link=post["attributes"]["source"],
        tags=tags,
        collection=joplin_collection,
        created=post["attributes"]["updated"]
    )

This is import works only for pages that still exist (which was good enough for me, I saved the dead pages elsewhere in my files). I can access the saved pages in the browser and save them with SingleFile in case I need it locally.

The import also preserves tags, which is very important for me.

— Nov 23, 2022