Download Pictures, Photospheres and Streetview Panoramas from Google Maps

Note: as of May 2025 the code in this post does not work.
What works for photospheres is turning a photosphere viewing URL like
:

https://www.google.com/maps/place/Borot+Lots+Campground/@30.5021229,34.6319275,3a,75y,315.58h,91.88t/data=!3m8!1e1!3m6!1sCIHM0ogKEICAgIDqy52-jAE!2e10!3e11!6shttps:%2F%2Flh3.googleusercontent.com%2Fgpms-cs-s%2FAB8u6HZTukqE-3smpL_xzpTY2oWZNf7zn4T9jQhVDBJ_TG-ZQWFgjvuo2jVKWya-CX4xEf7-6igY7SqslnHdxUxDlTxP7xlJRUKlDPxEtrJW5buM4pmHoaS-Uu3d-SemgpSD6Onfr3icog%3Dw900-h600-k-no-pi-1.8781544128473797-ya207.57962850748117-ro0-fo100!7i12800!8i3890!4m7!3m6!1s0x1501e72618987fe3:0x3f575221900fd9c6!8m2!3d30.5135718!4d34.6086344!10e5!16s%2Fg%2F11cnd55nkj?entry=ttu&g_ep=EgoyMDI1MDUwNi4wIKXMDSoASAFQAw%3D%3D

into this URL:

https://lh3.googleusercontent.com/gps-cs-s/AB8u6HZTukqE-3smpL_xzpTY2oWZNf7zn4T9jQhVDBJ_TG-ZQWFgjvuo2jVKWya-CX4xEf7-6igY7SqslnHdxUxDlTxP7xlJRUKlDPxEtrJW5buM4pmHoaS-Uu3d-SemgpSD6Onfr3icog=s8000-k-no

Here is how you can download imagery from Google Maps onto your own computer.

This method involves bookmarklets – special bookmarks that run custom javascript code on the page you are visiting. Steps:

  1. Choose the relevant bookmarklet from the 3 on this page
  2. Drag the (Button) next of the bookmarklet into the “Bookmarks” bar in your browser
  3. Visit the Google Streetview page with the image you want to download
  4. Press on the bookmarklet link you just added to your bookmarks
  5. The image/panorama will open in a new tab. Right-click on it and pick “Save Image As…”

Repeat steps 3 through 5 for as many images/photospheres/streetviews as you wish!

You can view your saved Photospheres/Streetview images at

https://arachnoid.com/3DViewer/index.html
or at
https://renderstuff.com/tools/360-panorama-web-viewer/

Download Individual Photos / Photospheres

Regular flat photos on Google Maps appear next to business listings and in the “explore” bar on the lower right:

User-uploaded Photospheres appear on Streetview as blue circles and only allow you to look around while standing in one spot:

The following Bookmarklet turns flat photos and user-uploaded photo-spheres into saveable images. Drag and drop this button to your Bookmarks bar:

Click to expand the readable code for this bookmarklet. It was converted to a link using Bookmarkleter.
let currentURL = window.location.href;
let panoId = currentURL.match(/!1s(.+?)!/)[1];
let newURL = "https://lh3.ggpht.com/p/" + panoId + "=s8000";
window.open(newURL, '_blank').focus();

Download a Streetview Sphere

Note: as of May 2025 the code in this post does not work. There is a photosphere workaround at the top of the page, but no workaround for Streetview.

Google Streetview images are the ones appearing as part of a “path” on Google Maps and that allow you to move around. They were captured by the Google Team and function differently than the sandalone user-uploaded Photospheres discussed higher on this page.

An example of a Google Streetview image.

This is bookmarklet prepares Zoom level 4 Streetview panorama for saving as a flat image (with a fallback to Zoom level 3). Click and drag this button into your Bookmarks bar:

This is the readable code behind this bookmarklet.

