# Reverse-Engineered Internal Endpoints

Protobuf APIs, tbm=map, APP\_INITIALIZATION\_STATE, pagination

# Protobuf Endpoints & Internal APIs

## Google Maps Internal Protobuf API

Google Maps communicates with its backend using **Protocol Buffer (protobuf) encoding** over HTTP. Several internal endpoints have been documented.

### tbm=map Search Endpoint

Adding `tbm=map` to a Google search returns protobuf-over-JSON instead of HTML. Single HTTP request, no browser rendering needed.

```
https://www.google.com/search?tbm=map&hl=en&q=restaurants+in+berlin&tch=1&ech=1
```

Returns: nested arrays parseable with JSON indexing — business names, ratings, review counts, categories, addresses, coordinates, thumbnails.

### /maps/preview/place — Place Details

Returns protobuf-over-JSON place details via a `pb` parameter with feature ID embedded. More stable than HTML scraping — follows internal schema, not frontend layout.

### /maps/vt/pb — Tile Endpoint

Map tile requests containing ~730 fields across ~125 protobuf messages. Uses `!`-separated text-based protobuf with type characters (s, i, d, f, j, u, v, x, y, g, h, n, o, e, z, B, b, m).

### window.APP\_INITIALIZATION\_STATE

Google Maps embeds data in `window.APP_INITIALIZATION_STATE` in the HTML response. No headless browser needed:

```
JSON.parse(window.APP_INITIALIZATION_STATE[3][2].split("'\n")[1])
```

*Source: r/webscraping*

### Protobuf Pagination Details

- **PSI parameter**: stored in `window.APP_OPTIONS[11]`, changes after each page reload — no static URL construction possible
- **Altitude formula**: `altitude = (27.3611 * 6371010 * 768 * cos(lat)) / (2^zoom * 256)`
- **Pagination**: `!7i20` = 20 results/page, `!8i[offset]` = offset (increments of 20)
- **Responses**: served through `f.txt` endpoint with "XHR1" signature

### Data Available

Potentially *everything* visible in the Maps UI: full review text with timestamps, all photos, Q&amp;A, popular times histograms, wait times, related places, owner responses — far exceeding the official API's 5-review limit.

### Fragility Warning

Google's cryptographic constants rotate continuously. SearchGuard makes "reverse-engineered bypasses obsolete within minutes." One Reddit user reported successfully building a pure HTTP/protobuf scraper that reduced costs from $50K/mo to $1K/mo — but maintenance is constant.

# Protobuf Tools & Decoders

## Protobuf Tools

<table id="bkmrk-toollanguagepurposel"><tr><th>Tool</th><th>Language</th><th>Purpose</th><th>Link</th></tr><tr><td>**pbtk**</td><td>Python</td><td>Extract and fuzz protobuf structures from Chrome</td><td>[GitHub](https://github.com/marin-m/pbtk)</td></tr><tr><td>**google-maps-pb-decoder**</td><td>Ruby</td><td>Decode pb URL params to JSON</td><td>[GitHub](https://github.com/serpapi/google-maps-pb-decoder)</td></tr><tr><td>**deproto**</td><td>Python</td><td>Decode, manipulate, re-encode protobuf strings (round-trip conversion)</td><td>[GitHub](https://github.com/MrDebugger/deproto)</td></tr></table>

### XHR/Network Interception

Intercept browser XHR requests during Google Maps navigation; responses contain protobuf-encoded data with "XHR1" signature. Use CDP `Network.requestWillBeSent` event + `history.replaceState()` hooks. Supported by Puppeteer request interception and Playwright route handlers.

### Sources

- [SerpAPI — Reverse Engineering Maps Pagination](https://serpapi.com/blog/how-we-reverse-engineered-google-maps-pagination/)
- [$5K Google Maps XSS via Protobuf](https://medium.com/@marin_m/how-i-found-a-5-000-google-maps-xss-by-fiddling-with-protobuf-963ee0d9caff)
- [Scrape.do — Maps Scraping Guide](https://scrape.do/blog/google-maps-scraping/)