npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

googlemaps-kit

v0.4.0

Published

TypeScript SDK + Bubble Tea TUI for Google Maps consumer surfaces

Readme

googlemaps-kit

TypeScript SDK for programmatic access to Google Maps consumer surfaces.

npm version npm downloads TypeScript License Node

Site: googlemapskit.vaandeetttt.com · npm: googlemaps-kit

Agent bootstrap (Cursor / Claude / Codex): use Copy Agent Instruction on the site, or:

npx skills add KumarVandit/googlemaps-kit --skill googlemaps-kit --agent '*'

Overview

Intent-first client for search, places, reviews, directions, photos, geocoding, tiles, and more. No Maps Platform API key. No browser dependency — works out of the box from Node 18+ with automatic client initialization.

Disclaimer

Not an official Google product. Endpoints are undocumented and can change, throttle, or block without notice. Intended for research and personal tooling, not bulk scraping.

How it works

  1. Zero configsdk() initializes automatically; no API keys or manual setup.
  2. Same surfaces as Maps — Search, place details, reviews, directions, and photos use the same HTTP and RPC paths as the Maps web app, merged into typed results.
  3. Intent + namespaces — call discover / profile / route for common flows, or use domain namespaces (places, travel, map, …) for full control.
  4. No headless browser — except passiveAssist, which needs a viewport token you supply externally.

Quick start

npm install googlemaps-kit
import { sdk } from 'googlemaps-kit';

const maps = sdk({
  locale: { hl: 'en', gl: 'in' },
});

const { places } = await maps.discover({
  query: 'cafes in indiranagar',
  near: { lat: 12.98, lng: 77.64 },
});

const top = places[0]!;
const { place } = await maps.profile(top, { depth: 'card' });
const reviews = await maps.opinions(top, { pages: 1 });

console.log(place.name, place.rating, reviews.reviews.length, 'reviews');

Package layout

| Import | Use for | |--------|---------| | googlemaps-kit | Apps & agents — sdk(), Intent API, namespaces, result types | | googlemaps-kit/advanced | Under the hood — HTTP client, protobuf builders, RPC, parsers |

Intent API

| Method | Input | Output | Latency notes | |--------|-------|--------|---------------| | discover({ query, near }) | query + coords (near or location) | { places, timingMs, mode, pagination } | Default mode:'fast' ~400 ms; pass offset to paginate | | discoverPages(…) | same + maxPages | async iterable of DiscoverResult | Streams pages; dedupes across pages | | resolve({ query \| url, near? }) | text or URL | { hexId?, name?, lat?, lng?, source } | Identity only — check hexId before profile | | profile(ref, { depth? }) | PlaceRef | { place, depth, reviews?, … } | Use place.name (not top-level .name) | | profileMany(refs) | PlaceRef[] | PlaceProfile[] | Bounded concurrency + onProgress | | route({ from, to }) | coords / address / PlaceRef | DirectionsResult | Default metrics only | | opinions(ref) | PlaceRef | ReviewsResult | reviewCount = page size; totalReviews needs aggregates | | opinionsPages(ref) | PlaceRef | async iterable of review pages | Streams Boq pages | | media(ref) | PlaceRef | { photos[], photoCount, nextPageToken? } | Flat PlacePhoto[] | | mediaMany(refs) | PlaceRef[] | MediaResult[] | Bounded concurrency | | pipeline({ discover, … }) | discover + optional profile/opinions | enriched rows | One-shot lead scrape | | tools() | — | agent tool map | Same as createMapsTools(maps) | | capabilities() | — | capability flags | Async; cookie presence only |

Common mistakes

| Mistake | Do this instead | |---------|-----------------| | const p = await maps.profile(…); p.name | p.place.name | | route({ from: hexId }) | Pass coords or address — bare ids need lat/lng | | reviews.reviewCount as place total | Use totalReviews with includeAggregates: true | | place.photos[0].normalizedUrl after profile | Profile photos are URL strings; use media() for PlacePhoto | | session: 'authenticated' without cookies | Throws at create — cookies are the real gate |

Namespaces

| Namespace | Contains | |-----------|----------| | maps.places | search, suggest, details, get(), reviews, photos, knowledge, localPosts | | maps.location | geocode, timezone, reveal, passiveAssist | | maps.travel | directions, distanceMatrix, elevation, transit, traffic | | maps.map | tiles, staticMap, panorama | | maps.meta | categories, ugcAggregates, lists, links, batchUrl | | maps.agent | ask(), askMaps (signed-in) | | maps.auth | status(), summarize() | | maps.surfaces | list(), working(), get(name) |

