If you have written any code that talks to a map library, you have written code that touches the viewport. The viewport is the runtime state of the map: where it is centred, how far it is zoomed in, which way it is pointing, and optionally how much it is tilted. Every pan, zoom, rotate, and click depends on it.
This guide explains what a viewport actually is, the four core values that describe it, how it interacts with tiles and bounding boxes, and the production patterns for saving, restoring, and sharing viewport state.
The Four Core Values
A modern web-map viewport is described by up to four values:
- Center (
{ lat, lng }): the geographic coordinate at the middle of the screen. - Zoom (a number, often a float): how far the map is zoomed in. Higher numbers show smaller areas in more detail.
- Bearing (a number in degrees, default 0): the rotation of the map from "north up". 90 means east is up.
- Pitch (a number in degrees, 0 to ~85): the 3D tilt. 0 is flat top-down, 60 is a strong perspective view.
Every modern map library (MapLibre GL, Mapbox GL, OpenLayers, Leaflet, MapAtlas Dynamic Maps) exposes these as readable and writable state. A 2D-only library like Leaflet may not expose bearing or pitch.
Zoom Levels in Detail
Zoom level is the most-asked-about of the four. It is an integer (or fractional) number that maps the world to a tile pyramid:
- Zoom 0: entire world in one 256x256 tile
- Zoom 1: world split into 4 tiles
- Zoom 2: 16 tiles
- ...
- Zoom 14: ~268 million tiles, neighbourhood scale
- Zoom 18: building scale
- Zoom 22+: usually rendered with vector style upscaling rather than fresh tile data
A useful rule of thumb at the equator: each zoom level increase halves the visible width on screen. At zoom 14, one screen typically shows a few city blocks. At zoom 10, a metropolitan area. At zoom 6, a country. The effective resolution depends on screen size and the projection (Web Mercator distorts north-south as you move toward the poles).
Most production code stores zoom as a float (e.g. 14.5) because smooth zooming animations interpolate between integer zooms. Tile fetches happen at the integer level rounded down or up, depending on library convention.
Viewport vs Bounding Box
A viewport is camera state. A bounding box is the geographic rectangle currently visible. You compute the bbox from the viewport every time you need to ask the server "what should I show inside this view?".
In code:
const bbox = map.getBounds(); // returns { _sw: {lat, lng}, _ne: {lat, lng} }
const params = new URLSearchParams({
bbox: `${bbox._sw.lng},${bbox._sw.lat},${bbox._ne.lng},${bbox._ne.lat}`,
});
const features = await fetch(`/api/places?${params}`).then(r => r.json());
This pattern (compute bbox from viewport, send to server, render returned features) is the heartbeat of every viewport-based search experience: real estate, listings, store locators, fleet tracking, ride-share.
How the Viewport Drives Tile Loading
When the viewport changes, the map library figures out which tiles cover the new visible area at the current zoom level, fetches any missing tiles from the server (or its in-memory cache), and renders them. Tiles already cached are reused; tiles outside the viewport are kept around in case the user pans back.
A smooth pan and zoom feels seamless because the library is doing this work asynchronously: it draws what it has, fetches what it needs, and updates the canvas as new tiles arrive. Vector tile pipelines do extra work to render geometry to pixels on the GPU, which is why modern web maps stay sharp at any zoom and rotation.
Saving and Sharing Viewport State
Storing the viewport in the URL is the standard pattern for shareable map links. Most products use a URL hash like #map=14.5/52.5200/13.4050 (zoom, lat, lng). On page load, parse the hash and apply the viewport. On viewport change, debounce a few hundred milliseconds and update the hash so the browser back button stays useful.
For browser-internal state across tabs or sessions, a localStorage key with the same shape works. For server-rendered pages, the viewport often shows up as query params for SEO-friendly URLs (?zoom=14&lat=52.52&lng=13.405).
Viewport Bias for Search and Autocomplete
Geocoding APIs accept the viewport (or its bbox) as a bias parameter. MapAtlas exposes boundary.rect.* for a hard filter and focus.point.* for a soft bias. Without a bias, autocomplete for "Springfield" returns whichever Springfield is most globally popular. With a viewport bias, the user typing inside their map of Massachusetts gets Massachusetts results first.
Apply this bias on every keystroke. The cost is one parameter and significantly more relevant suggestions.
Initial Viewport: Where to Start
The first thing every map app has to decide is where to start. Common patterns:
- Default to the user's locale: a user in Germany lands at a viewport over Berlin, a user in France over Paris.
- Default to the user's last viewport: persist viewport across sessions.
- Default to the data: if your map shows search results, fit the bbox of those results on initial render.
- Default to the user's IP geolocation: low precision, no permission required, good fallback.
- Ask for browser geolocation only when the user explicitly opts in: never on first load without UI consent.
Picking a sensible initial viewport is a small detail with a big effect on perceived quality.
How MapAtlas Exposes Viewport State
The MapAtlas Dynamic Maps component exposes the same getCenter, getZoom, getBearing, getPitch, and setView API every developer-grade web map provides, with the addition of EU-only hosting and consistent viewport bias parameters across the Geocoding and Search endpoints. For a deeper look at how viewport interacts with tiles and projections, see What Is a Vector Tile and What Is Web Mercator.
Frequently Asked Questions
What is a map viewport?
A map viewport is the visible window of a map: the geographic area currently displayed on screen, described by a center coordinate (latitude and longitude), a zoom level (how far in or out the map is), and optionally a bearing (rotation) and pitch (3D tilt). Every modern web map (Google Maps, MapLibre, Mapbox GL, MapAtlas) exposes the viewport as state you can read and set programmatically. The viewport changes every time the user pans, zooms, rotates, or tilts the map.
What is a zoom level?
Zoom level is an integer (or fractional) number that controls how much of the world is visible in a fixed-size tile. Zoom 0 fits the entire world in a single 256x256 tile. Each subsequent zoom level doubles the resolution: zoom 1 has 4 tiles, zoom 2 has 16, and so on. Zoom 14 is roughly neighbourhood scale, zoom 18 is roughly building scale. Most production maps support zoom levels from 0 to 22 or beyond, although the underlying tiles only exist up to a certain zoom and are oversampled or up-resolved past that.
What is the difference between viewport and bounding box?
A viewport is the camera state (center, zoom, bearing, pitch). A bounding box is the geographic rectangle that the camera currently shows. You compute the bbox from the viewport: given a center, zoom, and screen size, the map library calculates which lat/lng rectangle is visible. The bbox is what you pass to the geocoding API as a viewport bias, what you query the database with for visible features, and what you log when you want to know what the user was looking at.
How do I save and restore a map viewport?
Serialise the four core values (center latitude, center longitude, zoom, bearing if you support rotation) into the URL or local storage. A common pattern is a hash like #map=14.5/52.5200/13.4050 for zoom 14.5 at the center of Berlin. On page load, parse the hash and call map.setView(...) or map.flyTo(...). MapAtlas, MapLibre, and Mapbox GL all expose a getCenter / getZoom / getBearing API and a setView equivalent, so this round-trip is one helper function in any production codebase.

