Chiang Shun Fan134 downloadsUpload local Obsidian media to Cloudflare R2 and rewrite note links automatically.
R2 Media Sync is an Obsidian plugin that automatically uploads local media assets referenced in Markdown notes to Cloudflare R2, rewrites the Markdown links to public R2 URLs, and optionally deletes the local files.
It is designed for workflows where other tools create local image files inside your vault, such as PDF-to-Markdown converters, document importers, AI assistants, or batch import tools.
minAppVersion at v1.12.7+.R2 Media Sync is a standalone Cloudflare R2 media uploader for Obsidian.
It can handle the common image-entry moments directly:
It also handles the next problem: other tools may create image files directly inside your vault and insert local image links into Markdown. Common examples include:
In those cases, paste/drag upload hooks never run. R2 Media Sync watches the resulting Markdown files, uploads the referenced local images to Cloudflare R2, rewrites the links in-place, and can remove the local image files after a successful upload.
In short:
![[image.png]]R2 Media Sync fully supports Obsidian mobile.
Handle local image after upload on mobile. After upload and link rewrite, the original local file can be moved to a review folder or Obsidian trash._r2_media_review) keeps files in a safety staging area. Files there are not deleted automatically; clear them from the dashboard after confirming other devices render the R2 URLs correctly. "Move to Obsidian trash" removes the image from the vault through Obsidian's trash handling.Scan on startup is always disabled at runtime on mobile to ensure fast app startup.Plugins such as EzImage handle pasted or dragged images very well, but some Obsidian workflows create files directly in the vault and write local links into Markdown. For example, a PDF conversion plugin may create files like _page_3_Picture_2.jpeg and insert:

Those files can clutter the vault and consume sync storage. R2 Media Sync cleans up that class of generated assets automatically.
.obsidian, .git, Templates, or attachment folders.R2 Media Sync uses conservative defaults for first-time installs:
After confirming your R2 settings, public URL, and scan scope, you can opt in to startup scans or local deletion from the plugin settings.
data.json file from your vault config folder locally and does not modify it.Before uploading a JPEG image, R2 Media Sync reads local EXIF GPS coordinates when available and stores a small local record in:
.obsidian/plugins/cloudflare-media-sync/image_metadata.json
Each record is keyed by file hash and includes the original vault path, file name, R2 object key, public URL, related Markdown paths, upload time, and optional GPS coordinates.
This helps multi-plugin workflows. For example, after a photo is rewritten to an R2 URL or the local attachment is no longer available on another device, Geo Capture can still look up the saved GPS point and suggest nearby places.
This cache is local to your vault and is intended for recovery and interoperability. It does not upload location data anywhere by itself.
R2 Media Sync scans Markdown files so it can find local media references that were created by PDF converters, importers, AI tools, or other automation.
You can limit this behavior by:
Only included folders instead of Whole vault.AI 工作區 or a specific project folder..obsidian, .git, .trash, Templates, or attachment folders.The plugin only uploads image files that are referenced by Markdown notes and are inside the configured scan scope.
This plugin is not yet published to the Obsidian community plugin registry.
If you use the BRAT plugin:
BRAT: Add a beta plugin for testing.fab34/cloudflare-media-sync
R2 Media Sync in Community plugins.Manual installation:
manifest.jsonmain.jsstyles.css.obsidian/plugins/cloudflare-media-sync/
Settings -> Community plugins.R2 Media Sync.Open Settings -> R2 Media Sync.
Choose one:
Auto: follow your system/browser language when it is Traditional Chinese, otherwise English.EnglishTraditional ChineseChoose one:
Read from EzImage: reuse EzImage's R2 settings.Manual: enter Cloudflare R2 settings directly in this plugin.Manual fields:
Reuse uploads by file hash: avoids uploading identical image content more than once by storing a local hash-to-URL history.Upload retry attempts: retries each R2 upload before the image is recorded in the failed upload log.The Upload selected image files command can insert one of three formats:
[image](https://example.com/image.png)https://example.com/image.pngLocal cleanup is disabled by default.
When enabled, choose one cleanup mode:
Move to Obsidian trash: removes the image from the vault through Obsidian's trash handling.Move to review folder: moves uploaded local files into a vault folder such as _r2_media_review, preserving the original path under that folder so you can inspect before deleting.The review folder is not cleared automatically. Use Clear local review folder from the command palette or dashboard when you are ready to move review-folder files to Obsidian trash.
Default:
{yyyy}/{MM}/{timestamp}-{random}.{ext}
Supported tokens:
{yyyy}{MM}{dd}{hh}{mm}{ss}{timestamp}{random}{name}{ext}Use the whole vault, or limit processing to included folders.
Recommended exclusions:
.obsidian, .git, .trash, Templates
Handle local image after upload disabled.Scan on startup disabled.R2 Media Sync: Upload local images in current note.Handle local image after upload disabled.Scan on startup disabled.EzImage is not required for this workflow. If you also use EzImage, note that EzImage's own local-save behavior may affect whether a local file remains in the vault after upload.
Open the command palette and search for R2 Media Sync.
Upload local images in current noteUpload selected image filesScan configured scope nowImport settings from EzImageShow failed upload summaryClear failed upload logClear local review folderRepair missing local image linksOpen sync dashboardBefore:

![[diagram.png]]
After:


Install dependencies:
npm install
Build:
npm run build
Development watch:
npm run dev
For a manual release, include:
manifest.jsonmain.jsstyles.cssThis repository is structured for eventual submission to the Obsidian community plugin directory.
Before submitting:
manifest.json, for example 0.1.2.manifest.json, main.js, and styles.css to that release.obsidianmd/obsidian-releases.See COMMUNITY_SUBMISSION.md for the suggested entry and checklist.
This plugin intentionally only processes image files that are referenced by Markdown notes. It does not upload unreferenced orphan images, because doing so could remove files that are still being staged or reviewed.
For multi-device setups, the safest pattern is:
MIT — Feel free to use, modify, and distribute. Issues and PRs are welcome.