the enhancer is essentially a modloader for notion. this document contains the specifications of how those modules can be made and what they should contain.

this file assumes basic working knowledge of modern javascript and css. since these are the languages executable within the notion app, these are the languages enhancements must be written in.

want to contribute? check the contribution guidelines.

for support, join the discord server.

creating a mod

to understand best how notion’s app works, check out the electron docs, explore the contents of your local extracted app.asar, and navigate the html structure with the devtools web inspector.

look through the existing modules for examples of the stuff described below in action.

at the moment, for ease of development and use (and security assurance), there’s no way for users to install their own modules. this means that testing modules requires running a dev build of the enhancer. a better system is in the works.

once your mod is working, open a pull request to add it to the enhancer!

each directory in the mods folder is considered a module, with the file entry points mod.js and styles.css.

file description
mod.js required: describes the module and contains functional javascript
styles.css optional: a css file automatically inserted into each app window


// not valid js!
// a visual representation of the contents/type
// of this file's exported object.
module.exports = {
  id: String of uuidv4,
  name: String of short_name,
  tags?: Array<String> of categories,
  desc: String of markdown,
  version: String of semver,
  author: String of github_username OR {
    name: String of author_name,
    link: String of url,
    avatar: String of image_source,
  options?: Array<{
    key: String,
    label: String,
    type: String in ['toggle', 'select', 'input', 'file'],
    value: Boolean or Array<String> or String or Number or null
  fonts: Array<String> of font_urls,
  hacks?: {
    [k: 'insert-point' (e.g. 'main/createWindow.js')]: function (
      store, // used for configuration and persisting of data (explanation below).
      __exports // module.exports of the target file. if you don't understand that, don't use it.
    ) {}
key value type
id required: uuidv4 - generate a new one here string
name required: short name (e.g. 'ocean theme') string
tags required: categories/type (e.g. 'extension', 'theme', 'light', 'dark') array<string>
desc optional: 1-3 sentence description of what the module is/does, with basic markdown support. string
version required: semver (e.g. '0.3.7') string
author required: see below: original extension creator string or <object>
options optional: see below: options made available in the enhancer menu (accessible from the tray) array<object>
fonts optional: a list of any font imports - should be https:// or enhancement:// urls array<string>
hacks optional: see below: code inserted at various points object

a module that with the primary function of being a hack should be tagged as an extension, while a module that has the primary function of adding styles should be tagged as a theme.


by default this is assumed to be a github username: just pass it as a string and the link/avatar will be automatically found.

if you’d rather customise this, pass this object:

key value type
name required: author’s (your?) name string
link required: link to the author’s profile string
avatar required: url for the author’s avatar string


key value type
key required: key to save value to the mod store string
label required: short description/name of option to be shown in menu string
type required: input type (see below) string
extensions optional: allowed file extensions (only use with a file option), e.g. ['js', 'ts'] array<string>
value optional: default or possible value/s for option see below
type value
toggle boolean
select array<string>
input string or number
color string
file none

the file option stores only a filepath, not the file itself.


each “hack” is a function taking 2 arguments.

  1. the store argument, which allows access to the module settings/options defined in mod.js (those set in the menu, or used internally by the module). each module store is automatically saved to + loaded from ~/.notion-enhancer/id.json. it should always be called as store({ defaults }) (not stored in a variable), but otherwise treated as a normal object to access and set things.
  2. the __exports argument, which is the module.exports of the file being modded. this can be used to call or replace functions from notion.

this hack is applied to whichever file (.js-only) is set as the function key. these can be found within the app folder.

files under the main folder are executed on app launch in a process shared between all app windows (consider it a backend). files under the renderer folder are executed on window launch in a pre-window process: the client-side javascript normally expected to run on a webpage.

unless scripts need to change app logic (e.g. to add the tray menu), they should usually be applied to renderer/preload.js to interact with the app window itself.


// sayhi.js
module.exports = function (store, __exports) {
  document.addEventListener('readystatechange', (event) => {
    if (document.readyState !== 'complete') return false;
    console.log(store({ name: 'dragonwocky' }).name);
// mod.js
module.exports.hacks = {
  'renderer/preload.js': require('./sayhi.js'),

the enhancement:// protocol

any files within the mods folder can be loaded with the enhancement:// protocol.

for example, inserting an image from the core mod: <img src="enhancement://core/image.png">.


the enhancer has been designed with theming in mind, so as much of notion’s colours and typography as possible and some basic spacing (both for the light and dark themes) have been mapped out using css variables.

this set of variables is 100% mandatory to use if you wish to use or change anything they handle (particularly colours). this is necessary to keep all themes consistently working (e.g. styling the menu and responding properly to light/dark theme changes), and it makes theming a lot easier - notion’s html structure needs some complex selectors to properly modify it, and it means theme authors don’t have to worry separately updating their theme every time something changes.

the full/up-to-date list of variables and their default values can be found in the variables.css file. each variable is named something along the lines of --theme_mode--target_name-property. still not sure what a variable does? try changing it and seeing what happens.

these are all made possible by the core module. if you believe this set of variables is buggy or lacking in any way, consider opening a pull request to fix those issues - please do not try and reinvent the wheel unnecessarily.

want to import an external font or import an included font file? do that in the mod.js file, otherwise it won’t be used for the enhancements menu.

using variables

variables should be used without specifying which mode they are relevant to. for example:

:root {
  --theme_dark--main: rgb(5, 5, 5);

.demo-element {
  background: var(--theme--main);

this to simplify styling and make it possible for things like the “night shift” module to work, by leaving the choice of light/dark theme up to the user and then directing the right values to the relevant variables.