Immich Integration

Immich Integration for the Photo Widget

1. Context & Objective

Gladys will soon have a Photo Widget for the dashboard (box.type = 'photo') that displays
a slideshow from a manually entered list of URLs ({ url, caption }). The images are
retrieved via a server proxy (GET /api/v1/dashboard/photo/proxy?url=) to remain
accessible remotely (Gladys Plus).

Objective: Allow the user to automatically populate this slideshow from an Immich server
(self-hosted photo manager).

The user connects their Immich once, then selects a dynamic source (an album,
or their memories “on this day”); the widget displays the corresponding photos and
refreshes itself.

Scope v1

  • Sources: Album of choice + Memories “on this day”
  • Image quality: preview (~1440px)
  • Architecture: full Immich service (config page + authenticated proxy)

2. The Immich API — What It Enables

2.1 Authentication

  • All requests include the header x-api-key: <key>.
  • The key is generated in Immich: Account Settings → API Keys. Minimum required
    permissions: album.read, asset.read, memory.read.
  • Base URL = Immich server address, e.g., http://192.168.1.20:2283. All paths
    below are prefixed by /api.

Key point: The current Gladys proxy (dashboard.getPhoto.js) makes a GET without
headers → it cannot talk to Immich. Therefore, a dedicated Immich proxy is needed that
injects x-api-key and points to the configured base URL.

2.2 Choosing Which Photos to Display (Sources)

Source Endpoint Useful Response
List of albums GET /api/albums [{ id, albumName, assetCount, albumThumbnailAssetId, shared }] — used to populate the album selector
Contents of an album GET /api/albums/{id} { albumName, assets: [{ id, type, originalFileName, fileCreatedAt, exifInfo }] }
Memories “on this day” GET /api/memories [{ id, type:"on_this_day", memoryAt, data:{ year }, assets:[{ id, ... }] }] — a group per year on the same date

2.3 Retrieving the Image File of an Asset

Each photo is identified by a UUID asset.id. Three renditions:

Variant Endpoint Usage
Preview (~1440px) :white_check_mark: v1 GET /api/assets/{id}/thumbnail?size=preview Good quality/size trade-off for a slideshow
Thumbnail GET /api/assets/{id}/thumbnail?size=thumbnail Small thumbnail (timeline)
Original GET /api/assets/{id}/original Max quality, potentially large files (>5 MB)

