How to backup Google Photos to Google Drive automatically after July 2019 with Apps Script

Updated on Monday, January 13, 2020

Google Photos backup to Google Drive shutting down in July 2019

Google has decided that backing up your photos via Google Drive is 'confusing' and so Drive based backup is going away this month. I love Google Photos but I don't trust it - I pull everything into Drive and then I stick a monthly backup from there onto an external drive in a fire safe. There is a way to get Drive backup working again using Google Apps Script and the Google Photos API. There are a few steps to follow but it's pretty straightforward - you should only need to change two lines in the script to get this working for your account.

First two four caveats to be aware of. Apps Script has a time limit and so it's possible that it could fail if moving a large number of photos. You should get an email if the script ever fails so watch out for that. Secondly and more seriously you could end up with two copies of your photos. If you use Backup and Sync to add photos from Google Drive then these photos will be downloaded from Google Photos by the script and added to Drive again. You need to either upload directly to Google Photos (i.e. from the mobile app or web site) or handle the duplicates in some way. If you run Windows then I have released a command line tool that sorts photos into year+month taken folders and handles de-duplication.

One more limitation. After a comment by 'Logan' below I realized that Apps Script has a 50MB limitation for adding files to Google Drive. The latest version of the script will detect this and send you an email listing any files that could not be copied automatically.

And a fourth limitation after investigating a comment by 'Tim' it turns out there is a bug in the Google Photos API that means it will not download original quality video files. You get some lower resolution version instead. Together with the file size limit this is a bit of a deal breaker for most videos. Photos will be fine, but videos will need a different fix.

On to the script. In Google Drive create a new spreadsheet. This is just a host for the script and makes it easy to authorize it to access Google Photos. Select 'Script editor' from the Tools menu to create a new Apps Script project.

In the script editor select 'Libraries...' from the Resources menu. Enter 1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF next to 'Add a library' and click add. This will find the Google OAuth2 library Pick the most recent version and click Save.

Select 'Project properties' from the File menu and copy the Script ID (a long sequence of letters and numbers). You'll need this when configuring the Google Photos API.

In a new window open the Google API Console, part of the Google Cloud Platform. Create a new project, click Enable APIs and Services and find and enable the Google Photos API. Then go to the Keys section and create an OAuth Client ID. You'll need to add a consent screen, the only field you need to fill out is the product name. Choose Web Application as the application type. When prompted for the authorized redirect URL enter https://script.google.com/macros/d/{SCRIPTID}/usercallback and replace {SCRIPTID} with the Script ID you copied above. Copy the Client ID and Client Secret which will be used in the next step.

Go back to the Apps Script project and paste the code below into the Code.gs window:

Enter the Client ID and Client Secret inside the empty quotes at the top of the file. You also need to add an email address to receive alerts for large files. There is a BackupFolder option at the top as well - the default is 'Google Photos' which will mimic the old behavior. You can change this if you like but make sure that the desired folder exists before running the script. Save the script.

Go back to the spreadsheet you created and reload. After a few seconds you will have a Google Photos Backup menu (to the right of the Help menu). Choose 'Authorize' from this menu. You will be prompted to give the script various permissions which you should grant. After this a sidebar should appear on the spreadsheet (if not choose 'Authorize' from the Google Photos Backup menu again). Click the authorize link from the sidebar to grant access to Google Photos. Once this is done you should be in business - choose Backup Now from the Google Photos Backup menu and any new items from yesterday should be copied to the Google Photos folder in Drive (or the folder you configured above if you changed this).

Finally you should set up a trigger to automate running the script every day. Choose 'Script editor' from the Tools menu to re-open the script, and then in the script window choose 'Current project's triggers' from the Edit menu. This will open yet another window. Click 'Add Trigger' which is cunningly hidden at the bottom right of the window. Under 'Choose which function to run' select 'runBackup'. Then under 'Select event source' select 'Time-driven'. Under 'Select type of time based trigger' select 'Day timer'. Under 'Select time of day' select the time window that works best for you. Click Save. The backup should now run every day.

The way the script is written you'll get a backup of anything added the previous day each time it runs. If there are any duplicate filenames in the backup folder the script will save a new copy of the file with (1) appended in front of the filename. Let me know in the comments if you use this script or have any suggestions to improve it.

Comments

Hurst

Hi, great script - works flawlessly! Thanks a lot!

One improvement idea:

Is it possible to sort photos on drive into year and month folders?

With your script the photos are backed up in the targed folder, but no sorting to year and month....

that would be awesome!

