SmugMug CLI
A fast, reliable command-line tool for uploading photos to SmugMug with intelligent deduplication and automatic album organization.
Features
- Simple Upload: Upload individual files or entire directories
- Smart Deduplication: Hash-based detection prevents re-uploading the same photo
- Album Organization: Automatically create and organize albums based on folder structure
- Multi-threaded: Concurrent uploads for maximum speed
- Docker Support: Easy deployment as a container
- Local Cache: Fast lookups of previously uploaded files
Installation
From Source
Docker
Pre-built multi-architecture images are available from GitHub Container Registry:
# Pull the latest image
# Or pull a specific version
# Run with your user's UID/GID to avoid permission issues
# Or use specific UID/GID (defaults to 99:100)
Build locally:
Docker Compose
See docker-compose.yml for a complete example. Basic usage:
services:
upload:
image: ghcr.io/jhofker/smugmug-cli:latest
command: upload /photos --album "My Photos"
environment:
- PUID=99 # Defaults to 99:100 if not specified
- PGID=100
- SMUGMUG_API_KEY=${SMUGMUG_API_KEY}
- SMUGMUG_API_SECRET=${SMUGMUG_API_SECRET}
- SMUGMUG_ACCESS_TOKEN=${SMUGMUG_ACCESS_TOKEN}
- SMUGMUG_ACCESS_TOKEN_SECRET=${SMUGMUG_ACCESS_TOKEN_SECRET}
volumes:
- ~/.config/smugmug-cli:/home/smugmug/.config/smugmug-cli
- ~/.cache/smugmug-cli:/home/smugmug/.cache/smugmug-cli
- /path/to/photos:/photos:ro
To build locally instead, replace image: with build: .
Quick Start
Getting Your Credentials
- Go to https://api.smugmug.com/api/developer/apply
- Create an application to get your API Key and API Secret
- Go to SmugMug Account Settings → Privacy → Authorized Services
- Click "token" next to your application to get your Access Token and Access Token Secret
Method 1: Using Environment Variables (Recommended for Development)
# Copy the example file
# Edit .env with your credentials
SMUGMUG_API_KEY=your_api_key_here
SMUGMUG_API_SECRET=your_api_secret_here
SMUGMUG_ACCESS_TOKEN=your_access_token_here
SMUGMUG_ACCESS_TOKEN_SECRET=your_access_token_secret_here
# Test authentication
# Upload photos
Method 2: Using Config File (Recommended for Production)
# Interactive setup
# Test authentication
# Upload photos
Configuration is stored in ~/.config/smugmug-cli/config.toml
Upload with Options
Configuration
The tool supports two configuration methods (environment variables take precedence):
Environment Variables
SMUGMUG_API_KEY=...
SMUGMUG_API_SECRET=...
SMUGMUG_ACCESS_TOKEN=...
SMUGMUG_ACCESS_TOKEN_SECRET=...
Config File (~/.config/smugmug-cli/config.toml)
[]
= "your_api_key"
= "your_api_secret"
= "your_access_token"
= "your_access_token_secret"
[]
= 4
= 3
# Folder for monthly albums when `upload` gets no --album (created private)
= "Uploads"
# RAW files: "auto" (originals with SmugMug Source, otherwise rendered JPEGs),
# "render", "original" or "skip"
= "auto"
[]
= true
Commands
Setup & Authentication
smugmug-cli init- Initialize configuration and authenticate with SmugMug (interactive setup)smugmug-cli auth- Sign in through your browser to get (or refresh) an access tokensmugmug-cli test-auth- Test that your credentials are working
Upload
smugmug-cli upload <PATH>- Upload photos from the specified path--threads <N>- Number of concurrent upload threads (default: 4)--album <NAME>- Album name (creates if doesn't exist, private by default)--parent <PATH>- Parent folder path (e.g., "2024/Travel")--structure- Recreate the directory structure as SmugMug folders and albums--interactive- Ask whether to upload to one album or keep the folder structure--dry-run- Preview what would be uploaded without uploading (creates no folders or albums)--check-remote- Check SmugMug for existing files by MD5 hash (slower but more reliable)--no-cache- Disable local cache (always check files, even if previously uploaded)--raw <MODE>- How to handle RAW files (auto,render,original,skip), overridingraw_modein the config
Where files go: with no --album, files go to an album named for the current month
(e.g. 2026-09) inside the default_folder from your config (Uploads unless changed), or
inside --parent if given. The default folder and all auto-created albums are private; use
albums settings to change privacy after creation.
Album size limit: SmugMug allows 5,000 photos and videos per album. When an upload would go
past that, it continues in Name (2), Name (3), and so on, filling any partly-used album in
the series first. Albums are only created when a file actually needs uploading, so skipped
duplicates never create empty albums, and a re-run skips files already in any album of the
series. This applies to --album too. (--structure uploads aren't split.)
RAW files: RAW originals can only be uploaded with a SmugMug Source subscription (detected
by init/auth). Without one, each RAW file is uploaded as a JPEG instead: the full-size
preview the camera embedded in it, under the same name with a .jpg extension
(IMG_1234.CR2 → IMG_1234.jpg), with the RAW's EXIF (capture date, camera, lens, exposure,
GPS, orientation) copied in. Things to know:
- It's the camera's own rendering (picture style, white balance), not a fresh RAW
conversion, so edits made in Lightroom, darktable and the like (including
.xmpsidecars) aren't included. - A RAW with a JPEG or HEIC of the same name next to it (shooting RAW+JPEG) is skipped, so the camera's JPEG is kept rather than replaced.
- When a RAW file has no preview of at least 1600 px on the long edge (common for DNGs made by Adobe DNG Converter with its default medium-size preview), the RAW data itself is converted instead, with rawler. That takes a few seconds and several hundred MB of memory per file (one at a time), and looks flatter than the camera's rendering. Files it can't decode fail and are listed as failed.
- A re-run skips a RAW whose
.jpgis already in the album, without comparing contents.
Set raw_mode in the config (or pass --raw) to change this: render always uploads JPEGs,
original uploads RAW originals (skipped without Source), skip leaves RAW files out.
Albums
smugmug-cli albums list- List all albumssmugmug-cli albums create <NAME>- Create a new album (private by default)--privacy <LEVEL>- Set privacy level (private, unlisted, public) - defaults to private
smugmug-cli albums delete <ALBUM>- Delete an album--force- Force deletion without confirmation
smugmug-cli albums download <ALBUM> [OPTIONS]- Download all images from an album--output <DIR>- Output directory (default: current directory)--threads <N>- Number of concurrent download threads (default: 4)
smugmug-cli albums tree- Show folder/album tree structuresmugmug-cli albums settings <ALBUM> [OPTIONS]- Update album settings--privacy <LEVEL>- Set privacy (public, unlisted, private)--description <TEXT>- Set description--keywords <KEYWORDS>- Set keywords (semicolon-separated)--sort-method <METHOD>- Set sort method (Position, Caption, FileName, DateTimeOriginal, DateTimeUploaded)--sort-direction <DIR>- Set sort direction (asc, desc)
smugmug-cli albums get-download-link <ALBUM>- Get album download link (ZIP file)--wait- Wait for download generation (polls until ready)
Images
smugmug-cli images list <ALBUM>- List images in an albumsmugmug-cli images info <ALBUM> <IMAGE_KEY>- Show detailed information about an imagesmugmug-cli images delete <ALBUM> <IMAGE_KEY>- Delete an image--force- Force deletion without confirmation
smugmug-cli images update <ALBUM> <IMAGE_KEY> [OPTIONS]- Update image metadata--caption <TEXT>- Set image caption--title <TEXT>- Set image title--keywords <KEYWORDS>- Set keywords (semicolon-separated)--latitude <LAT>- Set latitude--longitude <LON>- Set longitude
smugmug-cli images move <SOURCE_ALBUM> <IMAGE_KEY> <TARGET_ALBUM>- Move image to a different album--force- Force move without confirmation
Comments
smugmug-cli comments list <ALBUM> <IMAGE_KEY>- List comments on an imagesmugmug-cli comments create <ALBUM> <IMAGE_KEY> [OPTIONS]- Create a new comment on an image--text <TEXT>- Comment text (required)--name <NAME>- Commenter name--email <EMAIL>- Commenter email--rating <0-5>- Rating (0-5)
Cache
smugmug-cli status- Show cache statistics and upload historysmugmug-cli cache clear- Clear the local deduplication cache
Development
See DESIGN.md for architecture details and development roadmap.
Building
Running Tests
SmugMug API Setup
- Go to https://api.smugmug.com/api/developer/apply
- Create a new application
- Note your API Key and API Secret
- Use these during
smugmug-cli init
License
MIT. Release binaries also include rawler, which is LGPL-2.1 licensed; see THIRD-PARTY-NOTICES.md.