// zoomLevel = zoom level of streetview. We start at 4 and recursively fail back to 3 from within this function if necessary 
function downloadSphere( zoomLevel )
{

  // grab panorama ID
  var currentURL = window.location.href;
  var panoId = currentURL.match(/!1s(.+?)!/)[1];
 
  // maximum possible x and y values. For zoom level 4 in car view - we're fetching 128 tile images, each one 512x512 px
  var max_x = 15;
  var max_y = 7;
  // actual x and y counts - in case sphere is not the max size
  var actual_x = 0;
  var actual_y = 0;
  
  
  // create invisible canvas element - in our maximum hypothetical size
  var canvas = document.createElement('canvas');
  canvas.width = (max_x + 1) * 512;
  canvas.height = (max_y + 1) * 512;

  var context = canvas.getContext('2d');
  
  // total number of images we're loading. will help us determine when all tiles are loaded
  var allimages = (max_x+1) * (max_y+1);


  // when we're done painting all the tiles to canvas, export it as an image into a new tab
  function exportCanvas()
  {
	  
	// hardcoded case: if x=0 and y=0 then fall back to zoom 3. There are also older spheres zoom 5 is available with 256x256 tiles, but we don't bother with that.
	if( actual_x == 0 && actual_y == 0 )
	{ 
		//alert("No tiles retrieved at Zoom Level 4. Falling back to Zoom 3.")
		return( downloadSphere(3))
	}
	
	//create our "final" canvas, potentially smaller than the hypothetical large canvas
	var canvasCropped = document.createElement('canvas')
	canvasCropped.width = (actual_x + 1) * 512
	canvasCropped.height = (actual_y + 1) * 512
	
	// hardcoded case for x=12 and y=6 grid - it has a black band running along the bottom that needs to be cropped
	if( actual_x == 12 && actual_y == 6 ){ canvasCropped.height -= 256; }
	
	// hardcoded case for x=6 and y=3 grid - 2007 sphere: it has a black band on the bottom and an extra column of tiles on the right
	if( actual_x == 6 && actual_y == 3 ){ canvasCropped.height -= 384; canvasCropped.width -= 256; }

	var contextCropped = canvasCropped.getContext('2d')
	
	contextCropped.drawImage( canvas, 0, 0)	// draw the contents of the first canvas into our cropped-size canvas
	
	// Chrome-specific workaround: Chrome doesn't allow opening base64 URLs from code
	var new_window = window.open();
	new_window.document.body.appendChild( canvasCropped ) // will save the image as PNG, but it solves an intractable issue in Firefox. I suspect it was due to their 32MB Data URL limit

  }


  // The below code loads all the image tiles and composes them in a grid
  
  // closures https://stackoverflow.com/questions/1552941/how-does-a-function-in-a-loop-which-returns-another-function-work 
  for( let x = 0; x <= max_x; x++ )
  {
	for( let y = 0; y <= max_y; y++ )
	{
		let img = new Image();
		img.crossOrigin = "anonymous";
		img.src = "https://streetviewpixels-pa.googleapis.com/v1/tile?cb_client=maps_sv.tactile&panoid="+panoId+"&x="+x+"&y="+y+"&zoom="+zoomLevel+"&nbt=1&fover=2";
		
		img.onload = function( x, y) {				// must wait for the image to load before you try to draw it
			return function()
			{
				//console.log("good x="+x+" y="+y)
				context.drawImage(img, 512 * x, 512 * y);
				
				// increment the "actual" x and y dimensions. That way we'll figure out the available number of tiles on the fly
				if( x > actual_x ){ actual_x = x; }
				if( y > actual_y ){ actual_y = y; }
				
				allimages--;
			
				if( allimages == 0 ) // this is the last tile to load - open the final image in new tab
				{
					//console.log("actual X: "+actual_x+" -- actual Y: "+actual_y)
					exportCanvas() // create new tab with our canvas as an image
					
				}
				
				
			}
		}(x,y);
		
		// errors in loading are ok - just means we're trying to load a bigger image than actually exists
		img.onerror = function(mysource){
						return function()
						{
							//console.log("err x="+x+" y="+y)
							allimages--; // do this so we generate an image even if it is missing tiles

						
							if( allimages == 0 ) // this is the last tile to load - open the final image in new tab
							{
								//console.log("actual X: "+actual_x+" -- actual Y: "+actual_y)
								exportCanvas()

							}
						}
					}(img.src);
	
	}
  
  }

} // downloadSphere

downloadSphere( 4 )

I used Bookmarkleter to convert the code into a bookmarklet.



If you loved this post you’ll superlove my monthly emails ✉️


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *