Using icloudpd to sync iCloud Photos to a Raspberry Pi Photo Frame

The digital photo frame project I’ve been working on is mostly about one thing: I want to be able to see all the photos I’ve taken over the years. In my last post, I wrote about getting the hardware and display working for my digital photo frame. The next step was figuring out how to get my iCloud photos onto the device.

All of my photos live in iCloud. It’s a great way to make sure they’re backed up and available across my iPhone, iPad, Mac, and Apple Watch.

For the most part though, it means I’m not really seeing many of those photos. I think that for most people, iCloud Photos is the digital equivalent of putting your old photos in boxes in the attic. With over 18,000 items in iCloud, I have a lot of shoeboxes.

Why I Needed to Download from iCloud

PicFrame, the photo frame display software I’m using, will display any photo you throw at it, but those photos have to be local to the device (in my case, a Raspberry Pi).

One of the best resources I found was TheDigitalPhotoFrame.com, which has great tutorials on building your own smart digital photo frame. It has great articles about copying photos from cloud storage to your device, but there was nothing about iCloud. It covered Google Photos and Dropbox, for example, but not Apple’s ecosystem.

So, with a little help from ChatGPT, I researched what was possible.

Finding the Right Tool: icloudpd

I quickly landed on using icloudpd (short for iCloud Photos Downloader). It’s a simple but powerful command-line tool for downloading photos from iCloud to any local folder.

You can find it on GitHub here.

In my setup, I download all my photos from iCloud to the Raspberry Pi’s local storage. I’m using a 128GB SD card for that purpose. With about 18,000 photos (roughly 58GB total), I still have plenty of room left on that 128GB SD card.

To install icloudpd I used pip:

pip install icloudpd

Authenticating with Your Apple Account

Since iCloud is an Apple service, you need to authenticate with your Apple Account before accessing any photos. That’s true whether you’re using iCloud.com or a third-party tool like icloudpd.

The first step is to sign in and get a valid session token. Use the icloudpd command with –auth-only to authenticate:

icloudpd --username my@email.address --password my_password --auth-only

Once you are signed in, you’ll have a valid session token that lasts for a while (I think that is about 2 months), allowing you to start downloading.

Re-Authenticating every couple of months

Every Apple Account is required to have multi-factor authentication set up in order to sign in. There are some very very old accounts that do not have this requirement but not many of those are left. That session token we created above expires after 2 months or so. When that happens you must sign in again in order to refresh the token.

icloudpd does have some stuff that helps with that. e.g. They can trigger an email when the token expires so you go sign in again. You can also store the password in the keyring but I’m not comfortable with that. They also offer a Web UI which you can use to enter the password but I have not tried that either.

Email notifications from icloudpd will require some configuring of smtp parameters. The following are the parameters to look at for that:

  • –smtp-username X, –smtp-password X, –smtp-host X, –smtp-port X, –smtp-no-tls
    • Settings for SMTP notifications for expired/needed authentication
  • –notification-email X, –notification-email-from X
    • Settings for email notification addressing
  • –notification-script X
    • Script to be executed for notifications on expired MFA

Another option is to enable the icloudpd web ui. This enables an internal web server on port 8080 which accepts input for the password and MFA code.

--mfa-provider webui

Downloading Your Photos

Once the authentication token is in place, the next step is to start downloading your photos. The most basic form of that is to just tell icloudpd where to place your photos as they are downloaded.

icloudpd --directory /data --username my@email.address

icloudpd supports many parameters for customizing how photos are downloaded, organized, and stored. Full documentation is available here.

Have a look at my personal script below for the list of parameters that I use for my photo frame.

Filtering Downloads: Albums & Date Range

In my case, I plan to just download all my photos. It does take a few hours and a bunch of space on the SD card but I’m ok with that.

I know that some folks will want to download only some of their photos. icloudpd enables this with the ability to limit retrieval to specific libraries or albums using –album x or –library x. They also have the ability to restrict to certain time periods using –skip-created-before and –skip-created-after,

To get a list of all available albums on iCloud use the following command:

icloudpd --list-albums --username <your Apple ID>

Then use a command, like the following, to download the album you want to see in Picframe:

icloudpd —album <album name> --username <your Apple ID>

Mac Alternative: Use Photos Takeout Instead

