Overview
Before this update, the Geographies page was a flat layout showing a static world map and a locations table. There was no way to explore member distribution interactively, and the device or visit analytics sections were entirely simulated with hardcoded placeholder data.
The page has been redesigned into three distinct tabs — World Map, Devices, and Visits — all scoped to the current team and backed by live Convex queries. A new pageViews table records every authenticated visit, enabling real device and traffic analytics that grow naturally as the platform is used.
World Map tab — zoom and explore
The world map is now zoomable. Built with react-simple-maps and its ZoomableGroup component, users can zoom in up to 12× using the +, −, and ⊙ buttons overlaid on the top-right corner of the map, or drag to pan around the canvas. Marker size scales inversely with zoom level so pins remain readable at any zoom.
Member location pins are sourced from the locations Convex table. Hovering a pin shows a tooltip with the member's name, city, and country. Below the map, the existing member locations table and top-countries breakdown remain in this tab, so all geographic context is in one place.
Admins can pin a new member location using the + Add location button, which opens a dialog to select a member, choose a country from the ISO reference list (pre-populated with lat/lng coordinates), and optionally enter a city name.
Devices tab — real session analytics
Every time an authenticated user opens the Geographies page, the client records a page view via the pageViews.record Convex mutation. Device type is detected from window.innerWidthat mount time — viewports 768 px and wider are classified as desktop; narrower viewports as mobile.
The Devices tab queries pageViews.monthlyByDevice, which aggregates all records for the team in the current calendar year into 12 monthly buckets, splitting counts by device type. The result drives two stat cards (YTD desktop and mobile totals), a grouped bar chart comparing the two device types month by month, and a stacked area chart showing the share split over time.
Visits tab — monthly traffic volume
The Visits tab queries pageViews.monthlyVisits, collapsing device type to produce simple monthly visit totals for the current year. Two headline stat cards show YTD visits and the current month's count, followed by a smoothed area chart plotting the full year's traffic curve.
Both analytics queries enforce the same access control as other team-scoped queries — platform owners see data for any team, while regular users must hold an active membership for the requested team.
Data model additions
Two new Convex tables were added:
- locations — stores
teamId,memberId, city, country, ISO country code, and lat/lng coordinates. Theupsertmutation uses aby_team_memberindex to ensure each member has at most one location per team. - pageViews — stores
teamId,userId,device(“desktop” | “mobile”), andtimestamp. Indexed by team and by team + timestamp for efficient range queries.
What's next
With real visit data now being collected, the next iteration will add session-level tracking (duration, bounce rate) and extend analytics coverage to other dashboard pages beyond Geographies. The world map will gain cluster aggregation to handle teams with large numbers of closely-grouped member locations.