Response = binary image/*. The Immich proxy converts it to the format already expected by
the widget: "<contentType>;base64,<data>".

2.4 Asset Fields Usable for Captions

originalFileName, fileCreatedAt / localDateTime, and exifInfo (description, city,
dateTimeOriginal). Allows auto-generating a caption (e.g., “Rome — August 12, 2019”).

3. Expected Functional Behavior

3.1 Connecting the Integration (Once)

  • New Immich card in the list of integrations.
  • Config page asking for Server URL + API Key.
  • “Test Connection” button → calls GET /api/albums to validate URL + key, and
    returns a clear error if failed (unreachable URL, 401 invalid key).

3.2 Widget Configuration (By the User, When Editing the Dashboard)

The Photo Widget gains a choice of source mode:

  1. Manual URLs — current behavior, unchanged (full backward compatibility).
  2. Immich — Album — a dropdown lists the albums (via GET /api/albums);
    the user selects one.
  3. Immich — Memories — displays photos returned by GET /api/memories
    (“X years ago, on this day”).

Existing options are preserved and applicable to all modes: framing (cover/contain),
slideshow interval, showing/hiding captions, widget title.

For Immich modes, the caption can be auto-generated from the asset metadata (date + location) instead of manually entered.

3.3 Display (Runtime)

  • On opening, the widget resolves the Immich source to a list of assets (album or memories),
    then displays each image in preview via the authenticated Immich proxy.
  • Slideshow: automatic scrolling according to the interval, forward/backward navigation and
    indicators (already present in PhotoBox.jsx).
  • Image cache in memory + preloading of the next image (already present), reused as is.
  • Refreshing the list: The list of assets (especially “memories,” which changes
    every day) is periodically re-queried / when the widget is mounted, to be decided.

3.4 Edge Cases & Functional Decisions to Validate

  • Empty album / empty memories for the day → explicit empty state (message), no error.
  • Videos in an album (asset.type = VIDEO) → filtered (only IMAGE kept) or
    display their poster? → To be decided (proposal: ignore videos in v1).
  • Large albums → limit the number of loaded assets (e.g., ceiling + possible random order)
    to avoid thousands of entries? → To be decided.
  • Display order: chronological (by fileCreatedAt), reverse, or random?
    To be decided (proposal: most recent first).
  • 5 MB proxy limit: preview remains well below the limit, so kept. Only to be reviewed if
    we add the “original” or video mode later.

4. API Sources (Reference)

  • Immich API Doc: API | Immich · endpoints: Immich - API Documentation
  • Albums: getAllAlbums, getAlbumInfo · Memories: searchMemories (GET /api/memories)
  • Image: viewAsset / GET /api/assets/{id}/thumbnail?size=preview
  • Random (ref.): POST /api/search/random · Metadata: POST /api/search/metadata

5. Open Questions Before Implementation

  1. Videos in albums: ignore or display a poster? (proposal: ignore in v1)
  2. Display order: reverse chronological, chronological, or random?
  3. Limit on the number of photos per source (performance)?
  4. Caption: auto-generated (date + location) by default, or no caption for Immich?

Model Ideas

I just ran Manus on it. We’ll see if it yields any conclusive results!

First version made by Manus 1.6.

I won’t have the opportunity to test today, but if someone is eager to try, a test image is available on the GitHub repository.

From the integrations page, click the « Install from GitHub » button and paste the link:

https://github.com/gboulvin/Gladys-Immich

I was able to test the connection and it’s OK, but when adding a device, I get this error:

The integration published an incomplete or invalid device: Gladys refused to register it.

Technical details:

HTTP 422 — <!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="robots" content="nofollow,noarchive,noindex">
  <title data-l10n>Unprocessable Entity</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
  <!--  -->
  <meta name="title" content="422: Unprocessable Entity">
  <meta name="description" content="">
  <meta property="og:title" content="422: Unprocessable Entity">
  <meta property="og:description" content="">
  <meta property="og:locale" content="en_US">
  <meta property="twitter:title" content="422: Unprocessable Entity">
  <meta property="twitter:description" content="">
  <meta name="format-detection" content="telephone=no">
  <style>
    :root {
      --color-bg-primary: #ffffff;
      --color-text-primary: #000000;
      --color-text-emphasis: #333333;
      --color-text-heading: #444444;
      --color-text-secondary: #555555;
      --color-text-subtle: #888888;
      --color-illust-ink: #263238;
 …

The second iteration (0.1.2) is ready and tested on my end.

  1. Create an API key in your Immich server
  2. Fill in the fields in the Immich external integration
  3. Save, test the connection and refresh the slideshow
  4. In the « discovery » tab, save the device (change its name if desired). You can choose the room in the « Devices » tab
  5. You need to add an… « Immich camera » in the desired dashboard and you’re good to go!

I’m publishing to the store, go for your feedback!

Edit:

I’ll test again but I think I’ll get a better result if I add the camera to the dashboard before refreshing the slideshow. It seems that if you refresh first, the photo is too large, whereas in the opposite direction, it is reduced.

Edit 2: No, it’s just that the image is very large if it’s in portrait mode…

I get an error when I enter the UUID of an album:

[2026-08-13T22:03:12.795Z] [ERROR] [immich-slideshow] Failed to publish the next Immich slide EmptyPhotoSourceError: No images are available in “MonAlbum”.
    at ImmichSlideshow.next (file:///app/src/slideshow.js:118:13)
    at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
    at async publishNextSlide (file:///app/src/devices/slideshowCamera.js:61:17)
    at async publish (file:///app/src/devices/slideshowCamera.js:118:9) {
  code: 'EMPTY_SOURCE'
}

Yet I do have images in this album

When I set the source to « Souvenirs - Ce jour là » it works correctly :slight_smile:

Another small issue, there is no cover on the integration

And if possible in the improvements, add the ability to add multiple albums - 1 album per device would be cool I think :grinning_face:

I also got this error:

[2026-08-13T22:09:51.808Z] [ERROR] [immich-slideshow] Failed to publish the next Immich slide Error: publishCameraImage: maximum image size is 153600 bytes (150 KB)
    at GladysIntegration.publishCameraImage (/app/node_modules/@gladysassistant/integration-sdk/lib/gladys-integration.js:606:13)
    at publishNextSlide (file:///app/src/devices/slideshowCamera.js:63:16)
    at async publish (file:///app/src/devices/slideshowCamera.js:118:9)
[2026-08-13T22:10:51.644Z] [INFO] [immich-slideshow] Published “20250812_123806_1800.jpeg” from Memories — on this day

Hi!

Thanks for your feedback!

Yes, I know but I don’t understand why. When I run in developer mode, I have it but not in the release. I have the same problem with the other integrations developed or in development…

For the rest, I’ll look into it today :wink:

Voilà, update available.

It is now possible to list the UUIDs of the 50 most recent albums, more practical! To do this, a new action is available at the bottom of the configuration page.

Attention, it is now necessary to check the asset.read in the API key permissions in Immich.

I’ll look into it tonight :wink:

And for the cover, maybe it will work next time, I have high hopes :smiley:

The bug is well fixed :wink:
Thanks @GBoulvin
And thanks in advance for the rest :grinning_face:

And there we go! New version!

  • Ability to select multiple albums
  • Ability to display a caption
  • Finally a cover image (but uh… I might well change it in a future release as it’s not very readable) Edit: And on top of that, it’s not a video slideshow. In short…

That sounds interesting, but since I don’t have an Immich server, could someone share an easy tutorial to set up this server?

With Docker: Docker Compose [Recommended] | Immich
And you will find the other installation types.
I followed Installer Immich sur un NAS Synology (Guide complet 2026) - Cachem but you need a Synology.

I followed the Immich documentation.

Basically, you need to choose a folder where the photos will be stored and run the docker command (I don’t remember exactly, but first you need to download a file, edit it, and then run the command).

Edit: @mutmut was faster :smiley: It’s installed on my Beelink S13

Thanks for this version @GBoulvin

Actually, I was thinking more about the possibility of having multiple devices here in order to play an album on one device and another album on another device:

My request may not be relevant, so it’s probably up for debate :wink:

Ahhh, I see!

I’ll ask Manus tomorrow :innocent:

Thanks for this nice integration :clap:
I think it would be more interesting in the long run for the Photos widget to take this additional photo source into account (rather than reusing Camera).

What do you think? In that case, I can make a feature request in the core Gladys + SDK :thinking:

It would be Gladys who poll Immich and not a generation of snapshots, I imagine that would also be better in terms of resources…

Indeed, I’ll leave that to you, I don’t feel up to it!

It’s done!

Personally, I’m not convinced because there’s just the possibility to configure a second server linked to a second slideshow, but it works as requested :wink:

Here you go Widget Photo - sources issues d'intégrations (Immich)