Street View panorama IDs

Date: 2025-02-25

Each Street View image has a panorama ID. This post collects some information about pano IDs used in different places.

Official pano IDs

Pano IDs created for Google's own Street View images are 22 characters long and end with a g, w, A, or Q.

Checking if pano IDs are 22 characters long gives you a good guess for whether an image is official Google imagery or not, though the Maps API uses a different check.

Unofficial pano URLs

A full URL to an unofficial panorama contains one representation of a pano ID:

https://www.google.com/maps/@13.4550671,-16.5770576,3a,75y,133.5h,80.5t
/data=!3m6!1e1!3m4!1sAF1QipOxDNPw6hEebqAFLzanNBDBt8MPj_tVzvRoLx4x!2e10!7i10560!8i5280

The ID is AF1QipOxDNPw6hEebqAFLzanNBDBt8MPj_tVzvRoLx4x. But there's actually another important part here: If we remove the !2e10 from the URL, then the image will not load.

/data=!3m5!1e1!3m3!1sAF1QipOxDNPw6hEebqAFLzanNBDBt8MPj_tVzvRoLx4x!7i10560!8i5280

That's because 10 is the panorama type.

Load an unofficial panorama in a street view embed

If we try to use the setPano() API with our value AF1QipOxDNPw6hEebqAFLzanNBDBt8MPj_tVzvRoLx4x, it does not work.

This is because we are not telling the street view embed what type of panorama we are looking up!

The street view embed uses a special encoding for this. You have to give it a base64-encoded protobuf message:

message ImageKey {
  int32 type = 1;
  string id = 2;
}

We can convert between the encoded and unencoded formats using the pbf module:

import Pbf from 'pbf'

const TYPE_OFFICIAL = 2
const TYPE_UNOFFICIAL = 10

function encodePanoId (type: number, id: string): string {
  if (type === TYPE_OFFICIAL) {
    return id
  }

  const pbf = new Pbf()
  pbf.writeVarintField(1, type)
  pbf.writeStringField(2, id)
  const bytes: Uint8Array = pbf.finish()
  return bytes.toBase64()
}

function decodePanoId (string: string): { type: number, id: string } {
  try {
    const bytes = Uint8Array.fromBase64(string)
    const pbf = new Pbf(bytes)
    return pbf.readFields((tag, data) => {
      if (tag === 1) data.type = pbf.readVarint()
      if (tag === 2) data.id = pbf.readString()
    }, { type: TYPE_OFFICIAL, id: '' })
  } catch {
    return { type: TYPE_OFFICIAL, id: string }
  }
}

Given

encodePanoId(
  10,
  "AF1QipOxDNPw6hEebqAFLzanNBDBt8MPj_tVzvRoLx4x",
)

We get:

CAoSLjFzQUYxUWlwT3hETlB3NmhFZWJxQUZMemFuTkJEQnQ4TVBqX3RWenZSb0x4NHg

This value we actually can give to setPano().

With the decodePanoId() function, we can also take a pano ID from a street view embed, and create street view URL for it.

This pair of functions is useful if you want to give users a way to copy links to street view, or paste street view links into your app.