Reference

The on-device Timeline.json format: a field reference

Updated August 2026 · 8 min read

Since the 2024 migration, the only Google Maps location history you can export yourself comes off the handset as a file called Timeline.json. It is not the format Google Takeout used to hand out, it is not documented by Google, and it is not the same on Android as it is on iOS. This page is the field reference for it.

What this does not cover, and where to go instead. The reference for the older Google Takeout exports — Records.json, Settings.json, Timeline Edits.json and the Semantic Location History — is locationhistoryformat.com, and it is more thorough on those than this page will ever be. Its last update is dated March 2024, which is before the on-device export existed, so the shapes below are the part it leaves open. Use both.

Three shapes, not one

A parser that has to accept whatever a user drops on it is dealing with three distinct documents. The first is the legacy Takeout export, which is still what you get for pre-migration history. The other two are the on-device export, which differs by platform.

ShapeRootWhere it comes from
Legacy TakeoutObject with timelineObjectstakeout.google.com, pre-migration history only
Android on-deviceObject with semanticSegmentsSettings → Location → Location services → Timeline → Export Timeline data
iOS on-deviceA bare JSON arrayGoogle Maps app → profile picture → Settings → Location & Privacy

Telling them apart

Detect on the root, not on a field. Android gives you a key to look for; iOS gives you nothing — the array is the whole document, so there is no wrapper to test. The check that works is: does the root carry semanticSegments, or is the root an array whose elements look like segments?

"Look like segments" needs a real test, because a bare array is also what a plain row table looks like — and a row table is flat, every value a scalar, which is the cheapest way to rule it out. What marks a segment is a string startTime together with at least one of visit, activity or timelinePath. Note that timelinePath counts: a file can open on breadcrumbs before any trip appears, and a test that insists on a visit or an activity rejects it. Sample the first few elements rather than the first one.

One archive, many shapes. A Takeout ZIP holds files from every product you selected, and the first JSON in the archive says nothing about the hundreds behind it. Sniff each file, and when you report on a format, report the shape of the largest file rather than the first — we had a bug report carrying the shape of one file out of 997.

The same record, written two ways

Both on-device shapes agree on the outline: an array of segments, each with startTime, endTime, and either a visit or an activity, each of those holding a topCandidate. The differences are all in the leaves, and they are the reason a parser written against one platform returns nothing on the other.

WhatAndroidiOS
Place identifierplaceIdplaceID
Visit coordinatesplaceLocation.latLngplaceLocation, a string
Coordinate encoding"45.4642°, 9.1900°""geo:45.4642,9.1900"
Trip endpointsactivity.start.latLngactivity.start, a string
distanceMetersNumber: 3850String: "3850"
Breadcrumb timingtime, absolute ISO 8601durationMinutesOffsetFromStartTime, a string of minutes
Also seeneditConfirmationStatus, isTimelessVisithierarchyLevel, probability repeated outside topCandidate

The placeId / placeID split is the one that costs the most time, because no other field in the record changes case between platforms, so nothing else primes you to look for it.

Coordinates: three encodings, one rule

Across the three shapes a coordinate pair arrives in one of three ways:

ShapeEncodingExample
Legacy TakeoutTwo integers, scaled by 107"latitudeE7": 454225900
Android on-deviceDecimal pair with degree signs"latLng": "45.4642°, 9.1900°"
iOS on-devicegeo: URI"geo:45.4642,9.1900"

One reader covers both on-device forms: accept either a string or an object carrying latLng, strip a leading geo:, split on the comma, strip the degree sign, and parse each half as a float. Reject the pair unless both halves come back finite — a half-parsed coordinate is worse than none, because it lands somewhere plausible.

The legacy form needs its own path: divide each E7 integer by 107. Two things bite here. First, a place visit writes the pair as centerLatE7 and centerLngE7 rather than latitudeE7 and longitudeE7, so a reader that only knows the latter silently loses every visit. Second, and worse:

Takeout sometimes ships a negative E7 coordinate wrapped as an unsigned 32-bit integer, so it arrives as the true value plus 232. Every southern latitude and western longitude in the file can land on the wrong continent, and the number looks perfectly well-formed.

A wrap is therefore always a large positive number, never a large negative one, and the only ceiling that detects it is the coordinate's own: 90° and 180°, which in E7 are 900,000,000 and 1,800,000,000. Above the ceiling, subtract 232. Judge each axis on its own value — a wrapped longitude says nothing about whether the latitude wrapped, and treating the pair as one unit corrupts the half that was fine.

timelinePath is not extra distance

Both on-device shapes carry timelinePath, an array of raw breadcrumbs. On a real export it is the bulk of the file by volume, and it is tempting to treat it as more trips.

It is not. A timelinePath retraces the same ground the activity segments already describe, so anything that sums both double-counts every kilometre. Take distance from the activity segments; treat the path as detail for drawing a line on a map. If you are counting records to detect a format change — which is worth doing — count paths separately, or they drown the counter.

A segment can also carry a timelinePath with no activity beside it. Those are breadcrumbs Google never resolved into a trip: real movement, no claimable distance, and no start or end place.

Where the legacy distance hides

For the legacy Takeout shape, an activitySegment may carry its distance in any of four fields, and usually only one of them is present:

FieldTypically when
waypointPath.distanceMetersA route Google reconstructed through waypoints
simplifiedRawPath.distanceMetersA simplified trace of the raw points
transitPath.distanceMetersPublic transport
distanceA plain total, no path attached

Reading only the first of these loses a substantial share of trips, silently, and the loss is not evenly spread — it follows how each trip happened to be recorded.

Other things worth knowing before you start

Time-mile reads all three shapes in the browser — the Takeout ZIP, the Android Timeline.json, the iOS array — resolves the coordinates to street addresses, and exports a mileage log. Your file never leaves your machine.

Launch Time-mile

Frequently asked questions

How do I tell an Android Timeline.json from an iPhone one?

By the root of the document, not by any field inside it. Android wraps the segments in an object under a semanticSegments key. iOS ships the array on its own, with no wrapper key at all, so there is no key to look for — you have to test whether the root is an array and whether its elements look like segments.

Why does my parser find no coordinates in an iPhone export?

Because iOS puts the coordinate string directly on placeLocation, while Android nests it one level deeper under a latLng key. Reading placeLocation.latLng returns undefined on every iOS record. The encodings differ too: iOS writes a geo: URI, Android writes a decimal pair carrying degree signs.

Is placeId or placeID the correct spelling?

Both, depending on the platform. Android writes placeId with a lowercase d, iOS writes placeID with a capital D. The same is true of no other field in the record, which is what makes it easy to miss.

Can I add up the distances in timelinePath to get a total?

No. A timelinePath is the raw breadcrumb trail underneath the trips, so it retraces the same ground the activity segments already cover. Summing both double-counts every kilometre. Use the activity segments for distance and treat timelinePath as detail.

Does locationhistoryformat.com cover this format?

No. It is the reference for the Google Takeout exports — Records.json, Settings.json, Timeline Edits.json and Semantic Location History — and its last update is dated March 2024, before the on-device export existed. It remains the better reference for anything that came out of Takeout.

Where does the distance live in a legacy Takeout activitySegment?

In one of four places, and usually only one of them is present: waypointPath.distanceMeters, simplifiedRawPath.distanceMeters, transitPath.distanceMeters, or a plain distance field. Which one appears depends on how the trip was recorded.