Nice Zotero Annoation Links in Obsidian

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.

SCR-20250821-ldyn

<%*
// 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.

SCR-20250821-lbgg




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.

SCR-20250821-lbjz

SCR-20250821-lblm

1 Like