goplaces

May 4, 2026 · View on GitHub

Modern Go client and CLI for the Google Places API (New), plus selected Routes API workflows.

Docs site: https://goplaces.sh

Use it when you want Google place data from a terminal, shell script, agent, or Go program without hand-writing Places field masks and request payloads. goplaces keeps the human CLI pleasant, but the same commands also emit stable JSON for automation.

Typical jobs:

  • Find places by text, type, rating, price, current open state, and location bias.
  • Inspect a place: address, coordinates, phone, website, hours, photos, reviews, current open state, and business status.
  • Autocomplete partial place/query input.
  • Search nearby a lat/lng radius.
  • Resolve free-form locations to place candidates.
  • Search for places along a route.
  • Get directions, travel time, distance, steps, units, and drive route modifiers.

Project Shape

  • cmd/goplaces: CLI entrypoint built around the library.
  • Root package github.com/steipete/goplaces: stable public Go API.
  • internal/places: Places + Routes implementation and focused client tests.
  • internal/cli: command parsing, output rendering, and CLI tests.
  • Places API (New): search, nearby, details, autocomplete, photo media, resolve.
  • Routes API: route polyline sampling and directions.
  • Output: compact color text by default, JSON with --json.
  • Runtime config: environment variables or flags.

Install / Run

Latest release: v0.4.0 (2026-05-04).

  • Homebrew: brew install steipete/tap/goplaces
  • Go: go install github.com/steipete/goplaces/cmd/goplaces@latest
  • Source: make goplaces

API Setup

goplaces needs a Google API key with the right APIs enabled:

  • Places API (New) for search, nearby, autocomplete, details, photo, and resolve.
  • Routes API for route and directions.
export GOOGLE_PLACES_API_KEY="..."

Optional overrides:

  • GOOGLE_PLACES_BASE_URL (testing, proxying, or mock servers)
  • GOOGLE_ROUTES_BASE_URL (testing Routes API or proxying)
  • GOOGLE_DIRECTIONS_BASE_URL (testing Routes API directions calls or proxying)

Create a Key

  1. Create a Google Cloud Project

    • Go to Google Cloud Console
    • Click "Select a project" → "New Project"
    • Name it (e.g., "goplaces") and click "Create"
  2. Enable the Places API (New)

  3. Enable the Routes API (for route and directions)

    • Search for "Routes API"
    • Click "Enable"
  4. Create an API Key

  5. Set the Environment Variable

    export GOOGLE_PLACES_API_KEY="your-api-key-here"
    

    Add to your ~/.zshrc or ~/.bashrc to persist.

  6. (Recommended) Restrict the Key

    • Click on the key in Credentials
    • Under "API restrictions", select "Restrict key" → add "Places API (New)" and "Routes API"
    • Set quota limits in Quotas

Note: The Places API has usage costs. Check pricing and set budget alerts!

CLI Overview

Long flags accept --flag value or --flag=value (examples use space).

goplaces [--api-key=KEY] [--base-url=URL] [--routes-base-url=URL] [--directions-base-url=URL] [--timeout=10s] [--json] [--no-color] [--verbose]
         <command>

Commands:
  autocomplete  Autocomplete places and queries.
  nearby        Search nearby places by location.
  search   Search places by text query.
  route    Search places along a route.
  directions  Get directions between two points.
  details  Fetch place details by place ID.
  photo    Fetch a photo URL by photo name.
  resolve  Resolve a location string to candidate places.

Command map:

CommandAPIUse
searchPlaces Text SearchFind places by query and filters.
nearbyPlaces Nearby SearchFind places around a lat/lng radius.
autocompletePlaces AutocompleteGet place/query suggestions for partial input.
detailsPlace DetailsFetch rich place data by place ID.
photoPlace Photo MediaTurn a photo resource name into a media URL.
resolvePlaces Text SearchResolve a free-form location string.
routeRoutes + PlacesSample a route and search near waypoints.
directionsRoutesGet distance, duration, warnings, and steps.

Examples

Search with filters + location bias:

goplaces search "coffee" --min-rating 4 --open-now --limit 5 \
  --lat 40.8065 --lng -73.9719 --radius-m 3000 --language en --region US

Pagination:

goplaces search "pizza" --page-token "NEXT_PAGE_TOKEN"

Autocomplete:

goplaces autocomplete "cof" --session-token "goplaces-demo" --limit 5 --language en --region US

Nearby search:

goplaces nearby --lat 47.6062 --lng -122.3321 --radius-m 1500 --type cafe --limit 5

Route search:

goplaces route "coffee" --from "Seattle, WA" --to "Portland, OR" --max-waypoints 5

Directions (walking with optional driving comparison):

