gPhotos2Immich

gPhotos2Immich

Docker app from Nackophilz's Repository

Overview

gPhotos2Immich syncs Google Photos shared albums to Immich on a schedule, without any Google API key: it reads public shared-album links, downloads full-quality photos and videos with their taken dates and skips items already uploaded. The web UI shows live logs and has a Sync Now button; a sync can also be triggered with POST /api/sync (e.g. from Home Assistant). First launch: create config.json (see Requires), open the WebUI, enter the Immich API URL (e.g. http://192.168.1.10:2283/api) and an Immich API key with the asset.read, asset.upload, album.create, album.read, album.update, albumAsset.create and user.read permissions (or All), then add your shared album links. Changes apply without a restart. Only public shared links work: check that the album opens in a private browser window. The web UI has no password: never expose its port to the internet.

gPhotos2Immich

Docker Downloads Docker Daily Downloads

Sync photos from Google Photos shared albums to your Immich instance- automatically, on a schedule.


Quick Start

  1. Run with Docker Compose:

    # compose.yml
    services:
      gphotos2immich:
        image: ghcr.io/warreth/gphotos2immich:latest
        container_name: gphotos2immich
        network_mode: "host" # Fixes DNS resolution and natively exposes port 8080 for the Web UI
        restart: unless-stopped
        environment:
          - PORT=8080 # Port for the Web UI
          - DISABLE_WEBUI=false # Set to true to fully disable the Web UI
          # - IMMICH_API_KEY=your-key # Overrides config.json when set (e.g. for key rotation)
          # - IMMICH_API_URL=http://immich-server:2283/api # Overrides config.json when set
        volumes:
          - ./config.json:/app/config.json # Optional, will be created by Web UI if omitted
          - ./data:/app/data # Persistent dedup cache (survives container restarts)
    
    docker compose up -d
    
  2. Open http://localhost:8080 in your browser to configure your Immich API details and Google Photos shared album links via the Web UI! The app will automatically hot-reload when you save changes.

Docker image tags

The image is published to ghcr.io/warreth/gphotos2immich with these tags:

Tag Description
latest Newest stable release. Pre-releases never get this tag.
beta Newest pre-release (e.g. v1.7.0-beta1). Updated on every pre-release.
vX.Y.Z Exact release version, e.g. v1.7.0.
sha-<hash> Build pinned to a specific commit.

To test a pre-release, use ghcr.io/warreth/gphotos2immich:beta in your compose file. Stable users should stay on latest or a pinned vX.Y.Z tag.


Permissions Note: The container runs as an unprivileged user (app, UID 1000).

  • Default behavior: If you run the container without specifying a user:, it will automatically fix permissions on mounted files at startup and drop to the app user.
  • Explicit user: If you specify user: "1000:1000" in your compose file, ensure the mounted config.json and data/ on the host are writable by UID 1000 (chown 1000:1000 config.json data).

[!IMPORTANT] The built-in Web configuration UI is not password-protected. Do NOT expose the port to the public internet or untrusted networks!

Heads Up! If you prefer not to use a Web UI, you can fully disable it by setting DISABLE_WEBUI=true and configuring via config.json. See the Configuration Document for details on formatting and settings.


API Key Permissions

To sync photos, generate an Immich API key with the following permissions (or just select "All"): asset.read · asset.upload · album.create · album.read · album.update · albumAsset.create · user.read


Frequently Asked Questions

Can this sync albums I don't own, or private albums? Only public shared album links work. The tool scrapes shared-album URLs without any Google authentication by design, so an album must be viewable by anyone with the link (test it in an incognito window). Private albums and links that require signing in return 404 and cannot be supported without full Google account authentication, which is out of scope.

Why do I get duplicates in Immich when I already have the same photos? Google Photos serves re-encoded (compressed) copies for shared albums, so their checksums differ from your originals and Immich's content-hash duplicate detection cannot match them. Nothing can be fixed on this tool's side; use Immich's built-in duplicate review after syncing to clean them up.

Features

  • No Google API Keys: We scrape directly from shared album URLs, so there's no complex Google Cloud setup required!
  • Web UI & Hot Reloading: Manage your albums from a sleek web interface on port 8080. Check live logs, trigger an instant sync with "Sync Now", and tweak settings; everything applies instantly without restarting the container.
  • Trigger Sync API: Trigger a sync on demand outside the regular schedule via POST /api/sync or GET /sync_now (ideal for Home Assistant buttons, webhooks, or automation scripts). See home-assistant.yaml for a ready-to-use Home Assistant configuration.
  • Smart Syncing: We pull down the full images and videos (no compressed thumbnails), extract the correct "taken" dates, and smoothly avoid Google's rate limits.
  • Speed & Deduping: Concurrent workers speed through downloads, while a persistent local cache skips over photos that Immich already has, saving you bandwidth.

Development

# Run directly
go run main.go

# Run with Docker (build from source)
sudo docker compose up --build --remove-orphans

# Run tests (offline; integration tests are skipped)
go test ./...

# Run tests including live integration tests against the real test album
GP2IMMICH_INTEGRATION=1 go test ./... -timeout 15m

Requirements

config.json is mounted as a single file and must exist before the first start, otherwise Docker creates a folder in its place. From the Unraid terminal:

mkdir -p /mnt/user/appdata/gphotos2immich
echo '{}' > /mnt/user/appdata/gphotos2immich/config.json

Related apps

Explore more like this

Explore all

Details

Repository
ghcr.io/warreth/gphotos2immich:latest
Last Updated2026-10-23
First Seen2026-10-23

Runtime arguments

Web UI
http://[IP]:[PORT:8080]/
Network
bridge
Shell
sh
Privileged
false

Template configuration

WebUI PortPorttcp

WebUI port (must match PORT)

Target
8080
Default
8080
Value
8080
Config filePathrw

Settings file written by the WebUI (create it first, see Requires)

Target
/app/config.json
Default
/mnt/user/appdata/gphotos2immich/config.json
Value
/mnt/user/appdata/gphotos2immich/config.json
DataPathrw

Sync state used to skip items already uploaded

Target
/app/data
Default
/mnt/user/appdata/gphotos2immich/data
Value
/mnt/user/appdata/gphotos2immich/data
TZVariable

Timezone

Default
Europe/Paris
Value
Europe/Paris
PORTVariable

Internal listen port (must match WebUI Port container port)

Default
8080
Value
8080
DISABLE_WEBUIVariable

true turns the WebUI off (config.json must then be written by hand)

Default
false
Value
false