Zotero annotations can be copied as a link to Obsidian, allowing you to have a clickable reference that opens the annotation directly within Zotero. However, the default link format is distracting while reading, so I wrote a Templater script that I use to make my Zotero annotations visually more appealing in Obsidian.
<%*
// This script converts Zotero linked annotations into a more visually appealing format. Simply copy an annotation in Zotero, run this Templater script, and paste the Zotero annotation link using Cmd + Shift + V on Mac or Ctrl + Shift + V on Windows.
// Linked Zotero annotations in Obsidian will change in the reading view from '“Annotation Text.” (Mustermann, 2025, p. 333) (pdf)' to 'Annotation Text. Z'.
// This function expects input in the format: “Annotation Text.” ([Mustermann, 2025, p. 333](zotero://select/library/items/UBJZP9TQ)) ([pdf](zotero://open-pdf/library/items/ICKGKCNH?page=1&annotation=IREYF7KJ)).
function transformString(inputStr) {
const textPattern = /“(.*?)”/s;
const itemPattern = /\(\[.*?\]\(zotero:\/\/select\/library\/items\/.*?\)\)/;
const pdfPattern = /\(\[pdf\]\(zotero:\/\/open-pdf\/library\/items\/.*?\)\)/;
const textMatch = inputStr.match(textPattern);
const itemMatch = inputStr.match(itemPattern);
const pdfMatch = inputStr.match(pdfPattern);
// Input validation for the correct format.
if (!textMatch || !itemMatch || !pdfMatch) {
return null;
}
let annotationText = textMatch[1];
let itemLink = itemMatch[0];
let pdfLink = pdfMatch[0];
// Converts the link format to: Annotation Text. %%([Mustermann, 2025, p. 333](zotero://select/library/items/UBJZP9TQ))%%[Z](zotero://open-pdf/library/items/ICKGKCNH?page=1&annotation=IREYF7KJ).
pdfLink = pdfLink.slice(1, -1).replace("[pdf]", "[Z]");
return `${annotationText} %%${itemLink}%%${pdfLink}`;
}
let outputStr = null;
// 1. Looping until a valid input string is provided or the prompt is cancelled.
while (!outputStr) {
let inputStr = await tp.system.prompt("Paste Zotero annotation here:");
// The user can cancel the prompt by Esc or closing the prompt.
if (inputStr === null) {
console.log("User cancelled the prompt.");
break;
}
// If the input is empty, display a warning and prompt again.
if (!inputStr.trim()) {
window.alert("⚠️ \n No input provided.\n \n Please paste the annotation or close the prompt.");
continue;
}
outputStr = transformString(inputStr);
// If the input format is incorrect, display a warning and prompt again.
if (!outputStr) {
window.alert("⚠️ \n Input did not match expected Zotero annotation format.\n \n Remember to copy a linked annotation (Cmd + Shift + V on Mac or Ctrl + Shift + V on Windows). \n \n Please try again or close the prompt.");
}
}
if (outputStr) {
tR += outputStr;
}
-%>
How to use
If you insert the template into a note (I use a shortcut for it), copy your Zotero annotation and paste it as a link (Windows: Ctrl + Shift + V, macOS: Cmd + Shift + V, ) into the input field and press Enter. This will insert the reference at the current cursor position in your Obsidian note.
You will receive a warning if no input is provided or if the input string is in the wrong format, and you can enter an input again.