Geetings

Robert Ellison

I have an app that does this which I've used for a while because even the old integration had this problem of sticking everything in one folder. I'll look at tidying this up and releasing it - ideally solving the duplicate problem at the same time. Will probably be a few weeks before I get to this.

Hurst

Perfect - looking forward to it!

Logan

is this only work w/ photos?

I synced video clips and synced files only have 50mb files and cannot play

Cleve

Any way with a script to reverse this process? (ie. automatically copy all pictures in Drive over to photos)

Fabian Briese

Hi, very nice. Thank you. But I have some trouble: When clicking on "Backup Now" I get this error message: "Error: Access not granted or expired."

Any ideas?

Robert Ellison

Logan - UrlFetchApp has a 50MB limit so larger files that that won't work. I'd expect an exception in this case but unfortunately it just downloads a truncated file which isn't good. I'm testing an update that will skip these files and send an email to let you know they need to be downloaded manually, will update once it looks like it's working. I don't see a great work around for this so far but will keep looking.

Robert Ellison

Cleve - should be possible using the APIs. Would need to enumerate files in drive that look like photos or videos and then upload these to Google Photos. I'm not likely to implement this, it might be that a client app is needed to really solve this problem completely.

Robert Ellison

Fabian - there are three types of authorization needed, as outlined in the steps above. Make sure that the API is enabled in Google Cloud Console, that the script is authorized to run and that Google Photos has granted access to the script.

If that doesn't help there is a 'Reset Settings' option in the Google Photos Backup menu that gets added to the spreadsheet that hosts the script. Run that and then go to myaccount.google.com, click Security and then Manage third-party access. Find the Google Photos Backup item and click Remove Access. Once this is done run through authorizing again and see if that clears the problem.

Robert Ellison

Hurst - I just released the app that sorts pictures and videos into date + month folders. This also handles de-duplication. See Photo Sorter 1.00.

Fabian Briese

Hi Robert, thanks for your help. I forgot a point: click on "Authorize. Close this after you have finished." Now its running. :-)

David Katz

Before Google stopped Google Photos and Google Drive sync, this feature created files in Google Drive regardless of the storage space available in the Google Drive account. How does this script handle storage capacity - must there be available space in the Google Drive account?

Robert Ellison

David - yes, you need space in Google Drive. For any new photos you need quota in both services if you want a copy in both places.

John Gillings

Robert,

Thanks, this is very useful! For my purposes, I want a reasonably frequent update, skipping duplicates instead of making a copy. I adjusted the endDate to

"day": date.getDate() + 1

to include files from today, and the body of the copy loop to

var response = UrlFetchApp.fetch(downloadList[i].baseUrl, {

headers: {

Authorization: 'Bearer ' + photos.getAccessToken()

}

});

var files = folder.getFilesByName(filename);

if (!files.hasNext()) {

var blob = response.getBlob();

blob.setName(filename);

folder.createFile(blob);

}

so duplicates are ignored. My trigger is hourly, which is often enough for what I need. It's almost back to previous behaviour, just a bit lagged.

(I log photos in entries in a Google Calendar work diary - they need to be in Drive to see them from the "Add Attachment" dialog when editing a calendar entry).

Robert Ellison

Logan - I just updated the script to email you if it encounters files larger than 50MB. Not perfect but at least you'll know that there are files you need to download manually.

Google - UrlFetchApp should really exception in this case.

John Gillings

Not really knowing much about Google script, my adjusted date calculations seemed to work, until we rolled over into the new month. Having read some documentation about how dates work, I've changed the start and end dates to this. Hopefully clearer and will survive month (and year?) rollovers? :

var MILLIS_PER_MINUTE = 60000;

var MILLIS_PER_HOUR = MILLIS_PER_MINUTE * 60;

var MILLIS_PER_DAY = MILLIS_PER_HOUR * 24;

var now = new Date();

var from = new Date(now.getTime() - MILLIS_PER_DAY)

