The problem

A local business owner asked me: "How do I send customers a link that opens the Google review box straight away?"

Google supports this with a direct review link:

https://search.google.com/local/writereview?placeid=ChIJb5qX9LW9cEgRVzYV0mRGxVw 

To build it you need the business's Place ID (the ChIJ… string). The official route is the Places API, which means:

  • a Google Cloud project
  • an API key and billing details
  • a server to keep the key private

There's a simpler way. The Place ID is already inside every Google Maps link, just encoded differently. In this post we'll build a Place ID finder around one small function (about 10 lines) that pulls it out, entirely in the browser.

TL;DR

Step What you do
1 Find the feature ID in the Maps URL: !1s0x…:0x…
2 Pack its two 64-bit numbers into 20 bytes of protobuf
3 Base64url-encode the bytes. That's the Place ID.

Step 1: Find the feature ID in the URL

Open a business on Google Maps and look at the full URL. In the data= part you'll see something like:

!1s0x4870bdb5f4979a6f:0x5cc54664d2153657 

This is the feature ID (FID): two 64-bit hex numbers joined by a colon.

  • First half: 0x4870bdb5f4979a6f
  • Second half: 0x5cc54664d2153657. This is the CID, the number used in maps.google.com/?cid=… links.

The Place ID for the same business is:

ChIJb5qX9LW9cEgRVzYV0mRGxVw 

They look unrelated, but they contain exactly the same data.

Step 2: Understand the Place ID format

Base64-decode the Place ID and you get 20 bytes:

0a 12 09 6f 9a 97 f4 b5 bd 70 48 11 57 36 15 d2 64 46 c5 5c 

These bytes are a small protocol buffers message:

Bytes Meaning
0a 12 Field 1: a nested message, 18 bytes long
09 Inner field 1, type fixed64
6f 9a 97 f4 b5 bd 70 48 0x4870bdb5f4979a6f, first half of the FID (little-endian)
11 Inner field 2, type fixed64
57 36 15 d2 64 46 c5 5c 0x5cc54664d2153657, second half of the FID (little-endian)

In short, a Place ID is { 1: { 1: fixed64 a, 2: fixed64 b } }, serialised and base64url-encoded.

💡 That's also why every Place ID starts with ChIJ: it's the base64 form of the fixed header bytes 0a 12 09.

Step 3: The finder: feature ID → Place ID

function placeIdFromFid(fid) { const [a, b] = fid.split(':').map(h => BigInt(h)); const bytes = new Uint8Array(20); const dv = new DataView(bytes.buffer); bytes[0] = 0x0a; bytes[1] = 0x12; bytes[2] = 0x09; // header dv.setBigUint64(3, a, true); // first half, little-endian bytes[11] = 0x11; // field 2 tag dv.setBigUint64(12, b, true); // second half, little-endian let s = ''; bytes.forEach(x => { s += String.fromCharCode(x); }); return btoa(s).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); } placeIdFromFid('0x4870bdb5f4979a6f:0x5cc54664d2153657'); // → "ChIJb5qX9LW9cEgRVzYV0mRGxVw" ✅ 

BigInt and DataView.setBigUint64 work in all modern browsers, so this runs fully client-side. No key, no server, no quota.

Step 4: Build the review link

const reviewUrl = pid => `https://search.google.com/local/writereview?placeid=${encodeURIComponent(pid)}`; 

Common pitfalls (and how to fix them)

Problem Why it happens Fix
Wrong business returned A URL can contain several feature IDs: the building, nearby places, directions points Match in priority order (see below)
First half is 0x0 The link points to a single review, not the business Show a message asking for the business link
Short links (maps.app.goo.gl) The browser can't follow cross-origin redirects Resolve them with a small server endpoint
share.google/… links These come from Google Search and contain a Knowledge Graph ID, not a feature ID Ask the user to share from Google Maps instead
Missing business name /maps/place/<Name>/ is URL-encoded and sometimes absent on mobile Treat the name as optional

Picking the right feature ID

Match the URL patterns in this order:

  1. !3m<n>!1s<FID>: the place panel that's open (most reliable)
  2. !1s<FID>: usually the place, but can be a directions point
  3. ftid=<FID>: older link formats
  4. any 0x…:0x…: last resort

!5s… usually refers to a nearby place, so it's never picked first.

const FID = '(0x[0-9a-f]{1,16}:0x[0-9a-f]{1,16})'; const fid = ( url.match(new RegExp('!3m\\d+!1s' + FID, 'i')) || url.match(new RegExp('!1s' + FID, 'i')) || url.match(new RegExp('ftid=' + FID, 'i')) || url.match(new RegExp(FID, 'i')) || [] )[1]; 

Resolving short links safely

My server endpoint for maps.app.goo.gl links:

  • only contacts Google hosts (allowlist)
  • follows redirects one at a time and stops once it finds a feature ID
  • handles the consent.google.com?continue=… page served to UK and EU visitors
  • is rate-limited per hashed IP

How I tested it

I compared the output with Place IDs from the official Places API for several UK businesses, using:

  • long desktop URLs
  • maps.app.goo.gl short links
  • mobile share links
  • directions URLs

Every result matched byte for byte. To check your own, reverse the process in Node:

const b = Buffer.from(pid.replace(/-/g, '+').replace(/_/g, '/'), 'base64'); console.log('0x' + b.readBigUInt64LE(3).toString(16) + ':0x' + b.readBigUInt64LE(12).toString(16)); 

What I built with it

I turned this into a free tool for small businesses. Paste a Google Maps link and it gives you:

  • ✅ the business's Place ID, ready to copy
  • ✅ the direct review link
  • ✅ a QR code (PNG)
  • ✅ a printable A6 counter card, drawn on a <canvas>
  • ✅ ready-to-send WhatsApp, text and email messages

The tool showing the Place ID, review link, QR code and message templates

It needs no sign-up, stores nothing, and is plain JavaScript plus the MIT-licensed qrcode-generator.

👉 Try it: Free Google review link generator and Place ID finder

Limitations

This format isn't documented by Google and could change. It has been stable for years, but if you rely on it, keep a fallback such as the Places API, or let users paste a Place ID directly.

Over to you

Have you found Google Maps URL patterns that break this, or other hidden IDs in Google URLs worth decoding? Tell me in the comments and I'll make the parser more robust. 👇