Google Places SDK Flutter
Cross-platform Google Places client and widget toolkit for Flutter, built on Places API (New).
The package includes package-owned request and response models, a
cross-platform PlacesClient, and autocomplete widgets for inline, form,
dialog, and fullscreen flows. The widget layer is locale-aware, RTL-friendly,
and designed to work consistently across Android, iOS, web, macOS, Windows,
and Linux.
Preview
Overview:
Sample flows (Inline field, dialog launcher, fullscreen launcher, and rich result payload):
Features
- Places API (New) autocomplete
- Optional place-details fetch on selection
- Optional Google Time Zone API fetch on selection
- Text search and nearby search client APIs
- Inline field, dialog launcher, and fullscreen launcher modes
- Customizable strings and
InputDecoration - Locale support with
languageCodeandregionCode - Rich field-mask control with
PlaceFieldandPlaceFieldPresets - Typed address support through
postalAddress,addressComponents, and convenience getters
Installation
Add the package to your pubspec.yaml file:
dependencies:
google_places_sdk_flutter: latest_version
Then create a client with your Google Maps Platform API key:
final client = PlacesClient(
apiKey: const String.fromEnvironment('GOOGLE_MAPS_API_KEY'),
);
Official Google docs:
On web, the package uses the Google Maps JavaScript Places library behind the
same PlacesClient API.
Minimal Example
import 'package:flutter/material.dart';
import 'package:google_places_sdk_flutter/google_places_sdk_flutter.dart';
class MinimalPlacesField extends StatefulWidget {
const MinimalPlacesField({super.key});
@override
State<MinimalPlacesField> createState() => _MinimalPlacesFieldState();
}
class _MinimalPlacesFieldState extends State<MinimalPlacesField> {
final _client = PlacesClient(
apiKey: const String.fromEnvironment('GOOGLE_MAPS_API_KEY'),
);
@override
void dispose() {
_client.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return PlacesAutocompleteField(
client: _client,
onSelection: (selection) {
debugPrint(selection.displayText);
},
);
}
}
Common Widget Example
final controller = PlacesAutocompleteController();
PlacesAutocompleteField(
client: client,
controller: controller,
fieldMode: PlacesAutocompleteFieldMode.inline,
strings: const PlacesStrings(
searchHint: 'Search for a place',
),
decoration: const InputDecoration(
labelText: 'Place',
border: OutlineInputBorder(),
),
languageCode: 'en',
regionCode: 'us',
includedPrimaryTypes: const <String>['restaurant', 'cafe'],
includedRegionCodes: const <String>['us'],
fetchPlaceDetailsOnSelection: true,
fetchTimeZoneOnSelection: true,
selectionFields: PlaceFieldPresets.rich,
onSelection: (selection) {
debugPrint(selection.displayText);
debugPrint(selection.place?.formattedAddress);
debugPrint(selection.timeZone?.timeZoneId);
},
onClearField: () {
debugPrint('Cleared');
},
onError: (error) {
debugPrint(error.toString());
},
)
Form Example
Use PlacesAutocompleteFormField when autocomplete selection should
participate in form validation and saving.
final formKey = GlobalKey<FormState>();
Form(
key: formKey,
child: PlacesAutocompleteFormField(
client: client,
decoration: const InputDecoration(
labelText: 'Place',
border: OutlineInputBorder(),
),
fetchPlaceDetailsOnSelection: true,
selectionFields: PlaceFieldPresets.recommended,
validator: (selection) {
if (selection == null) {
return 'Please choose a place';
}
return null;
},
onSaved: (selection) {
debugPrint(selection?.placeId);
},
),
)
Field Options
PlacesAutocompleteField supports the following public options:
PlacesAutocompleteField(
key: key,
client: client,
controller: controller,
decoration: decoration,
strings: strings,
languageCode: languageCode,
regionCode: regionCode,
locationBias: locationBias,
locationRestriction: locationRestriction,
includedPrimaryTypes: includedPrimaryTypes,
includedRegionCodes: includedRegionCodes,
includePureServiceAreaBusinesses: includePureServiceAreaBusinesses,
fetchPlaceDetailsOnSelection: fetchPlaceDetailsOnSelection,
fetchTimeZoneOnSelection: fetchTimeZoneOnSelection,
selectionFields: selectionFields,
selectionLanguageCode: selectionLanguageCode,
selectionRegionCode: selectionRegionCode,
selectionTimeZoneAt: selectionTimeZoneAt,
selectionTimeZoneLanguageCode: selectionTimeZoneLanguageCode,
fieldMode: fieldMode,
onSelection: onSelection,
onClearField: onClearField,
onError: onError,
maxSuggestions: maxSuggestions,
enabled: enabled,
autofocus: autofocus,
showPoweredByGoogle: showPoweredByGoogle,
suggestionBuilder: suggestionBuilder,
)
In practice:
fieldModecan beinline,dialog, orfullscreenincludedPrimaryTypesuses Google Places primary type strings such as'restaurant','cafe', or'(cities)'selectionFieldscontrols which fields are fetched when details loading is enabledmaxSuggestionsis a display cap and is effectively limited to5by Google Autocomplete (New)- if you pass a custom
InputDecoration, the package preserves your styling and still keeps the clear action available
Google primary type reference:
Selection Model
All widget flows return a package-owned PlaceSelection:
class PlaceSelection {
final PlaceSuggestion suggestion;
final PlaceData? place;
final PlaceTimeZoneData? timeZone;
}
This means:
suggestionis always availableplaceis available whenfetchPlaceDetailsOnSelectionis enabledtimeZoneis available whenfetchTimeZoneOnSelectionis enabled
Standalone Client Calls
Use the client directly when you already have a place id or want to resolve time-zone data separately from the widget flow.
Fetch rich place details from a place id:
final place = await client.fetchPlaceById(
'ChIJmQJIxlVYwokRLgeuocVOGVU',
fields: PlaceFieldPresets.rich,
languageCode: 'en',
regionCode: 'us',
);
Fetch time-zone data from resolved place details:
final timeZone = await client.fetchTimeZoneForPlace(
place,
timestamp: DateTime.now().toUtc(),
languageCode: 'en',
);
debugPrint(timeZone.timeZoneId);
debugPrint(timeZone.timeZoneName);
Time-zone lookups use Google Time Zone API, which is separate from Places API and may be billed separately.
Typed Address Details
When you request PlaceField.postalAddress and/or
PlaceField.addressComponents, PlaceData exposes typed address structures
and convenience getters for common legacy-style fields:
final place = await client.fetchPlaceById(
'ChIJmQJIxlVYwokRLgeuocVOGVU',
fields: <PlaceField>{
...PlaceFieldPresets.rich,
PlaceField.postalAddress,
PlaceField.addressComponents,
},
);
debugPrint(place.route);
debugPrint(place.streetNumber);
debugPrint(place.locality);
debugPrint(place.administrativeArea);
debugPrint(place.postalCode);
debugPrint(place.country);
debugPrint(place.countryCode);
Google references:
Overlay Usage
Use PlacesAutocompleteOverlay.show() when search should happen in a dedicated
route instead of inline:
final selection = await PlacesAutocompleteOverlay.show(
context,
client: client,
mode: PlacesAutocompleteOverlayMode.fullscreen,
languageCode: 'en',
regionCode: 'us',
fetchPlaceDetailsOnSelection: true,
fetchTimeZoneOnSelection: true,
selectionFields: PlaceFieldPresets.rich,
);
Example App
The /example app demonstrates:
- inline autocomplete
- form integration
- dialog and fullscreen launcher modes
- rich place-details loading
- optional time-zone loading
- custom strings
- locale switching
- RTL layout
Run it with:
flutter run --dart-define=GOOGLE_MAPS_API_KEY=your_key_here
Libraries
- google_places_sdk_flutter
- Cross-platform Flutter package for Google Places API (New).