-
-
Notifications
You must be signed in to change notification settings - Fork 3
Guide: Templating
Readwise Mirror uses the powerful Nunjucks templating engine to give you full control over the content and structure of your notes. This guide covers the available templates, variables, and filters that you can use to customize your sync.
The templating system works by combining templates, variables, and filters:
-
Function: A template defines the structure and layout of the Obsidian notes this plugin generates from each Readwise item that is synced. It contains a mix of static text (like headings) and dynamic placeholders for your Readwise data. The plugin uses three templates which are combined to create a single note.
-
Application: The plugin builds each note in a specific order:
- First, the Frontmatter Template is processed to create the note's metadata.
- Next, the Header Template is processed to create the top section of the note's body.
- Finally, the plugin loops through every highlight and applies the Highlight Template once for each, appending the results in order.
-
Function: A variable is a placeholder that represents a specific piece of data from your Readwise library, such as a book's title or the text of a highlight.
-
Application: You insert a variable into a template using double curly braces:
{{ variable_name }}. During a sync, the plugin replaces this placeholder with the actual data.-
Example: The variable
{{ title }}is replaced by the book's title, such asThe Psychology of Money.
-
Example: The variable
-
Function: A filter is a special function that modifies the content of a variable before it is placed in the final note. Filters are used for formatting, such as changing a date's appearance or ensuring text is correctly quoted. They do not change your original data in Readwise, only how it is displayed in Obsidian.
-
Application: You apply a filter to a variable using the pipe symbol (
|). This "pipes" the variable's content through the filter to transform it.-
Example: To format a timestamp into a simple date:
-
Variable:
{{ last_highlight_at }} -
Raw Data:
2024-02-18T10:00:00Z -
Template Code:
{{ last_highlight_at | date("YYYY-MM-DD") }} -
Final Output:
2024-02-18
-
Variable:
-
Example: To format a timestamp into a simple date:
You can customize three distinct parts of each note, which are combined to create the final file.
- Frontmatter Template: Controls the note's metadata (also called "properties" in Obsidian). This section is at the very top of the file and must be valid YAML.
- Header Template: Defines the top section of the note's body. This is the perfect place for displaying cover images, titles, authors, and other metadata you want to see in the note content itself.
- Highlight Template: Formats each individual highlight and its associated notes. This template is rendered once for every highlight in the document and appended in order.
Variables are placeholders for data from Readwise. You can insert them into your templates using {{ variable_name }}.
These variables are available in the Frontmatter and Header templates.
| Variable | Description | Example |
|---|---|---|
id |
The unique ID for the document | 12345 |
title |
The original title of the document | "The Psychology of Money" |
sanitized_title |
A filesystem-safe version of the title | "The-Psychology-of-Money" |
author |
The author's name(s) as an array | ['Morgan Housel'] |
authorStr |
The author's name formatted with wiki links | "[[Morgan Housel]]" |
category |
The content type | "books" |
document_note |
Your note on the document itself | "A great collection of..." |
summary |
The document's official summary | "Timeless lessons on wealth..." |
num_highlights |
The total number of highlights | 42 |
| Variable | Description | Example |
|---|---|---|
highlights_url |
The URL for the item in Readwise | "https://readwise.io/..." |
source_url |
The URL of the original content | "https://www.collaborativefund.com/..." |
unique_url |
The Reader URL (if available) | "https://readwise.io/reader/..." |
cover_image_url |
The URL for the cover image | "https://images-na.ssl-images-amazon.com/..." |
| Variable | Description | Example |
|---|---|---|
tags |
Document tags, including the #
|
"#finance, #psychology" |
tags_nohash |
Document tags without the #
|
"'finance', 'psychology'" |
highlight_tags |
All highlight tags, including the #
|
"#important, #quote" |
hl_tags_nohash |
All highlight tags without the #
|
"'important', 'quote'" |
| Variable | Description | Example |
|---|---|---|
created |
The date the item was created | "2023-01-15T12:00:00Z" |
updated |
The date the item was last updated | "2024-02-20T18:30:00Z" |
last_highlight_at |
The date of the most recent highlight | "2024-02-18T10:00:00Z" |
These variables are available only inside the Highlight Template.
| Variable | Description | Example |
|---|---|---|
text |
The highlighted text | "The highest form of wealth is..." |
note |
Your personal annotation on the highlight | "This is a key insight." |
color |
The color of the highlight | "yellow" |
| Variable | Description | Example |
|---|---|---|
location |
The position reference (e.g., page) | "Page 42" |
location_url |
A direct link to the location (e.g., Kindle). Empty (undefined/empty if ASIN and/or location are not available) |
"kindle://..." |
url |
A direct link to the highlight on Readwise | "https://readwise.io/open/..." |
| Variable | Description | Example |
|---|---|---|
id |
The unique ID for the highlight | "98765" |
tags |
Tags associated with the highlight | "#important, #todo" |
updated_at |
The timestamp of the last update | "2024-02-20T18:30:00Z" |
Filters are functions you can apply to variables to transform their output. The syntax is {{ variable | filter }}.
| Filter | Description | Example |
|---|---|---|
fme |
Escapes frontmatter, deals with multi-line text, quotes, and other special characters. Use this as the last filter to escape (all) variables in your frontmatter templates or in Atomizer blocks | {{ text | fme }} |
bq |
Adds blockquote markers (>) to each line of text. |
{{ text | bq }} |
is_qa |
Returns true if a note contains the .qa action tag. |
{% if note | is_qa %} |
qa |
Converts a .qa note into a Q&A format. |
{{ note | qa }} |
date |
Formats a timestamp using Moment.js syntax. | {{ created | date("YYYY-MM-DD") }} |
This filter escapes the input and ensures valid frontmatter is generated. It works for both single-line and multi-line values. Use it in the frontmatter templates and in atomize blocks in the highlights template.
The following will escape a single-line value:
---
title: {{ title | fme }}
---The following escapes the note and highlight into a properly formatted frontmatter property which can be used in an atomize block:
---
highlight: {{ text | fme }}
note: {{ note | fme }}
---N.B.: This also works for JSON when using the dump() filter: json: {{ json | dump(4) | fme(true) }}, will dump a variable json into a text, and then escape it into a valid multiline block.
This filter correctly formats multi-paragraph highlights as a single blockquote in Markdown, preserving line breaks.
Template:
> [!quote]
> {{ text | bq }}
> — [[{{ authorStr}}]] on page {{ location }}Result:
> [!quote]
> This is the first paragraph of the highlight.
>
> And this is the second paragraph.
> — [[Morgan Housel]] on page 42These filters properly render flashcards created with the .qa action tag in Readwise.
Template:
{% if note and note | is_qa %}
**Question:**
{{ note | qa }}
**Original Highlight:**
> {{ text }}
{% else %}
{{ text }}
{% if note %}
> **Note:** {{ note }}
{% endif %}
{% endif %}
---The date filter uses moment.js for robust date formatting.
Template:
Date Highlighted: {{ last_highlight_at | date("MMMM Do, YYYY") }}
Result:
Date Highlighted: February 18th, 2024
The plugin will split the authors from Readwise into an array of individual author names which can then be used in your templates as you wish.
The author field with the following value John Doe, Jane Smith, and Homer Simpson would be split into an array consiting of [ 'John Doe', 'Jane Smith', 'Homer Simpson']. You can then use other nunjucks filters, including join(), to rebuild a string in your template.
For example the following frontmatter and heading template
---
author: [ {{ author | join(', ') }} ]
---
...
Author: [[{{ author | join(']], [[') }}]]
Would render as
---
author: [ 'John Doe', 'Jane Smith', 'Homer Simpson' ]
---
...
Author: [[John Doe]], [[Jane Smith]], [[Homer Simpson]]Note
This will not work for authors that are stored in Readwise in the scientific notation (Last, First). If you end up having such cases stored in your Readwise library, it is best to manually correct them at the source or in Readwise and sync again to Obsidian.
This filter helps standardize author names by removing common honorifics and titles, making them more consistent for linking and organization.
- Removes common academic and courtesy titles like:
- Academic: Dr, Professor, Prof
- Courtesy: Mr, Mrs, Ms, Miss, Mx
- Honorary: Sir, Lord, Lady, Dame
- Cleans up extra whitespace
- Works with both single authors and arrays of authors
{{ author | normalize_author }}{{ "Dr. Jane Doe" | normalize_author }}
→ "Jane Doe"
{{ "Prof. John Smith" | normalize_author }}
→ "John Smith"
{{ ["Mrs. Alice Brown", "Dr. Bob Wilson"] | normalize_author }}
→ ["Alice Brown", "Bob Wilson"]Here is one examples to get you started.
This setup is clean and simple, focusing on basic metadata and clear presentation, using the qa filter to format Readies Q&As.
Frontmatter Template:
title: {{ title }}
tags: [readwise, {{ category }}]
author: "{{ author | join(', ') }}"
source: {{ source_url }}
uri: {{ highlights_url }}Header Template:
# [[{{ title }}]]
*by [[{{ author | join(']], [[') }}]]*
---
# HighlightsHighlight Template:
```nunjucks
{% if note and note | is_qa %}
**Question:**
{{ note | qa }}
**Original Highlight:**
> {{ text }}
{% else %}
{{ text }}
{% if note %}
> **Note:** {{ note }}
{% endif %}
{% endif %}
***---
author: {{ author | normalize_author | join(', ') }}
---
Authors: {% for name in author | normalize_author -%}
[[{{ name }}]]{% if not loop.last %}, {% endif %}
{%- endfor %}The templating is based on the nunjucks templating library and thus shares its limitations.