CLI tool
ArnaudCrl/immich-automated-selfie-timelapse avatar
ArnaudCrl/immich-automated-selfie-timelapse

immich-automated-selfie-timelapse: turning an Immich face index into a portrait timelapse

Automated face extraction, resizing and alignment suitable to make a selfie timelapse video.

796 stars21 forksRustMIT

At a glance

What is it?
A Rust service that reads Immich face metadata, crops and aligns portraits through a configurable filter pipeline, and renders an MP4 with FFmpeg. The filters are heuristics, so expect to hand-prune frames before the final compile.
Who is it for?
Adopt this if you already run Immich with face recognition enabled and want a portrait timelapse without exporting and editing photos by hand. Skip it if you need a general-purpose video pipeline, if you cannot grant an Immich API key the seven scopes listed in the README, or if you expect the filters to work without manual review.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 69 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The gap this fills between Immich face data and an actual video

Immich already does the hard part: it detects faces and groups them by person. What it does not do is turn that grouping into a sequence of uniform frames. A photo library spanning years has portraits shot at different distances, angles, and exposures, and dropping those straight into a slideshow produces a jittering mess. This project sits between the two: it queries Immich for the photos tied to one person, extracts the face crop from each, normalizes the framing, discards frames that fail quality checks, and hands the survivors to FFmpeg. The README frames the goal as generating "timelapse videos of your loved ones' portraits from your Immich photo library," and the audience is narrow by design. If you self-host Immich, have face recognition running, and want a birthday or anniversary video of one person growing up, this is aimed at you. If you want a general photo-to-video tool, it is not. The dependency on Immich's face index is structural, not incidental.

How the pipeline moves from Immich metadata to MP4

The flow starts with an Immich API key. The service uses the face and person endpoints to resolve a person to a set of assets, then downloads those assets. Each image passes through a chain of stages. Face cropping uses the bounding box Immich already stored, so no separate detector runs for that step. Alignment then uses eye positions to rotate and shift the crop so the eyes land in a consistent place across frames, which is what keeps the timelapse from swimming. After that comes the filter stack: head pose filtering through an ONNX model the README names as DMHead, blink rejection via Eye Aspect Ratio, blur rejection via gradient magnitude with a Sobel operator, brightness bounds, and a minimum face resolution. A separate photo-limiting control caps how many images are taken per day, week, or month so that a heavy photo period does not dominate the video. Surviving frames can optionally get a date overlay, and FFmpeg compiles the sequence to MP4. The output directory holds both the processed stills and the video, which matters because it means you can re-run the compile step without redoing extraction.

Deployment: two environment variables and two volumes

The recommended path is Docker Compose. The image is arnaudcayrol/immich-selfie-timelapse, and the README's compose file runs it as user 1000:1000, publishes port 5000, and mounts ./config to /app/config and ./output to /app/output. Only two environment variables are required: IMMICH_API_KEY and IMMICH_BASE_URL, the latter pointing at your Immich instance on its API port, shown as http://your-immich-host:2283 in the example. A plain docker run invocation is also given with the same flags. The README advises storing the key in a .env file next to the compose file rather than in plain text, which is sensible given that the key can download your entire library for the selected person. Permissions are the most likely first-run failure: the README explicitly says to ensure read/write access and gives chown -R 1000:1000 ./config ./output. The container writes config.toml into /app/config, so that directory is not optional. Once it is up, the web UI on port 5000 handles configuration and progress monitoring, and the README notes the app is "one shot" in nature, meaning you can run it on a faster machine and shut it down afterward rather than keeping it resident.

API scopes and the permissions you are actually granting

The README lists seven scopes the key needs: album.read, asset.download, asset.read, asset.view, face.read, person.read, and server.about. Read that list as a description of the tool's reach. asset.download lets the container pull original image files, not thumbnails, which is why face crops can be rendered at usable resolution and why the output directory can grow quickly. face.read and person.read are what tie the run to Immich's recognition results, so the quality of your timelapse is bounded by how well Immich has grouped that person's faces. If your library has a person split across two identities, or a child's early photos merged with a sibling, the extraction step will inherit that error and no filter downstream will fix it. There is no scope here for writing back to Immich, so the tool is read-only against your server, which limits the blast radius of a misconfiguration to disk usage and API load rather than data loss.

The filters are heuristics, and the README says so

This is the part to take seriously before committing. The README states plainly that "the photo filtering is not 100% accurate and will continue to improve," and the author's own advice is to open the gallery view, go through the images, delete the bad ones, and then hit "Compile video" again. That is not a footnote; it is the intended workflow. Every filter in the stack is a threshold: an EAR cutoff, a Sobel gradient cutoff, brightness bounds, a minimum face size, and a head-pose score from DMHead. Thresholds that are strict enough to remove a blurry frame will also remove a sharp frame taken in dim light, and thresholds loose enough to keep everything let through the closed eyes and the profile shots. The README acknowledges this by noting the defaults are "quite permissive because every human being is unique" and asking you to tune brightness and eye aspect ratio for the specific person. So the realistic cost of a run is not just compute time; it is a manual review pass over the extracted frames. If you were hoping for a fully unattended pipeline, this is the wrong tool, and the project's own documentation is the source of that judgement.

Where it fits against a scripted ffmpeg or ImageMagick pipeline

The obvious alternative is to skip this project and write your own export-and-crop script: pull the person's assets from Immich via the API, crop to the stored face bounding box, resize, and feed the sequence to ffmpeg. That approach gives you total control and no extra container. The difference is everything after the crop. A hand-rolled script gets you a slideshow of faces at inconsistent scale and rotation; this project adds eye-based alignment, which is the single step that makes a timelapse look stable rather than jittery, plus the pose, blink, blur, and brightness gates and the per-day photo cap. Those are the components you would otherwise have to source and tune yourself, including an ONNX runtime for the DMHead model. The trade-off runs the other way too: a custom script can be adapted to any source, while this tool is bound to Immich's person and face endpoints and to the seven scopes above. If your photos live anywhere other than an Immich server with face recognition on, the alternative is not really an alternative; it is the only option.

Maintenance, releases, and what MIT means here

The project is MIT licensed, which permits commercial use, modification, and redistribution provided the copyright notice and permission notice are retained. That is a permissive grant, and nothing in the repository suggests additional restrictions, but the licence text itself is the authority and this is not legal advice. On maintenance, the author is candid in the README: issues are welcome and will be handled at his own pace, while pull requests carry no guaranteed review timeline. The release history shows a steady cadence rather than a stalled one, with v2.2.1 in March 2026 and v2.3.0 in July 2026, and the repository is not archived. The practical upgrade cost is low because the container is stateless apart from config.toml and the output directory. Pulling a new image and restarting is the whole procedure, and since the processed stills persist in /app/output, you can recompile the video after an upgrade without re-downloading assets from Immich. The risk to weigh is the dependency surface: Immich's API, the DMHead model, and FFmpeg all live inside the image, so a breaking Immich API change would require a new release rather than a config tweak on your side.

Editorial conclusion

Adopt this if you already run Immich with face recognition enabled and want a portrait timelapse without exporting and editing photos by hand. Skip it if you need a general-purpose video pipeline, if you cannot grant an Immich API key the seven scopes listed in the README, or if you expect the filters to work without manual review. Before deploying, verify that your Immich face data actually covers the person you care about, confirm the DMHead ONNX model and FFmpeg are present in the image you pull, and check write access on the two mounted directories with chown -R 1000:1000 ./config ./output.

Official sources

  1. ArnaudCrl/immich-automated-selfie-timelapse on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Community notes

Community notes