Loconotion is a Python script that parses a Notion.so public page (alongside with all of its subpages) and generates a lightweight, customizable static site out of it.
Notion is a web app where you can create your own workspace / perosnal wiki out of content blocks. It feels good to use, and the results look very pretty - the developers did a great job. Given that it also offers the possibility of making a page (and its sub-pagse) public on the web, several people choose to use Notion to manage their personal blog, portfolio, or some kind of simple website. Sadly Notion does not support custom domains: your public pages are stuck in the
notion.so domain, under long computer-generated URLs.
Some services like Super, HostingPotion, HostNotion and Fruition try to work around this issue by relying on a clever hack using CloudFlare workers. This solution, however, has some disadvantages:
- Not free - Super, HostingPotion and HostNotion all take a monthly fee since they manage all the "hacky bits" for you; Fruition is open-source but any domain with a decent amount of daily visit will soon clash against CloudFlare's free tier limitations, and force you to upgrade to the 5$ or more plan (plus you need to setup Cloudflare yourself)
- Ugly URLs - While the services above enable the use of custom domains, the URLs for individual pages are stuck with the long, ugly, original Notion URL (apart from Fruition - they got custom URLs figured out, altough you will always see the original URL flashing for an instant when the page is loaded).
- Notion Free Account Limitations - Recently Notion introduced a change to its pricing model where public pages can't be set to be indexed by search engines on a free account (but they also removed the blocks count limitations, which is a good trade-off if you ask me)
Loconotion approaches this a bit differently. It lets Notion render the page, then scrapes it and saves a static version of the page to disk. This offers the following benefits:
- Caches all images / assets / fonts (hashing filenames), while keeping links intact.
- Cleans up the pages urls, letting you use custom slugs if desired
- Full meta tags controls, for the whole site or individual pages
- Granular custom Goggle Fonts control on headings, navbar, body and code blocks
- Lets you inject any custom style or script, from custom analytics or real-time chat support to hidden crypto miners (please don't do that)
- Outputs static files ready to be deployed on Netlify, GitHub Pages, Vercel, your Raspberry PI, that cheap second-hand Thinkpad you're using as a random server - you name it.
The result? A faster, self-contained version of the page that keeps all of Notion's nice page layouts and eye candies. For comparison, that same example page parsed with Loconotion and deployed on Netflify's free tier achieves a PageSpeed Insight score of 96 - 100!
Bear in mind that as we are effectively parsing a static version of the page, there are some limitations compared to Notion's live public pages:
- All pages will open in their own page and not modals (depending on how you look at it this could be a plus)
- Databases will be presented in their initial view - for example, no switching views from table to gallery and such
- All editing features will be disabled - no ticking checkboxes or dragging kanban boards cards around. Usually not an issue since a public page to serve as a website would have changes locked.
- Dynamic elements won't update automatically - for example, the calendar will not highlight the current date.
Everything else should be fine. Loconotion re-implements the logic on client side for the following dynamic elements so they still work:
- Toggle blocks (nested ones too!)
- Anchor links
- Name column on tables become a link to the page of the database item in that row
On top of that, it defines some additional CSS rules to enable mobile responsiveness across the whole site (in some cases looking even better than Notion's defaults - wasn't exactly thought for mobile).
But Notion already had an html export function?
It does, but I wasn't really happy with the styling - the pages looked a bit uglier than what they look like on a live Notion page. Plus, it doesn't support all the cool customization features outlined above!
You can check out an example site containing most of Notion's blocks / elements exported as a static site with Loconotion, and hosted on Netlify: https://loconotion-example.netlify.app/
For reference, the original Notion public page that the site was generated from can be accessed here.
Installation & Requirements
Make sure you're in your virtual environment of choice, then run
poetry install --no-devif you have Poetry installed
pip install -r requirements.txtotherwise
This script uses ChromeDriver to automate the Google Chrome browser - therefore Google Chrome needs to be installed in order to work.
The script will automatically try to download and use the appropriate chromedriver distribution for your OS and Chrome version. If this doesn't work, download the right version for you from https://chromedriver.chromium.org/downloads and use the
--chromedriver argument to specify its path at runtime.
There is a Docker support also. To build a container and to render the page run:
# Build container with loconotion $ docker-compose build loconotion # Run loconotion renderer with any arguments $ docker-compose run loconotion PATH_TO_NOTION_FILE [ARGS]
Docker container is built from
python:3.8 tag, there is google-chrome-stable and chromedriver installed. See more in docker/Dockerfile.
python loconotion https://www.notion.so/The-perfect-It-s-Always-Sunny-in-Philadelphia-episode-d08aaec2b24946408e8be0e9f2ae857e
In its simplest form, the script takes the URL of a public Notion.so page, and generates the site inside the
dist folder, based on the page's title (the above example will generate the site inside
You can fully configure Loconotion to your needs by passing a .toml configuration file to the script instead:
python loconotion example\example_site.toml
Here's what a full .toml configuration would look like, alongside with explanations of each parameter.
On top of this, the script can take these optional arguments:
-h, --help show this help message and exit --chromedriver CHROMEDRIVER Use a specific chromedriver executable instead of the auto-installing one --single-page Only parse the first page, then stop --dark-theme Use dark themed version of the target Notion.so page --timeout TIMEOUT Time in seconds to wait for the loading of lazy-loaded dynamic elements (default 5). If content from the page seems to be missing, try increasing this value --clean Delete all previously cached files for the site before generating it --clean-css Delete previously cached .css files for the site before generating it --clean-js Delete previously cached .js files for the site before generating it --non-headless Run chromedriver in non-headless mode -v, --verbose Increase output log verbosity
Roadmap / Features wishlist
- Customizable navbar breadcrumbs
- Dark / light theme toggle
- Automated deployements (e.g. Netlify / GitHub pages / Vercel / etc.)
- Injectable custom HTML
- HTML / CSS / JS minification & images optimization
- More advanced custom theming
Sites built with Loconotion
If you used Loconotion to build a cool site and want it added to the list above, shoot me a mail or submit a pull request!
If you found this useful, consider buying me a coffee so I get a a nice dose of methilxanthine, and you get a nice dose of karma.