Skip to main content

Viewer location

createGlobe(canvas, { showViewer: true });

That pins the person looking at your page. No permission prompt, no network call, no API key, and it resolves instantly.

Loading globe…

How it works

Intl.DateTimeFormat().resolvedOptions().timeZone is available in every modern browser, requires no permission, and costs nothing. The package ships the IANA time-zone table: 312 zones and 237 aliases and maps the reported zone to its published coordinate.

const found = globe.locateViewer();
// {
// lat: 23.29, lon: 82.52,
// timeZone: "Asia/Kolkata", country: "IN",
// source: "timezone", accuracy: "region",
// accuracyMeters: 2242000
// }

:::note Legacy zone names are load-bearing Chrome commonly reports Asia/Calcutta, not Asia/Kolkata. Alias resolution is why this works for a large share of real users rather than silently failing. :::

It is a region, not a pinpoint

A time zone narrows someone to its area, and the tz database publishes one representative city per zone. Asia/Kolkata covers all of India, so a naive pin would sit confidently on Kolkata even for someone in Ahmedabad, 1,600 km away.

Two things prevent that:

Anchoring. For countries wider than 8°, the pin uses the country centroid instead of the zone's city, which roughly halves the average error. Smaller countries keep their real city: London stays London.

An uncertainty circle. The pin is surrounded by a dashed circle sized to the actual radius, so the graphic says somewhere in here rather than exactly here.

showViewer: {
anchor: "auto", // "country" | "timezone" to force it
accuracyCircle: true, // false to hide it
}

Asking for precision

const found = await globe.locateViewer({ precise: true });
globe.setViewerLocation(found);

This requests the browser's high-accuracy provider and reports the device's own accuracyMeters, so you can tell a 20 m GPS fix from a 40 km Wi-Fi one. If the visitor declines, it resolves to the time-zone estimate and never rejects.

PromptNetworkAlways worksTypical radius
Time zone (default)NoNoYesCountry-sized
Locale fallbackNoNoYesCountry-sized
precise, GPSYesNoOnly if allowed5-50 m
precise, Wi-Fi/IPYesYes (by the browser)Only if allowed1-50 km

:::caution On a desktop, "precise" often is not A laptop with no GPS falls back to network positioning, which frequently lands on your ISP's city. The reported accuracyMeters is the only way to tell: show it, or size a circle with it, rather than implying a street address. :::

Options

showViewer: {
emoji: "📍",
label: "You",
color: "#f97316",
live: true, // pulsing ring
anchor: "auto",
accuracyCircle: true,
accuracyColor: "#22c55e",
flyTo: true, // centre on them once located
ping: true, // fire a ping at their position
precise: false, // ask for GPS on construction
onLocate: (location) => track(location.country),
}

The pin lives outside the markers array, so setMarkers() never wipes it.

Standalone helpers

Useful without a globe at all:

import { locateViewer, timeZoneLocation, countryLocation, placeLocation } from "canvas-globe";

locateViewer(); // the full result
timeZoneLocation("Asia/Calcutta"); // → resolves the alias
countryLocation("IN");
placeLocation("New York");

Privacy

Nothing leaves the device. The time zone is read from the local Intl API and matched against a bundled table. There is no request, no third party, and nothing to disclose in a cookie banner: though if you send the result to your own analytics, that is your call to document.