Upload media

Required authentication scope

Uploading media items to a user’s library or album requires either the .appendonly or the .photoslibrary scope.

Media items can also be created using the .sharing scope. To create items with the .sharing scope, you must first create an album and mark it as shared using shareAlbum. You can then create media items that are shared with the user in the album. You can't create items directly in the user's library or in albums that your app hasn't shared.

When listing albums, the isWriteable property indicates whether your application has access to create media in a particular album.

The upload process

Uploading media items is a two-step process:

  1. Upload the raw bytes to a Google Server. This doesn't result in any media items being created in the user’s Google Photos account. Instead, it returns an upload token which identifies the uploaded bytes.
  2. Use the upload token to create the media item in the user’s Google Photos account. You can choose whether the media should be also added to a specific album. For more information, see Create albums.

Uploading bytes

Bytes are uploaded to Google using upload requests. If the upload request is successful, an upload token which is in the form of a raw text string, is returned. To create media items, use these tokens in the batchCreate call.

REST

Include the following fields in the POST request header:

Header fields
Content-type Set to application/octet-stream.
X-Goog-Upload-File-Name Recommended. Set to the filename along with the file extension. Only the filename is shown to the user in Google Photos.
X-Goog-Upload-Protocol Set to raw.

Here is a POST request header:

POST https://photoslibrary.googleapis.com/v1/uploads
Authorization: Bearer OAUTH2_TOKEN
Content-type: application/octet-stream
X-Goog-Upload-File-Name: FILENAME
X-Goog-Upload-Protocol: raw

In the request body, include the binary of the file:

MEDIA_BINARY_DATA

If this POST request is successful, an upload token which is in the form of a raw text string, is returned as the response body. To create media items, use these text strings in the batchCreate call.

UPLOAD_TOKEN

Java

try {
  // Create a new upload request
  // Specify the filename that will be shown to the user in Google Photos
  // and the path to the file that will be uploaded
  UploadMediaItemRequest uploadRequest =
      UploadMediaItemRequest.newBuilder()
          //filename of the media item along with the file extension
          .setFileName(mediaFileName)
          .setDataFile(new RandomAccessFile(pathToFile, "r"))
          .build();
  // Upload and capture the response
  UploadMediaItemResponse uploadResponse = photosLibraryClient.uploadMediaItem(uploadRequest);
  if (uploadResponse.getError().isPresent()) {
    // If the upload results in an error, handle it
    Error error = uploadResponse.getError().get();
  } else {
    // If the upload is successful, get the uploadToken
    String uploadToken = uploadResponse.getUploadToken().get();
    // Use this upload token to create a media item
  }
} catch (ApiException e) {
  // Handle error
} catch (FileNotFoundException e) {
  // Local file could not be found for upload
}

PHP

// Create a new upload request

// Specify the filename that will be shown to the user in Google Photos
// and the path to the file that will be uploaded

// When specifying a filename, include the file extension
try {
    $uploadToken = $photosLibraryClient->upload(file_get_contents($localFilePath), $filename);
} catch (\GuzzleHttp\Exception\GuzzleException $e) {
    // Handle error
}

The suggested file size for images is less than 50 MB. Files above 50 MB are prone to performance issues.

The Google Photos Library API supports resumable uploads. A resumable upload allows you to split a media file into multiple sections and upload one section at a time.

Creating a media item

After uploading media items to Google, you can create media items in Google Photos using upload tokens. An upload token is valid for one day after being created. A media item is always added to the user's library. Optionally, it can also be added to an album if your app has been granted permission.

Media items can be created only within the albums created by your app. For more information, see Authentication and authorization scopes.

To create new media items, call mediaItems.batchCreate by specifying a list of newMediaItems. Each newMediaItem contains an optional media description that is shown to the user. This description field is restricted to 1000 characters. It also contains an upload token that's specified inside a simpleMediaItem.

You can create a single media item or multiple media items in a user’s library by specifying the descriptions and corresponding upload tokens:

REST

Here is the POST request header:

POST https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate
Content-type: application/json
Authorization: Bearer OAUTH2_TOKEN

The request body should specify a list of newMediaItems.

{
  "newMediaItems": [
    {
      "description": "ITEM_DESCRIPTION",
      "simpleMediaItem": {
        "uploadToken": "UPLOAD_TOKEN"
      }
    }
   , ...
  ]
}

Java

try {
  // Create a NewMediaItem with the uploadToken obtained from the previous upload request, and a description
  NewMediaItem newMediaItem = NewMediaItemFactory
      .createNewMediaItem(uploadToken, itemDescription);
  List<NewMediaItem> newItems = Arrays.asList(newMediaItem);

  BatchCreateMediaItemsResponse response = photosLibraryClient.batchCreateMediaItems(newItems);
  for (NewMediaItemResult itemsResponse : response.getNewMediaItemResultsList()) {
    Status status = itemsResponse.getStatus();
    if (status.getCode() == Code.OK_VALUE) {
      // The item is successfully created in the user's library
      MediaItem createdItem = itemsResponse.getMediaItem();
    } else {
      // The item could not be created. Check the status and try again
    }
  }
} catch (ApiException e) {
  // Handle error
}

PHP

try {
    $newMediaItems = [];
    $newMediaItems[0] = array(
        PhotosLibraryResourceFactory::newMediaItemWithDescription($uploadToken, $itemDescription));

    $response = $photosLibraryClient->batchCreateMediaItems($newMediaItems);
    foreach ($response->getNewMediaItemResults() as $itemResult) {
        $status = $itemResult->getStatus();
        if ($status->getCode() != Code::OK) {
            // Error when item is being created
        }
    }
} catch (\Google\ApiCore\ApiException $e) {
    // Handle error
}


You can add media items to the library and to an album by specifying the album id. For more information, see Create albums.

REST

{
  "albumId": "ALBUM_ID",
  "newMediaItems": [
    {
      "description": "ITEM_DESCRIPTION",
      "simpleMediaItem": {
        "uploadToken": "UPLOAD_TOKEN"
      }
    }
   , ...
  ]
}

Java

try {
  // Create new media items in a specific album
  BatchCreateMediaItemsResponse response = photosLibraryClient
      .batchCreateMediaItems(albumId, newItems);
  // Check the response
} catch (ApiException e) {
  // Handle error
}

PHP

try {
    $response = $photosLibraryClient->batchCreateMediaItems($newMediaItems, ['albumId' => $albumId]);
} catch (\Google\ApiCore\ApiException $e) {
    // Handle error
}

You can also specify albumId and albumPosition to insert media items at a specific location in the album.

REST

{
  "albumId": "ALBUM_ID",
  "newMediaItems": [
    {
      "description": "ITEM_DESCRIPTION",
      "simpleMediaItem": {
        "uploadToken": "UPLOAD_TOKEN"
      }
    }
    , ...
  ],
  "albumPosition": {
    "position": "AFTER_MEDIA_ITEM",
    "relativeMediaItemId": "MEDIA_ITEM_ID"
  }
}

Java

try {
  // Create new media items in a specific album, positioned after a media item
  AlbumPosition positionInAlbum = AlbumPositionFactory.createFirstInAlbum();
  BatchCreateMediaItemsResponse response = photosLibraryClient
      .batchCreateMediaItems(albumId, newItems, positionInAlbum);
  // Check the response
} catch (ApiException e) {
  // Handle error
}

PHP

try {
    $albumPosition = PhotosLibraryResourceFactory::albumPositionAfterMediaItem($mediaItemId);
    $response = $photosLibraryClient->batchCreateMediaItems($newMediaItems,
        ['albumId' => $albumId, 'albumPosition' => $albumPosition]);
} catch (\Google\ApiCore\ApiException $e) {
    // Handle error
}

For more details regarding positioning in albums, see Add enrichments.

Item creation response

The mediaItems.batchCreate call returns the result for each of the media items you tried to create. The list of newMediaItemResults indicates the status and includes the uploadToken for the request. A non-zero status code indicates an error.

REST

{
  "newMediaItemResults": [
    {
      "uploadToken": "UPLOAD_TOKEN",
      "status": {
        "message": "OK"
      },
      "mediaItem": {
        "id": "MEDIA_ITEM_ID",
        "productUrl": "https://photos.google.com/photo/PHOTO_PATH",
        "description": "ITEM_DESCRIPTION",
        "baseUrl": "BASE_URL-DO_NOT_USE_DIRECTLY",
        "mediaMetadata": {
          "width": "MEDIA_WIDTH_IN_PX",
          "height": "MEDIA_HEIGHT_IN_PX",
          "creationTime": "CREATION_TIME",
          "photo": {}
        },
      }
    },
    {
      "uploadToken": "UPLOAD_TOKEN",
      "status": {
        "code": 13,
        "message": "Internal error"
      }
    }
  ]
}

Java

BatchCreateMediaItemsResponse response = photosLibraryClient.batchCreateMediaItems(newItems);

// The response contains a list of NewMediaItemResults
for (NewMediaItemResult result : response.getNewMediaItemResultsList()) {
  // Each result item is identified by its uploadToken
  String uploadToken = result.getUploadToken();
  Status status = result.getStatus();

  if (status.getCode() == Code.OK_VALUE) {
    // If the request is successful, a MediaItem is returned
    MediaItem mediaItem = result.getMediaItem();
    String id = mediaItem.getId();
    String productUrl = mediaItem.getProductUrl();
    // ...
  }
}

PHP

// The response from a call to batchCreateMediaItems returns a list of NewMediaItemResults
foreach ($response->getNewMediaItemResults() as $itemResult) {
    // Each result item is identified by its uploadToken
    $itemUploadToken = $itemResult->getUploadToken();
    // Verify the status of each entry to ensure that the item has been uploaded correctly
    $itemStatus = $itemResult->getStatus();
    if ($itemStatus->getCode() != Code::OK) {
        // Error when item is being created
    } else {
        // Media item is successfully created
        // Get the MediaItem object from the response
        $mediaItem = $itemResult->getMediaItem();
        // It contains details such as the Id of the item, productUrl
        $id = $mediaItem->getId();
        $productUrl = $mediaItem->getProductUrl();
        // ...
    }
}

If an item is successfully added, a mediaItem is returned that contains its mediaItemId, productUrl and mediaMetadata. For more information, see Access media items.

If the media item is a video, it must be processed first. The mediaItem contains a status inside its mediaMetadata that describes the processing state of the video file. A newly uploaded file returns the PROCESSING status first, before it is READY for use. For details, see Access media items.

If you encounter an error during this call, follow the Best practices and retry your request with the uploadToken. You may want to keep track of successful additions, so the image can be inserted into the album at the correct position during the next request. For more information, see Create albums.

Results are always returned in the same order in which upload tokens were submitted.