await maps.places.search.searchText({ query: 'coffee', near, mode: 'fast' });
await maps.travel.directions.get({ origin: 'A', destination: 'B' });
await maps.location.geocode.geocode('HSR Layout, Bengaluru');

Auth tiers

| Tier | How | Unlocks | |------|-----|---------| | Anonymous (default) | Session warms itself | Search, places, Boq reviews, photos, directions, traffic, categories | | Authenticated | cookies / GMAPS_COOKIES | Ask Maps, reviews source:'rpc', private lists |

Signed-in surfaces throw AuthRequiredError when cookies are missing.

Configuration

sdk() loads .env.local then .env from the working directory.

| Option | Env var | Default | Description | |--------|---------|---------|-------------| | locale.hl / hl | GMAPS_HL | en | Language | | locale.gl / gl | GMAPS_GL | us | Region | | session | — | anonymous | Capability profile | | cookies | GMAPS_COOKIES | — | Optional signed-in cookie string | | performance.mode | — | fast | Default discover() search mode | | requestDelayMs | GMAPS_REQUEST_DELAY_MS | 0 | Min delay between request starts | | concurrency | GMAPS_CONCURRENCY | 6 | Max parallel in-flight requests | | debug | GMAPS_DEBUG | false | Log requests/responses | | hooks | — | — | onAction / onRetry / onError lifecycle callbacks | | cache | — | off | Optional TTL cache for discover / profile (card) |

DX extras

const maps = sdk({
  hooks: {
    onAction: ({ type, status, durationMs }) => console.log(type, status, durationMs),
  },
  cache: { ttlMs: 60_000 },
});

// cancel in-flight work
const ac = new AbortController();
await maps.discover({ query: 'coffee', near, signal: ac.signal });

// stream pages
for await (const page of maps.discoverPages({ query: 'coffee', near, maxPages: 3 })) {
  console.log(page.places.length, page.pagination.hasMore);
}

// batch + pipeline
await maps.profileMany(hits, { concurrency: 4, onProgress: console.log });
await maps.pipeline({ discover: { query: 'coffee', near }, maxPlaces: 5, profile: { depth: 'card' } });

// agent tools
const tools = maps.tools(); // or createMapsTools(maps)
await tools.discover.execute({ query: 'coffee', nearLat: near.lat, nearLng: near.lng });

CLI (pretty tables on TTY, JSON when piped) + interactive TUI:

# Interactive (Bubble Tea TUI)
npx googlemaps-kit
npx googlemaps-kit tui

# Scripted
npx googlemaps-kit discover "cafes in indiranagar" --near 12.98,77.64 --limit 5
npx googlemaps-kit resolve --query "Cubbon Park Bangalore"
npx googlemaps-kit profile --query "Third Wave Coffee Indiranagar" --near 12.98,77.64
npx googlemaps-kit route --from "Cubbon Park, Bangalore" --to "Indiranagar, Bangalore"
npx googlemaps-kit opinions --query "Third Wave Coffee Indiranagar" --near 12.98,77.64
npx googlemaps-kit media --query "Third Wave Coffee Indiranagar" --near 12.98,77.64
npx googlemaps-kit pipeline "cafes" --near 12.98,77.64 --max 3

TUI is built with Bubble Tea (TypeScript port). Use --json / --format json|csv|geojson for machine output. Export helpers: toCsv(places), toGeoJSON(places).

Advanced (under the hood)

When you need protobuf pb= builders, batchexecute RPC IDs, or raw parsers:

import {
  HttpClient,
  buildSearchPb,
  extractBusinesses,
  BATCH_EXECUTE_PATH,
} from 'googlemaps-kit/advanced';

Organized modules: HTTP transport, auth/session, RPC/protobuf, parsers, service classes.

Limitations

  • Undocumented consumer surfaces; no stability guarantee.
  • Signed-in features need cookies you supply — the kit does not perform Google login.
  • passiveAssist needs a viewport psi you supply externally.
  • Map tiles: 256px roadmap layer verified; other layers may return HTTP 400.

Development

npm test
npm run build
npm run examples:all
npm run verify:all

Website: googlemapskit.vaandeetttt.com

License

MIT