Using a command-line tool like icloudpd is an admittedly nerdy way to bring iCloud photos down to your picture frame. For folks that are less tech savvy or just prefer to have a more user-friendly UI to use, there may be other ways to accomplish the same thing. For example, on the Mac, I recently came across Photos Takeout while leafing through the latest issue of MacLife. I have not tried it but it looks like a slick way to grab photos out of iCloud and bring them down to your Mac.

That could be useful for backing up iCloud photos locally, for example. Or it could be used to pull photos out of iCloud and post them directly to your Raspberry Pi to use on your digital picture frame. The easiest way to do that is to connect to your Raspberry Pi over the network. If you set up your Raspberry Pi appropriately then the Samba file sharing service should be available to you for that. With Samba set up, you should be able to connect to the Raspberry Pi directly from Finder in the Network section. That would allow you to download directly from iCloud on your Mac and place them in the Pictures folder on the Raspberry Pi.

Photos Takeout is available from the Mac App Store here.

The Photos Takeout website has tons more info here.

My Scripts

Until I’m fully confident everything’s working as expected, I manually trigger downloads. icloudpd does support scheduled syncs and even deleting local files that were removed from iCloud, but I’m taking a more cautious approach for now.

Script 1: Authenticate and Refresh Session

#!/bin/bash
EXPECTED_VENV_PATH="/home/pi/venv_picframe"
if [[ -z "$VIRTUAL_ENV" ]]; then
    echo "Error: No virtual environment is activated."
    exit 1
elif [[ "$VIRTUAL_ENV" != "$EXPECTED_VENV_PATH" ]]; then
    echo "Error: Wrong virtual environment activated."
    echo "Expected: $EXPECTED_VENV_PATH"
    echo "Actual: $VIRTUAL_ENV"
    exit 1
else
    echo "Correct virtual environment is activated: $VIRTUAL_ENV"
fi
echo "And now running icloudpd --auth-only --username ben@buzztonic.com"
icloudpd --auth-only --username ben@buzztonic.com

This script ensures your authentication token is valid before you begin any downloads.

Script 2: Download Photos from iCloud

#!/bin/bash
set -euo pipefail
EXPECTED_VENV_PATH="$HOME/venv_picframe"
if [[ -z "${VIRTUAL_ENV:-}" ]]; then
    echo "Error: No virtual environment is activated."
    exit 1
elif [[ "$VIRTUAL_ENV" != "$EXPECTED_VENV_PATH" ]]; then
    echo "Error: Wrong virtual environment activated."
    echo "Expected: $EXPECTED_VENV_PATH"
    echo "Actual: $VIRTUAL_ENV"
    exit 1
else
    echo "Correct virtual environment is activated: $VIRTUAL_ENV"
fi
cmd=(icloudpd)
args=(
  --username "myemailaddress@example.com"
  --directory "$HOME/Pictures"
  --folder-structure '{:%Y/%m}'
  --file-match-policy name-id7
  --size adjusted
  --skip-videos
  --skip-live-photos
# --only-print-filenames  # Uncomment for dry run
)
printf 'Running: %q' "${cmd[@]}"; printf ' %q' "${args[@]}"; echo
exec "${cmd[@]}" "${args[@]}"

Explaining the icloudpd Parameters I Use

Below I’ve tried to explain each of the parameters I use in my download script:

--username
Your Apple Account email.
--directory "$HOME/Pictures"
Destination folder. PicFrame uses Pictures by default, so I kept that.
--folder-structure '{:%Y/%m}'
Creates subfolders by year and month for easier navigation.
--file-match-policy name-id7
Ensures no filename collisions by adding a unique asset ID suffix (for example, IMG_1234_QAZXSW.JPG).
--size adjusted
Downloads the edited version if it exists, otherwise the original.
--skip-videos
PicFrame doesn’t support video playback, so this keeps things clean and fast.
--skip-live-photos
Avoids downloading the video portion of Live Photos.
--only-print-filenames
Useful for dry runs when testing configuration changes. I uncomment when I’m testing and then comment it with a “#” to start the actual downloading

Wrapping Up

This setup lets me pull my entire iCloud photo library down to the Raspberry Pi automatically, ready for PicFrame to display.

It’s been satisfying to see so many forgotten photos appear again. I’m seeing so many of those moments I hadn’t thought about in years.

If you’re trying something similar or run into snags getting iCloud downloads working, drop me a line using the Contact form.

Was this article helpful?


Thank you for your support and motivation.


Scroll to Top