Skip to content

API and CLI

Everything the Frameleaf web app and apps do goes through the server’s API, and you can use it too. This page covers API keys, the Frameleaf command line tool for bulk uploads, calling the API from your own scripts, and the admin commands built into the server.

Scripts and the CLI sign in with an API key rather than your password. Each key belongs to your account and only reaches what you can.

  1. Select Settings in the sidebar, then open Access & security.
  2. Under API keys, select Create API key.
  3. Give the key a name and choose the permissions it needs. Pick only what the tool needs, or full access.
  4. Create the key and copy it. It’s shown only once.

Keep API keys private, like passwords. Delete a key from the same list when you no longer need it.

The Frameleaf CLI uploads photos and videos from a computer to your server, which is handy for big folders and archives. It can:

  • upload files and folders, skipping anything already on the server
  • create albums from folder names, or put everything into one album
  • watch a folder and upload new files as they appear
  • show the server’s version
  • move a person’s whole library to another server, with frameleaf migrate. See Move to a new server

The easiest way is the CLI’s Docker image. Run it from the folder you want to upload; the folder is mounted read-only at /import:

Terminal window
docker run -it -v "$(pwd)":/import:ro \
-e FRAMELEAF_INSTANCE_URL=https://photos.example.com/api \
-e FRAMELEAF_API_KEY=your-api-key \
ghcr.io/frameleaf/frameleaf-cli:latest upload --recursive .

Anything after the image name is passed to the frameleaf command. You can keep the key in a Docker env file instead of typing it.

You can also build the CLI from the Frameleaf source code, which needs Node.js and pnpm:

Terminal window
pnpm install
pnpm --filter @immich/sdk build
pnpm --filter @immich/cli build
node packages/cli/dist/index.js --help

The packages keep their original names; the command they build is frameleaf.

Terminal window
frameleaf login https://photos.example.com/api YOUR-API-KEY

Use your server’s address followed by /api. Your details are saved in auth.yml in ~/.config/frameleaf/. Keep that file safe, or run frameleaf logout when you’re done. An existing ~/.config/immich/ folder is still used as long as ~/.config/frameleaf/ doesn’t exist. Change the folder with -d or FRAMELEAF_CONFIG_DIR.

Instead of signing in, you can pass --url and --key, or set FRAMELEAF_INSTANCE_URL and FRAMELEAF_API_KEY.

Terminal window
# a few files
frameleaf upload file1.jpg file2.jpg
# a folder and everything in it
frameleaf upload --recursive directory/
# see what would happen first
frameleaf upload --dry-run --recursive directory/
# one album per folder
frameleaf upload --album --recursive directory/
# everything into one album
frameleaf upload --album-name "Summer holiday" --recursive directory/
# skip any folder named Raw
frameleaf upload --ignore "**/Raw/**" --recursive directory/
# straight into the archive
frameleaf upload --visibility archive --recursive directory/

By default the CLI works out each file’s checksum before uploading, so it doesn’t send files the server already has. The server always checks for duplicates itself too, so --skip-hash only trades a little safety for speed on a fast connection. Hidden files and folders are skipped unless you add --include-hidden. Exclusion patterns work like an external library’s.

Option What it does Environment variable
-r, --recursive Include subfolders FRAMELEAF_RECURSIVE
-i, --ignore <pattern> Skip paths matching a pattern FRAMELEAF_IGNORE_PATHS
--skip-hash Don’t work out checksums before uploading FRAMELEAF_SKIP_HASH
-H, --include-hidden Include hidden folders FRAMELEAF_INCLUDE_HIDDEN
-a, --album Create albums from folder names FRAMELEAF_AUTO_CREATE_ALBUM
-A, --album-name <name> Add everything to this album FRAMELEAF_ALBUM_NAME
--visibility <visibility> archive, timeline, hidden or locked FRAMELEAF_VISIBILITY
-n, --dry-run Show what would happen without uploading FRAMELEAF_DRY_RUN
-c, --concurrency <number> Files uploaded at once. Defaults to one less than your CPU cores FRAMELEAF_UPLOAD_CONCURRENCY
-j, --json-output Print details as JSON FRAMELEAF_JSON_OUTPUT
--delete Delete local files after uploading them FRAMELEAF_DELETE_ASSETS
--delete-duplicates Delete local files that are already on the server FRAMELEAF_DELETE_DUPLICATES
--no-progress Hide progress bars FRAMELEAF_PROGRESS_BAR
--watch Keep watching and upload new files automatically FRAMELEAF_WATCH_CHANGES

--json-output prints three lists: newFiles, duplicates and newAssets. Some log lines come first, so strip them before parsing:

Terminal window
frameleaf upload --dry-run --json-output . | tail -n +6 | jq .newFiles[]

Other commands are frameleaf server-info, frameleaf logout and frameleaf help.

Each FRAMELEAF_ variable the CLI reads also accepts its older IMMICH_ name, such as IMMICH_INSTANCE_URL or IMMICH_API_KEY, so existing scripts keep working. If both names are set to different values, the CLI refuses to start and names the pair. The immich command name also still works. Old names keep working for the current major version and stop in the next major release.

The API lives at your server’s address followed by /api, and is described with the OpenAPI standard. Send your key in the x-api-key header.

This Python example uploads one file:

#!/usr/bin/python3
import os
from datetime import datetime
import requests
API_KEY = 'YOUR_API_KEY' # replace with a valid API key
BASE_URL = 'http://127.0.0.1:2283/api' # replace as needed
def upload(file):
stats = os.stat(file)
headers = {
'Accept': 'application/json',
'x-api-key': API_KEY,
}
data = {
'fileCreatedAt': datetime.fromtimestamp(stats.st_mtime),
'fileModifiedAt': datetime.fromtimestamp(stats.st_mtime),
'isFavorite': 'false',
}
with open(file, 'rb') as f:
response = requests.post(f'{BASE_URL}/assets', headers=headers, data=data, files={'assetData': f})
print(response.json())
# {'id': 'ef96f635-61c7-4639-9e60-61a11c4bbfba', 'duplicate': False}
upload('./test.jpg')

Administrators can also manage server credentials from scripts; see System settings.

The server image includes frameleaf-admin for tasks you can’t do from the web app, such as resetting the administrator password, turning sign-in methods or maintenance mode on and off, printing a new server’s setup code and listing users. Run it from your Compose folder:

Terminal window
docker compose exec immich-server frameleaf-admin help

See Server commands for every command, with examples.