How to Process E7 Integer Coordinates in Google Timeline Data

The google-timeline-visualizer detects E7 integer coordinates by checking if values exceed 1,000,000 and divides them by 10⁷ to normalize them into standard decimal degrees.

Google Timeline exports often store latitude and longitude as E7 integers—values multiplied by 10⁷ (10 million)—particularly in Android and iOS Takeout files. The mahlernim/google-timeline-visualizer repository handles this conversion automatically through its core parsing logic, ensuring consistent coordinate representation regardless of the export format.

Understanding the E7 Coordinate Format

E7 is a fixed-point integer representation used by mobile GPS systems to store geographic coordinates without floating-point precision issues. In this format, 37.5° becomes 375000000 and 127.0° becomes 1270000000. The visualizer must detect these scaled integers and convert them back to decimal degrees for mapping and analysis.

According to the source code in visualizer.py, the normalization logic resides in the parse_coordinate helper function (lines 42-61), which serves as the primary entry point for all coordinate processing.

The parse_coordinate Implementation

The parse_coordinate function implements a robust pipeline for handling heterogeneous Google Timeline data.

Input Normalization and Cleaning

Before detecting the coordinate format, the function sanitizes inputs to handle various export variants:

  • Removes the geo: URI prefix commonly found in Google location strings
  • Strips whitespace and the degree symbol (°) from coordinate strings
  • Discards query parameters that appear after ? characters
  • Handles dictionary inputs containing latLng or point fields

This preprocessing ensures that strings like "geo:37.5,127.0?z=15" and "37.5°, 127.0°" both resolve to clean comma-separated values.

E7 Detection and Conversion Logic

The critical detection heuristic appears in the conversion phase:

  1. The function splits the cleaned string into latitude and longitude components
  2. It converts both values to float for comparison
  3. If either component's absolute value exceeds 1,000,000, the function assumes E7 encoding
  4. Both values are divided by 10,000,000 (10⁷) to yield decimal degrees

This threshold-based approach works because legitimate decimal degree coordinates never exceed 180.0, while E7 values always exceed 1 million for any realistic geographic location.

Range Validation

After conversion, the function enforces geographic bounds according to Web Mercator projection limits:

  • Latitude must fall within ±85.05112878 degrees
  • Longitude must fall within ±180 degrees

Coordinates outside these ranges return None, filtering out corrupted or malformed Timeline entries.

Supported Input Format Variations

The parser handles three distinct input types common in Google exports:

Raw comma-separated strings

parse_coordinate("37.5,127.0")        # Returns (37.5, 127.0)

parse_coordinate("375000000,1270000000")  # Returns (37.5, 127.0)

Geo URI format

parse_coordinate("geo:37.5,127.0")    # Returns (37.5, 127.0)

Dictionary structures

parse_coordinate({"latLng": "37.5,127.0"})  # Returns (37.5, 127.0)

Practical Code Examples

As verified by the test suite in tests/test_parser.py (lines 85-90), the following patterns demonstrate proper E7 handling:

from visualizer import parse_coordinate

# Standard decimal degrees (already normalized)

assert parse_coordinate("37.5,127.0") == (37.5, 127.0)

# E7 integer representation from mobile exports

# 375000000 represents 37.5°, 1270000000 represents 127.0°

assert parse_coordinate("375000000,1270000000") == (37.5, 127.0)

# Geo URI with optional query parameters

assert parse_coordinate("geo:37.5,127.0?time=123456") == (37.5, 127.0)

# Invalid latitude exceeding Web Mercator limits

assert parse_coordinate("91,127") is None

# Null or empty input handling

assert parse_coordinate(None) is None

Summary

  • E7 coordinates are 10⁷-scaled integers used in Android/iOS Google Timeline exports to preserve precision
  • The parse_coordinate function in visualizer.py (lines 42-61) automatically detects E7 format by checking if absolute values exceed 1,000,000
  • Normalization divides detected E7 values by 10,000,000 to convert them to decimal degrees
  • The parser supports multiple input formats including raw strings, geo: URIs, and dictionary objects
  • Range validation ensures coordinates conform to Web Mercator bounds (±85.05112878° latitude, ±180° longitude)

Frequently Asked Questions

What exactly are E7 coordinates in Google Timeline data?

E7 coordinates are latitude and longitude values multiplied by 10⁷ (10 million) and stored as integers. This format eliminates floating-point precision errors in JSON exports and is commonly used in Android and iOS Takeout files. For example, the coordinate 37.5° becomes the integer 375000000.

How does the visualizer distinguish between E7 and regular decimal degrees?

The parse_coordinate function checks if the absolute value of either coordinate component exceeds 1,000,000. Since valid decimal degrees never exceed 180.0, any value above this threshold is treated as an E7 integer and divided by 10,000,000 to normalize it.

What happens if I pass coordinates with a "geo:" prefix or degree symbols?

The parser automatically cleans inputs by removing the geo: prefix, stripping whitespace, discarding degree symbols (°), and ignoring query parameters after ? characters. This ensures that variations like "geo:37.5,127.0" and "37.5°, 127.0°" are processed correctly.

What does the function return for invalid coordinates?

If coordinates fall outside the valid Web Mercator range (latitude beyond ±85.05112878 or longitude beyond ±180), or if the input is malformed, parse_coordinate returns None rather than raising an exception. This allows the visualizer to skip corrupted Timeline entries gracefully.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →