Posted by:

David G

David G, Chief Explorer

All third-party Street View tools are built around the Google Street View Publish API. Here’s a closer look at how it works for uploading long sequences.

Google offers a coupld of ways to do this using the Google Street View Publish API’s

Photo upload

The photo resource can be used to upload single images.

Those of you who like to take things apart woll enjoy a previous post of mine introducing exactly how the Street View API and photo resource works.

This works well for individual photos, or for smaller sequences. However it starts to cause issues for tours of 30+ images. There are a few reasons for this:

Video upload

The photoSequence resource allows you to upload video files to be turned into mapped photos.

Officially this is still in alpha phase (you will need to request access), but there are some good examples of how it’s used in the wild, [including these examples on GitHub];

The script in the Samples for Street View Publish API repo linked above converts a series of timelapse photos into a photoSequence (packaging all the photos into a single .mp4 file for uploading).

Looking at the script in more detail, the overall flow works like so;

  1. Extract extract_geodata from images (gps timestamp, latitude, longitude, altitude) to create a rawGpsTimeline.
  2. Then convert_video which takes images and creates an .mp4 file from the photos using ffmpeg.
  3. Then upload_video which uploads the .mp4 video created earlier
  4. And finally, publish_video which uploads the geodata (the rawGpsTimeline created in step 1).

Not only does the photoSequence resource save the number of requests to the Google API to upload images, it is useful because it natively supports auto-connections and blurring not available for the photo resource (no more rejected blue lines!).

Once any required processing is complete (steps 1 and 2 above), to upload the video (step 3) a request to open an upload session is needed.


This will return an upload URL which will look something like this;

  "uploadUrl": "<account_id>/photo/<uploadReference>"


The raw video should then be uploaded to the uploadUrl value returned by the previous request.


On successful upload, the video can be published by using the create method.

This is where the GPS data can be added (if it is not natively held in the video as a CAMM track).

To do this an inputType request parameter should be used which will always be "VIDEO".

With the body of the request containing a variety of available parameters, the ones below being critical if CAMM telemetry is not embedded in the video;

  "rawGpsTimeline": [
      "latLngPair": {
        "latitude": 90,
        "longitude": 90
      "altitude": 90,
      "gpsRecordTimestampUnixEpoch": "2014-10-02T15:01:23.045123456Z"
      "latLngPair": {
        "latitude": 80,
        "longitude": 80
      "altitude": 80,
      "gpsRecordTimestampUnixEpoch": "2014-10-02T15:01:24.045123456Z"
  "captureTimeOverride": {
    "seconds": "2014-10-02T15:01:23.045123456Z"
  "uploadReference": {
    "uploadUrl": "<account_id>/photo/<uploadReference>"
  "gpsSource": "PHOTO_SEQUENCE"

Where captureTimeOverride.seconds is the first photo time, uploadReference.uploadUrl is the URL where the video was uploaded to previously, gpsSource is either CAMERA_MOTION_METADATA_TRACK (if video has CAMM track) or PHOTO_SEQUENCE (if using rawGpsTimeline object), and a rawGpsTimeline (if PHOTO_SEQUENCE) that contains the available GPS information from the captured sequence (usually generated from a GPX file).


Note, if the uploaded video contains a CAMM telemetry track you can simply pass the uploadReference.uploadUrl and gpsSource in the body of the request – no GPS information (rawGpsTimeline) is required.

After publishing a photoSequence, you will recieve a response with the processingState.

    "name": "<SEQUENCE_ID>", 
    "response": {
        "@type": "", 
        "id": "<SEQUENCE_ID>", 
        "processingState": "PROCESSING", 
        "uploadTime": "2020-09-26T20:11:01.878Z"

When the video is uploaded the photoSequence enters ProcessingState: PENDING. When the sequence is published (by uploading GPS information, if required) it enters ProcessingState: PROCESSING (note, videos uploaded containing CAMM telemetry will automatically enter this state).

After the Street View processing completes (usually 72 hours, but potentially longer), the photoSequence should enter ProcessingState: PROCESSED.

However, processing can, and often does fail, producing one of the following potential ProcessingFailureReason error.

`ProcessingFailureReason` valueError Description
PROCESSING_FAILURE_REASON_UNSPECIFIEDThe failure reason is unspecified, this is the default value.
LOW_RESOLUTIONVideo frame's resolution is too small.
DUPLICATEThis video has been uploaded before.
NO_OVERLAP_GPSNo overlap between the time frame of GPS track and the time frame of video.
INVALID_GPSGPS is invalid (e.x. all GPS points are at (0,0))
FAILED_TO_REFINE_POSITIONSThe sequence of photos could not be accurately located in the world.
TAKEDOWNThe sequence was taken down for policy reasons.
CORRUPT_VIDEOThe video file was corrupt.
INTERNALA permanent failure in the underlying system occurred.
INVALID_VIDEO_FORMATThe video format is invalid or unsupported.

One downside of using the photoSequence upload is that if one image in the uploaded video fails the Street View server side checks, the entire photoSequence will fail. As opposed to photo upload, where a single photo failure will not result in an entire failure for all photos uploaded in the sequence.

Ultimately, if you’re working with a sequence with more than 10 images, go with the photoSequence method (and make sure any bad images are removed before packing as a video to reduce the likelihood of failed checks), otherwise the photo approach described here is probably preferable.

Never miss an update

Sign up to receive new articles in your inbox as they published.

Discuss this post

Signals Corps Slack