Google Timeline Coordinate Parser: What Formats the `parse_coordinate` Function Handles
The parse_coordinate function in visualizer.py normalizes five distinct coordinate formats from Google Timeline exports: Android Takeout URIs, iOS Takeout strings, JSON objects with latLng or point keys, scaled micro-degree integers, and raw decimal strings—returning standard (lat, lon) tuples or None for invalid data.
Google Timeline exports vary significantly between Android and iOS devices, with additional variation between Takeout archives and direct device exports. The parse_coordinate utility function (lines 85–104 in visualizer.py) unifies these disparate formats into consistent floating-point coordinates. This article examines each supported format using the actual source code from the mahlernim/google-timeline-visualizer repository.
Android Takeout URI Format
Android Takeout exports frequently encode coordinates as geo-scheme URIs containing optional query parameters and formatting artifacts.
The function handles strings like:
parse_coordinate('geo:37.4219983,-122.084?z=15')
# → (37.4219983, -122.084)
The processing sequence stripps three components:
geo:prefix — removed viaremoveprefix('geo:')- Query string — everything after
?discarded usingsplit('?', 1)[0] - Degree symbols and whitespace — deleted with
replace('°', '').replace(' ', '')
iOS Takeout String Format
iOS exports omit the geo: scheme but may include degree symbols (°) and extra spacing:
parse_coordinate('37.4219983° , -122.084°')
# → (37.4219983, -122.084)
The same cleaning pipeline applies: degree symbols and whitespace removal, followed by comma-splitting to extract latitude and longitude values.
JSON Object Wrappers
Some Timeline exports embed coordinates in dictionary structures with either latLng or point keys:
parse_coordinate({'latLng': '37.4219983,-122.084'})
# → (37.4219983, -122.084)
parse_coordinate({'point': '37.4219983,-122.084'})
# → (37.4219983, -122.084)
As implemented in visualizer.py, the function checks isinstance(value, dict) and extracts the inner string via:
value = value.get('latLng') or value.get('point')
This dual-key support accommodates variations between Google Timeline export versions.
Scaled Integer Coordinates (Micro-Degrees)
Certain Android exports represent coordinates as integers scaled by 10,000,000 (micro-degrees) rather than floating-point decimals. The parse_coordinate function auto-detects this format:
parse_coordinate('374219983,-1220840000')
# → (37.4219983, -122.084)
The detection logic (lines 97–99 in visualizer.py) triggers when absolute values exceed 1,000,000:
if abs(lat) > 1_000_000 or abs(lon) > 1_000_000:
lat /= 10_000_000
lon /= 10_000_000
This automatic rescaling eliminates manual preprocessing for high-precision Android Timeline data.
Invalid Input Handling
The parse_coordinate function returns None for any input failing validation:
- Empty strings or non-string types
- Missing comma separators
- Non-numeric components
- Out-of-range coordinates: latitude outside
[-85.05112878, 85.05112878](Web-Mercator limits) or longitude outside[-180, 180]
parse_coordinate('invalid-coordinate') # → None
parse_coordinate('') # → None
parse_coordinate({'otherKey': 'value'}) # → None (no latLng or point)
Complete Implementation Reference
Here is the full parse_coordinate function from visualizer.py (lines 85–104) showing how Google Timeline coordinate formats are unified:
def parse_coordinate(value: Any) -> Optional[Tuple[float, float]]:
"""Parse coordinate values used by Android, iOS, and Takeout exports."""
if isinstance(value, dict):
value = value.get('latLng') or value.get('point')
if not isinstance(value, str) or not value.strip():
return None
cleaned = value.strip().removeprefix('geo:').split('?', 1)[0]\
.replace('°', '').replace(' ', '')
parts = cleaned.split(',')
if len(parts) < 2:
return None
try:
lat, lon = float(parts[0]), float(parts[1])
except ValueError:
return None
if abs(lat) > 1_000_000 or abs(lon) > 1_000_000:
lat /= 10_000_000
lon /= 10_000_000
if not (-85.05112878 <= lat <= 85.05112878 and -180 <= lon <= 180):
return None
return lat, lon
Supported Format Summary Table
| Format | Example Input | Output |
|---|---|---|
| Android geo-URI | 'geo:37.4219983,-122.084?z=15' |
(37.4219983, -122.084) |
| iOS decorated string | '37.4219983° , -122.084°' |
(37.4219983, -122.084) |
latLng object |
{'latLng': '37.4219983,-122.084'} |
(37.4219983, -122.084) |
point object |
{'point': '37.4219983,-122.084'} |
(37.4219983, -122.084) |
| Micro-degree integers | '374219983,-1220840000' |
(37.4219983, -122.084) |
| Invalid/missing data | 'invalid' or {} |
None |
Testing and Validation
The project's test suite in tests/test_parser.py verifies correct behavior across all supported Google Timeline coordinate formats. Running these tests ensures compatibility with new export variations as Google's formats evolve.
Summary
- Five input types: Android Takeout URIs, iOS strings,
latLng/pointJSON objects, micro-degree integers, and raw decimal strings - Automatic normalization: prefix stripping, query removal, degree symbol cleaning, and scaled-integer detection
- Robust validation: Web-Mercator latitude bounds and global longitude limits with
Nonereturn for invalid data - Single function interface:
parse_coordinateinvisualizer.pyhandles all Google Timeline export variations without caller-side preprocessing
Frequently Asked Questions
What Google Timeline exports use the geo: URI prefix?
Android Takeout archives typically wrap coordinates in geo:latitude,longitude format, often followed by query parameters like ?z=15 for zoom level. The parse_coordinate function automatically strips these components to extract raw coordinate values.
How does the parser handle iOS export differences?
iOS Timeline exports omit the geo: scheme but frequently include degree symbols (°) and irregular spacing. The function applies identical cleaning operations—removing ° and whitespace—so both Android and iOS strings normalize to the same output format.
What happens when coordinates are stored as integers?
Some Android exports use micro-degree encoding (values multiplied by 10,000,000). When parse_coordinate detects values exceeding 1,000,000 in magnitude, it automatically divides by 10,000,000 to convert to standard decimal degrees without requiring manual intervention.
Why does the function enforce Web-Mercator latitude limits?
The latitude bound of ±85.05112878° matches the mathematical limits of the Web-Mercator projection used by most mapping libraries. Coordinates outside this range or with longitude beyond ±180° return None, preventing downstream visualization errors in tools like Folium or Leaflet.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →