React Google Maps: Use the Google Maps API in React
The simplest way to use Google Maps in React today is @vis.gl/react-google-maps, a library of React components and hooks for the Maps JavaScript API. The Google Maps Platform team started it, and Google's own React page lists it. You wrap your app in <APIProvider apiKey=...>, render a <Map>, and add <AdvancedMarker>, <InfoWindow> and Places Autocomplete as children. Below is a setup that works with React 18 and 19, Vite or Next.js, as of October 2026 (library version 1.10).
Which React Google Maps library should you use?
Search "react google maps" on npm and you get several packages with nearly the same name. Here's where they stand:
| Package | Status (October 2026) | Use it? |
|---|---|---|
@vis.gl/react-google-maps |
Active, v1.10.x, started by the Google Maps Platform team (docs) | Yes, for new projects |
@react-google-maps/api |
Community library, v2.20.x, last published December 2025 | OK for existing apps; it predates Advanced Markers and the new Places widgets |
google-map-react |
v2.2.x, last published May 2025, renders React components over a map | Legacy projects only |
react-google-maps (tomchentw) |
Abandoned for years (v9.4.5) | No |
@googlemaps/react-wrapper |
Google's thin loader: loads the script, you write imperative code | Only if you want raw google.maps calls |
The rest of this guide uses @vis.gl/react-google-maps. Its components wrap the current Maps JavaScript API objects (AdvancedMarkerElement, importLibrary), so it follows what Google recommends today. The old google.maps.Marker is deprecated, for example.
Step 1: Get a Google Maps API key
- In the Google Cloud console, create or pick a project and attach a billing account. The Maps JavaScript API won't load without one, even if you stay inside the free usage.
- Go to APIs & Services > Library and enable Maps JavaScript API. For autocomplete, also enable Places API (New).
- Go to Keys & Credentials (or APIs & Services > Credentials) and create an API key.
- Restrict the key. Under application restrictions pick Websites and add your domains (
http://localhost:5173/*,https://yourapp.com/*). Under API restrictions allow only the APIs you enabled. A browser key is always visible to visitors, so these restrictions are your only protection (API security best practices). - For markers you also need a Map ID (see step 4). Use
DEMO_MAP_IDwhile testing; Google allows it for that (Advanced Markers docs).
Put the key in an env file, not in source control:
# Vite: .env.local
VITE_GOOGLE_MAPS_API_KEY=your-key-here
# Next.js: .env.local
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=your-key-here
Step 2: Install the library
npm install @vis.gl/react-google-maps
It works with React 16.8 and up, including React 19, and pulls in the @types/google.maps types, so TypeScript works without extra setup.
Step 3: Render a map in React
import {APIProvider, Map} from '@vis.gl/react-google-maps';
const API_KEY = import.meta.env.VITE_GOOGLE_MAPS_API_KEY as string;
export default function App() {
return (
<APIProvider apiKey={API_KEY}>
<div style={{height: '100vh', width: '100%'}}>
<Map
defaultCenter={{lat: 40.7128, lng: -74.006}}
defaultZoom={12}
gestureHandling="greedy"
disableDefaultUI
/>
</div>
</APIProvider>
);
}
Three things trip people up:
- The map needs a height. A Google map's natural height is 0.
<Map>fills its parent (width: 100%; height: 100%), so the parent must have a size (Map docs). defaultCentervscenter.defaultCenter/defaultZoomset the start position and let the user pan freely.center/zoomare controlled props: if you pass them without updating state inonCameraChanged, the map snaps back after every drag.- One
APIProvider. Put it high in the tree, once. It loads the script a single time and every map and hook below it shares it.
In Next.js (App Router), the map is client-only. Put it in a file that starts with 'use client' and read the key from process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY.
Step 4: Add markers with AdvancedMarker
AdvancedMarker wraps Google's AdvancedMarkerElement. It only works on a map that has a mapId (AdvancedMarker docs). Create a real Map ID in the console under Map management before production.
import {APIProvider, Map, AdvancedMarker, Pin} from '@vis.gl/react-google-maps';
const offices = [
{id: 'nyc', name: 'New York', position: {lat: 40.7128, lng: -74.006}},
{id: 'bos', name: 'Boston', position: {lat: 42.3601, lng: -71.0589}},
];
export function OfficeMap() {
return (
<APIProvider apiKey={import.meta.env.VITE_GOOGLE_MAPS_API_KEY}>
<div style={{height: 500}}>
<Map mapId="DEMO_MAP_ID" defaultCenter={{lat: 41.5, lng: -73}} defaultZoom={7}>
{offices.map(o => (
<AdvancedMarker key={o.id} position={o.position} title={o.name}>
<Pin background="#0f9d58" borderColor="#006425" glyphColor="#ffffff" />
</AdvancedMarker>
))}
</Map>
</div>
</APIProvider>
);
}
Leave out <Pin> to get the default red marker, or pass any JSX (an <img>, a styled <div>) as children for a fully custom marker. For hundreds of markers, cluster them with @googlemaps/markerclusterer; the library's examples show how.
Step 5: Show an InfoWindow when a marker is clicked
Connect an InfoWindow to a marker with useAdvancedMarkerRef. Listen to onClose too, because the user can close the window with its built-in X, and your state needs to know about it (InfoWindow docs).
import {useState} from 'react';
import {AdvancedMarker, InfoWindow, useAdvancedMarkerRef} from '@vis.gl/react-google-maps';
export function MarkerWithInfo({position, name}: {position: google.maps.LatLngLiteral; name: string}) {
const [markerRef, marker] = useAdvancedMarkerRef();
const [open, setOpen] = useState(false);
return (
<>
<AdvancedMarker ref={markerRef} position={position} onClick={() => setOpen(o => !o)} />
{open && (
<InfoWindow anchor={marker} onClose={() => setOpen(false)}>
<strong>{name}</strong>
</InfoWindow>
)}
</>
);
}
Step 6: Places Autocomplete in React
Since March 1, 2025, the legacy google.maps.places.Autocomplete widget isn't available to new Google Cloud projects; Google moved it to legacy status. Use the new PlaceAutocompleteElement (docs). The library has no wrapper component for it, but useMapsLibrary('places') loads the Places library for you:
import {useEffect, useRef} from 'react';
import {useMap, useMapsLibrary} from '@vis.gl/react-google-maps';
export function PlaceSearch() {
const map = useMap();
const places = useMapsLibrary('places');
const container = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!places || !map || !container.current) return;
const input = new places.PlaceAutocompleteElement({includedRegionCodes: ['us']});
const onSelect = async (event: Event) => {
const {placePrediction} = event as google.maps.places.PlacePredictionSelectEvent;
const place = placePrediction.toPlace();
await place.fetchFields({fields: ['displayName', 'formattedAddress', 'location']});
if (place.location) {
map.panTo(place.location);
map.setZoom(15);
}
};
input.addEventListener('gmp-select', onSelect);
container.current.appendChild(input);
return () => {
input.removeEventListener('gmp-select', onSelect);
input.remove();
};
}, [places, map]);
return <div ref={container} />;
}
Render <PlaceSearch /> inside <APIProvider> and next to (or inside) a <Map>, so useMap() finds the map. Ask fetchFields only for the fields you need, because the fields you request decide which Places SKU you're billed for.
What the Google Maps API costs in a React app
The library is free; Google bills the API calls. On March 1, 2025, Google replaced the old $200 monthly credit with free usage per SKU (March 2025 changes). As of October 2026 (pricing):
| SKU | Free per month | Then (per 1,000) |
|---|---|---|
| Dynamic Maps (each map load) | 10,000 | $7.00 |
| Autocomplete Requests | 10,000 | $2.83 |
| Place Details Essentials | 10,000 | $5.00 |
| Maps Embed API (iframe) | Unlimited | Free |
Ways to keep the bill down in React:
- Don't re-create maps. Every new
google.maps.Mapcounts as a map load. If a map mounts and unmounts as users switch routes, add thereuseMapsprop to<Map>so instances get reused. - Debounce your own search inputs if you call autocomplete services directly. The widget handles session tokens for you.
- Set quotas and budget alerts in the Cloud console so a leaked key or a render loop can't run up a big bill.
- Use an iframe (Maps Embed API) if all you need is a static location map. It's free and needs no JS.
If Google's pricing doesn't fit, compare it with OpenStreetMap-based providers in DevHunt's list of free maps and geocoding APIs. For the plain-JavaScript side (geocoding, directions, Places web services), see our Google Maps API integration basics.
Common errors
- Blank grey area: the container has no height, or the key's website restriction doesn't include the current origin. Check the browser console for
RefererNotAllowedMapError. ApiNotActivatedMapError: enable Maps JavaScript API (or Places API (New)) in the same project as the key.- Markers don't show:
AdvancedMarkerwithout amapIdon the<Map>. - "This page can't load Google Maps correctly": billing isn't enabled on the project.
- Map jumps back after dragging: you passed controlled
center/zoomwithout anonCameraChangedhandler. UsedefaultCenter/defaultZoominstead.
More React tutorials that use free APIs: choosing an API for a React weather app, or browse API tools on DevHunt.
FAQ
What is the best React Google Maps library?
For new projects, @vis.gl/react-google-maps. The Google Maps Platform team started it, it supports Advanced Markers and the newer libraries through useMapsLibrary, and it's actively released. @react-google-maps/api still works and is widely used in older code.
Is react-google-maps free?
The npm packages are free and open source. The Google Maps API behind them is paid per use, with free usage per SKU each month (10,000 map loads on Dynamic Maps as of October 2026), and you need a billing account on the project.
How do I use the Google Maps API in React with TypeScript?
Install @vis.gl/react-google-maps. It includes the @types/google.maps types, so google.maps.LatLngLiteral, google.maps.places.Place and the rest are available globally. All examples in this guide are TSX.
Why do I need a Map ID?
Advanced Markers and cloud-based map styling only work on maps with a Map ID. Use DEMO_MAP_ID for testing, then create one in the Cloud console under Map management. You can style that Map ID in the console without changing code.
Can I use Google Maps in React Native?
Not with these libraries; they target the browser DOM. React Native apps usually use react-native-maps, which wraps the native Google Maps SDK on Android (and Apple Maps or Google Maps on iOS).