Adding images
Three paths into a doc: paste from clipboard, drop onto the editor, or insert from URL via the slash menu. Plus the formats, the size cap, and the client-side optimization pipeline.
There are three ways to add an image to the doc you’re editing. They behave a little differently — picking the right one saves time and clicks.
The three paths
Trip notes line.
Trip notes line.
Trip notes line. /image
| Method | Inserts where | Source | Triggers upload |
|---|---|---|---|
| Paste from clipboard (⌘V) into the editor | At the cursor | OS clipboard | Yes |
| Drag-and-drop a file onto the editor body | At the drop coordinates | Your file system | Yes |
| Slash menu → Image | At the cursor | A URL you paste in a prompt | No (URL used as-is) |
Paste vs. drop, plus an important distinction
- Paste / drop INSIDE the editor → image is uploaded and inserted into the current doc, at the cursor (paste) or drop coordinates (drop).
- Drop a file OUTSIDE the editor (anywhere on the rest of the app: sidebar, top bar, blank space) → sweetdocs creates a new document from that file. This is how Word, PDF, and other importable formats get into your workspace. See Importing overview.
The “drop inside the editor” behavior is image-only. Non-image files dropped inside the editor fall through to the page-level drop overlay and become a new document.
Supported formats
Image upload accepts:
- PNG, JPEG, WebP, GIF, AVIF — uploaded directly
- HEIC / HEIF (iPhone photos) — automatically transcoded to JPEG in the browser before upload, because most non-Safari browsers can’t display HEIC
The detection looks at both MIME type and file extension, so iPhone photos that drop into Safari (which may report an empty MIME) still get picked up.
Size limit
The default cap is 10 MB per image. Anything larger surfaces a toast with the actual limit and skips that file — the rest of the batch keeps uploading.
This is the post-optimization check (see below), so a 15 MB photo that optimizes down to 6 MB will still go through fine. It’s the source-file gate.
What happens on upload
Every uploaded image runs through a small client-side pipeline before it leaves the browser:
- HEIC → JPEG transcoding when needed (Safari natively displays HEIC, but most other browsers don’t)
- EXIF strip so location and camera metadata don’t leak with the photo
- Resize if the longest edge exceeds 2048 px (uniform aspect-ratio scale)
- AVIF re-encode attempt when the browser supports canvas AVIF encoding — kept only if it’s smaller than the source (typical savings: 30-50% versus JPEG/PNG at perceptually identical quality)
- The smallest valid candidate gets uploaded to the API
The optimized file is sent as a multipart POST /api/images/upload request with your auth token. The server returns a stable URL on our R2 storage; that URL becomes the image’s src.
Trip photo from this morning:
Caption: bamboo grove just before sunrise.
What gets saved in the Markdown
A plain image node:

When you resize or align it (see Image layout), the alt + URL stay the same — the width and alignment ride along as HTML attributes on the rendered <img>.
The R2 URL is stable: it won’t change for the life of the image, and we won’t garbage-collect images that live inside a saved document. If you export the doc and host the Markdown elsewhere, the image keeps loading.
Status while uploading
- A toast appears for each file:
Uploading photo.png… - On success: image inserts inline, toast clears
- On failure: a red toast surfaces the error message (file too large, quota hit, network error, etc.)
- Each image in a multi-file paste / drop uploads in series — failures don’t stop the queue
Quota errors
Two quotas guard image uploads, and they produce two distinct messages:
| Type | Trigger | Message you’ll see |
|---|---|---|
| Storage cap | Total stored images on your plan are at the limit | ”You’re out of image storage on the free plan. Pro gives you 5 GB.” |
| Monthly upload cap | You’ve uploaded more images this month than your plan allows | ”Image upload quota reached for this month. Pro raises the cap.” |
Both are HTTP 429s under the hood, with the kind discriminating between storage and monthly. See Plans for the per-plan numbers.
What the slash menu’s Image item does instead
The slash menu → Image path is different: it opens a small native browser prompt for a URL. Whatever URL you paste becomes the image’s src directly — there’s no upload, no optimization, no storage. If the URL goes dark later (the host removes it, the CDN expires, etc.), the image breaks.
Use the slash menu for embedding an already-hosted image. Use paste or drag for everything else.
What’s not supported
| Missing | Notes |
|---|---|
| Captions | A caption / figcaption isn’t part of v1 — keep the description as alt text |
| Auto-OCR / image-to-text | Not in v1 |
| Inline SVG / vector editing | SVG via the Image layout editor is for SVG paste / edit, not raster |
| Direct camera capture in-app | The OS file picker covers this on mobile |