var request = {

"pageSize":"100",

"filters": {

"dateFilter": {

"ranges": [

{

"startDate": {

"year": from.getFullYear(),

"month": from.getMonth() + 1,

"day": from.getDate()

},

"endDate": {

"year": now.getFullYear(),

"month": now.getMonth() + 1,

"day": now.getDate()

}

}

]

}

}

Tim L

Thanks, Robert for this blog posting.

I created the above script with John Gillings' modification but I am still getting duplicates showing up.

Do I need to remove something to stop the duplicates being created?

Robert Ellison

Tim - unfortunately yes. There are a couple of ways of handling this. If your photo sources are mobile and a camera you can just add them differently. Mobile photos are added to Google Photos from your phone, allow the script to copy these over to your backup archive and you shouldn't get duplicates. For the camera upload directly to Google Photos and don't copy to your backup location. The script will move these over to drive and again you shouldn't have duplicates.

The other way - which is what I do - is to detect and remove duplicates locally. I allow all my photos to collect in the Google Photos folder in Google Drive and then periodically copy them to the Windows Photos folder with a tool that sorts them into month + year subfolders and skips any duplicates. I released this tool for Windows recently, it's called Photo Sorter. I don't have anything equivalent for Mac or Linux.

Tim L

Thanks for the reply. All my photos are from my mobile and I have auto-backup to Google Photos switched on.

I cannot make use of Windows as for security reasons, the link between a PC and Google drive is switched off. It's not possible to determine if someone's computer is encrypted like it is with a mobile.

The additional comment said they modified the script to ignore duplicates, which is what I was trying to do. This has to be reasonably straight forward or I'll spend more time deleting photos than the script spends keeping the stuff in sync.

Robert Ellison

Tim - I haven't tried or tested John's modifications. Can you go back to the original script and see if you get any duplicates?

Robert Ellison

Tim - One more thing. I had an email exchange with John and he suggests checking that you modified both the date code an the section that creates the file in drive. I'll add the full snippet below. This prevents duplicate filenames on the upload to drive.

John's full code

Steven W Buehler

the 'rclone' command line utility (for Linux, Mac, Windows) now supports Google Photos and organizes everything into folders by year, month, or day.

Tim

I noticed that one of the videos that was uploaded today, using the script, was only 4MB as opposed to 23MB it should be. I then downloaded the video from Google photos and manually uploaded it as a separate file and it was showing as 23MB in Google Drive.

This suggests the original full-size videos and photos are not being uploaded to Google Drive using the script. Is this a limitation of the API?

Cheers and Happy Christmas and New Year.

Robert Ellison

Hi Tim, the limitation I'm aware of is 50MB for adding files to drive. Did you set up an email address so the script can email you if it runs into this limit? Not sure why a 23MB file would fail this way. I've seen a reference to a daily upload limit, it might be possible that this was hit if a lot of files were uploaded on the same day.

Tim

It's not the 50MB limit I'm hitting in all cases but the fact that Google only allows high quality videos and photos to be uploaded using the Google Photos API, rather than the uploading from original quality videos and photos. I'd wanted the original quality videos and photos to be uploaded.

It may not bother all people, depending on what they are doing with the photos and videos that are uploaded.

However this limitation, along with the one that strips the location information, as ruined the whole work flow that I'd spent some time putting together - originally when the Google Drive syncing was automatic.

Rory

Thank you for this - I got it all up and running script is going and syncing however on first look it doesn't seem to sync anything new than July 23rd - any ideas what could cause this?

Rory

Spoke to soon - working like a charm!

Thanks again Robert.

Robert Ellison

Tim - I've done some more research and I think the problem you had was due to a bug in the API - issue 80149160 - which means that the dv parameter to download a video will not return the original resolution version. This is a pain. You could comment on the issue tracker in the hope that it encourages Google to fix it, I've just done this. It's been open for a while so I wouldn't hold out much hope. It looks like this is specific to videos and shouldn't impact photo downloads.

Location information is stripped out of photos by the download API and I don't see any way to override this behavior.

Rory

I got this all up and running well but it seems that my OATH has expired - I set it to 30 days so unsure why I would be getting these errors?

Start Function Error Message Trigger End

1/8/20 5:30 AM runBackup Error: Access not granted or expired. (line 454, file "Service", project "OAuth2") time-based 1/8/20 5:30 AM

Robert Ellison

Rory - go to your Google Account, Security and then Manage third party access. Find the script and revoke access. Then from the host spreadsheet run the Reset Settings option from the Google Photos Backup menu. Finally authorize the app again. Hopefully this should clear whatever has gone wrong.

Tim

There is one way to deal with the location issue and that is for Google to modify the download API to not strip out the location information.

I'm not aware of it being stripped out when had a direct link between Google Photos and Google Drive.

I shall comment on the bug trackers and hold out no hope.

Add Comment

All comments are moderated. Your email address is used to display a Gravatar and optionally for notification of new comments and to sign up for the newsletter.

I Thought He Came With You is Robert Ellison's blog.

Newsletter

Related

Google Fit Daily Step Export