Updated January 24, 2021
To build this blog, I first reverse-engineered Notion's private API. Notion is working on a public API, but for the time being I decided to build my own API by watching Chrome's dev tools while loading a Notion doc.
This turned into an open-source project called Potion, which includes hosted API endpoints that you can use.
My blog posts are written in a full-page table in Notion:
Because of Notion's structure for tables, each row in this table is also its own Notion document. This document contains the content of each blog post.
I also have a few other fields (columns) in the table, which include the URL of the blog post, when it was published, and whether it should be made public. I can use these to transfer each blog post (each row) onto my website.
Now for the fun part: pulling in the blog posts from Notion.
As I mentioned earlier, building this blog relied heavily on API endpoints from my open-source project Potion, specifically
potion-api.now.sh/table for getting the list of blog posts and
potion-api.now.sh/html for getting the HTML for each blog post.
Also make sure to set your Notion table to public sharing so the API can access it.
Essentially, when my site is being built, I use
node-fetch to make a request to
/table and list out all the blog posts. It filters down to only blog posts where
true, and then builds my site's
/blog page to list those posts.
Then, for each published post, it takes the
id of that row in the table and makes another request to
/html using that page's ID. This endpoint returns fully-baked HTML of the document's contents. I now just have to insert that HTML into a template for each blog post, along with the title from the earlier
/table call, and I can generate all the blog post pages (like the one you're looking at right now).
I've written some other blog posts on using the Potion API for Notion: