Skip to main content

Migrating my Pocket bookmarks to Obsidian

·3 mins

Context #

I’ve been using Pocket to manage my bookmarks for about 10 years and I’m honestly quite happy with it… but I’ve just rolled out my own bookmark manager, so I want to migrate all my bookmarks there, so that they will be available in my Obsidian Vault.

Exporting bookmarks from Pocket #

Pocket offers an API to interact with your bookmarks, protected by an OAuth2 authentication & authorization flow: this is a great option if one plans to keep using Pocket (and there are already solutions to help with that scenario), I’d actually like to make Pocket redundant, so I’m looking for a way to perform a one-time export of my stored URLs along with their tags… which is precisely what I can get out of the Pocket Export page: an HTML document with a list of links, each providing the URL, the epoch timestamp in which I bookmarked it, and a list of tags.

<!DOCTYPE html>  
<html>  
    <!--So long and thanks for all the fish-->  
    <head>  
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />  
       <title>Pocket Export</title>  
    </head>  
    <body>  
       <h1>Unread</h1>  
       <ul>  
          <li><a href="https://github.com/fedragon/bookmarkd" time_added="1719980127" tags="engineering">A local-first bookmark manager</a></li>
        ...
    </body>
</html>

(kudos to the Pocket team for that Hitchhiker’s Guide to the Galaxy quote at the beginning of the document 😂)

Importing bookmarks into bookmarkd #

Now that I have a list of my bookmarks, I want to go through them and issue requests to my own bookmark manager: since I need to use the Obsidian URI protocol ( obsidian://), I still need to run a browser.

An automation tool such as Playwright fits the bill: I can parse the HTML file, prepare the Obsidian URIs, and ask the builtin browser to open them. I wrote a small script for that purpose, started testing it and… requests failed with net::ERR_ABORTED 🤔

What the backend service does is sending an HTTP 302 response pointing to the Obsidian URI, for which the browser shows a confirmation dialog to the user. Looking around, I’ve found out that those kind of dialogs cannot currently be handled by Playwright since they are not part of any standard browser API: the only option is to instruct the browser to trust Obsidian URIs without asking the user.

After a lot of research and failed attempts at manually setting the Obsidian protocol handler in preferences’ files, I had to give up and accept a manual process (for now, at least). The short-term, not ideal, solution I have used is the following:

  • open an existing Chrome installation and type obsidian:// in the URL bar, then select Open app
  • make Playwright connect to that Chrome installation in debug mode, by running the following command (path to Google Chrome may vary depending on your OS):
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=1243

I have then instructed Playwright to connect to it using

const browser = await chromium.connectOverCDP('http://localhost:1243');

and things started working.

It’s disappointing that I could not find any way to automate this, but browsers are very restrictive when it comes to registering custom protocols, for security reasons: both Firefox and Chrome implement a registerProtocolHandler() function in their respective APIs, but they only allow a given set of permitted scheme (and obsidian is not among those).

The complete script is available in the pocket-importer directory of my repository, its README.md explains all the required steps.