# Google Timeline Coordinate Parser: What Formats the `parse_coordinate` Function Handles

> Discover the five coordinate formats the parseCoordinate function handles from Google Timeline exports including URIs JSON objects and more returning standard lat lon tuples or None for invalid data

- Repository: [mahlernim/google-timeline-visualizer](https://github.com/mahlernim/google-timeline-visualizer)
- Tags: api-reference
- Published: 2026-08-23

---

**The `parse_coordinate` function in [`visualizer.py`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/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`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/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](https://github.com/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:

```python
parse_coordinate('geo:37.4219983,-122.084?z=15')

# → (37.4219983, -122.084)

```

The processing sequence stripps three components:

- **`geo:` prefix** — removed via `removeprefix('geo:')`
- **Query string** — everything after `?` discarded using `split('?', 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:

```python
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:

```python
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`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/visualizer.py), the function checks `isinstance(value, dict)` and extracts the inner string via:

```python
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:

```python
parse_coordinate('374219983,-1220840000')

# → (37.4219983, -122.084)

```

The detection logic (lines 97–99 in [`visualizer.py`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/visualizer.py)) triggers when absolute values exceed 1,000,000:

```python
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]`

```python
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`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/visualizer.py) (lines 85–104) showing how Google Timeline coordinate formats are unified:

```python
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`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/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`/`point` JSON 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 `None` return for invalid data
- **Single function interface**: `parse_coordinate` in [`visualizer.py`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/visualizer.py) handles 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.