If the image you pasted inside Amplenote is only a reference to the original location, the Imager plugin will appear in the note options. The plugin fetches attempts to fetch the image and upload it to the Amplenote servers instead.

This is particularly useful if you're pasting images from sources that have unreliable access, such as links that can expire.

Important note for the "Save all note images to Amplenote" Note Option
When using this option to replace all images in a note, the plugin has to rewrite the entire contents of the note, which might result in some inconsistencies or even data loss. Those cases should be rare and you can undo that at any time using the Note Version History. Should you find such a case, please send us an email about it and we will fix it as quickly as we can.

Change log:

August 16th, 2023:

Added note option that saves all images in a note found to be external

imageOption: {
"Save image to Amplenote": {
run: async function(app, image) {
try {
const src = image.src;
const dataURL = await this._dataURLFromImageURL(src);
const sourceNoteHandle = await app.findNote({uuid: app.context.noteUUID});
const fileURL = await app.attachNoteMedia(sourceNoteHandle, dataURL);
await app.context.updateImage({src: fileURL});
await app.alert("Success!");
} catch (err) {
await app.alert(err);
check: async function(app, image) {
const src = image.src;
if (src.startsWith("")) return false;
return true;
noteOption: {
"Save all note images to Amplenote": {
check: async function(app, noteUUID) {
const noteContent = await app.getNoteContent({uuid: noteUUID});
const imageURLs = this._extractImageURLs(noteContent);
if (!imageURLs) return false;
const hasExternalImage = false;
for (const match of imageURLs) {
if (!match.url.startsWith("")) return true;
if (!hasExternalImage) return false;
run: async function(app, noteUUID) {
try {
const noteContent = await app.getNoteContent({uuid: noteUUID});
const sourceNoteHandle = await app.findNote({uuid: noteUUID});
const matches = this._extractImageURLs(noteContent);
const newURLs = [];
for (const match of matches) {
if (match.url.startsWith("")) {
const dataURL = await this._dataURLFromImageURL(`${ match.url }`);
const fileURL = await app.attachNoteMedia(sourceNoteHandle, dataURL);
const newContent = this._replaceMatches(noteContent, matches, newURLs);
await app.replaceNoteContent(sourceNoteHandle, newContent);
} catch (err) {
await app.alert(err);
_replaceMatches(inputString, replacementData, newContent) {
let modifiedString = inputString;
// Replace in reverse order to avoid shifting index issues
for (let i = replacementData.length - 1; i >= 0; i--) {
const data = replacementData[i];
modifiedString = modifiedString.slice(0, data.start) + newContent[i] + modifiedString.slice(data.end);
return modifiedString;
async _dataURLFromImageURL(src) {
const response = await fetch(`${ src }`);
const blob = await response.blob();
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = event => {
reader.onerror = function(event) {
_extractImageURLs(inputString) {
// Regex to match the pattern
const regex = /!\[.*\]\((https:\/\/.*?)\)/g;
const matches = [...inputString.matchAll(regex)];
// Extract the URLs, their start and end indexes, and the entire matched string
const replacementData = => ({
url: match[1],
start: match.index + match[0].length - match[1].length - 1,
end: match.index + match[0].length - 1,
matchedString: match[0]
return replacementData;