goplaces directions --from "Pike Place Market" --to "Space Needle"
goplaces directions --from-place-id <fromId> --to-place-id <toId> --compare drive --steps

Driving route modifiers:

goplaces directions --from "Paris" --to "Brest" --mode drive --avoid-tolls
goplaces directions --from "Paris" --to "Brest" --mode drive --avoid-highways --avoid-ferries

Units (default metric):

goplaces directions --from "Pike Place Market" --to "Space Needle" --units imperial

Details:

goplaces details ChIJ-bfVTh8VkFQRDZLQnmioK9s
goplaces details ChIJN1t_tDeuEmsRUsoyG83frY4 --reviews
goplaces details ChIJN1t_tDeuEmsRUsoyG83frY4 --photos

Photo URL:

goplaces photo "places/PLACE_ID/photos/PHOTO_ID" --max-width 1200

Resolve:

goplaces resolve "Riverside Park, New York" --limit 5

JSON output:

goplaces search "sushi" --json

Example JSON result fields include:

{
  "place_id": "ChIJ-bfVTh8VkFQRDZLQnmioK9s",
  "name": "Space Needle",
  "address": "400 Broad St, Seattle, WA 98109, USA",
  "rating": 4.6,
  "user_rating_count": 58186,
  "open_now": true,
  "business_status": "OPERATIONAL"
}

Library

boolPtr := func(v bool) *bool { return &v }
floatPtr := func(v float64) *float64 { return &v }

client := goplaces.NewClient(goplaces.Options{
    APIKey:  os.Getenv("GOOGLE_PLACES_API_KEY"),
    Timeout: 8 * time.Second,
})

search, err := client.Search(ctx, goplaces.SearchRequest{
    Query: "italian restaurant",
    Filters: &goplaces.Filters{
        OpenNow:   boolPtr(true),
        MinRating: floatPtr(4.0),
        Types:     []string{"restaurant"},
    },
    LocationBias: &goplaces.LocationBias{Lat: 40.8065, Lng: -73.9719, RadiusM: 3000},
    Language:     "en",
    Region:       "US",
    Limit:        10,
})

details, err := client.DetailsWithOptions(ctx, goplaces.DetailsRequest{
    PlaceID:        "ChIJN1t_tDeuEmsRUsoyG83frY4",
    Language:       "en",
    Region:         "US",
    IncludeReviews: true,
})

autocomplete, err := client.Autocomplete(ctx, goplaces.AutocompleteRequest{
    Input:        "cof",
    SessionToken: "goplaces-demo",
    Limit:        5,
    Language:     "en",
    Region:       "US",
})

nearby, err := client.NearbySearch(ctx, goplaces.NearbySearchRequest{
    LocationRestriction: &goplaces.LocationBias{Lat: 47.6062, Lng: -122.3321, RadiusM: 1500},
    IncludedTypes:       []string{"cafe"},
    Limit:               5,
})

photo, err := client.PhotoMedia(ctx, goplaces.PhotoMediaRequest{
    Name:       "places/PLACE_ID/photos/PHOTO_ID",
    MaxWidthPx: 1200,
})

route, err := client.Route(ctx, goplaces.RouteRequest{
    Query:        "coffee",
    From:         "Seattle, WA",
    To:           "Portland, OR",
    MaxWaypoints: 5,
})

Notes

  • Filters.Types maps to includedType (Google accepts a single value). Only the first type is sent.
  • Price levels map to Google enums: 0 (free) → 4 (very expensive).
  • Reviews are returned only when IncludeReviews/--reviews is set.
  • Photos are returned only when IncludePhotos/--photos is set.
  • Route search requires the Google Routes API to be enabled.
  • business_status is returned for search, nearby, and details when Google includes it.
  • Direction route modifiers (--avoid-tolls, --avoid-highways, --avoid-ferries) require --mode drive.
  • Field masks are defined alongside each request (e.g. search.go, details.go, autocomplete.go).
  • The Places API is billed and quota-limited; keep an eye on your Cloud Console quotas.

Testing

make lint test coverage

E2E tests (optional)

export GOOGLE_PLACES_API_KEY="..."
make e2e

Optional env overrides:

  • Use a custom endpoint (proxy/mock): GOOGLE_PLACES_E2E_BASE_URL
  • Override the search text used in E2E: GOOGLE_PLACES_E2E_QUERY
  • Override language code for E2E: GOOGLE_PLACES_E2E_LANGUAGE
  • Override region code for E2E: GOOGLE_PLACES_E2E_REGION
  • Override directions endpoints/locations: GOOGLE_DIRECTIONS_E2E_BASE_URL, GOOGLE_PLACES_E2E_DIRECTIONS_FROM, GOOGLE_PLACES_E2E_DIRECTIONS_TO