1"use strict";(globalThis.webpackChunkdawarich_app=globalThis.webpackChunkdawarich_app||[]).push([[5183],{66575(e,i,t){t.r(i),t.d(i,{assets:()=>l,contentTitle:()=>a,default:()=>d,frontMatter:()=>r,metadata:()=>o,toc:()=>c});var o=t(50706),s=t(74848),n=t(28453);const r={slug:"building-a-privacy-first-google-timeline-visualizer",title:"Building a Privacy-First Google Timeline Visualizer",authors:"evgenii",tags:["tools"]},a="Building a Privacy-First Google Timeline Visualizer",l={authorsImageUrls:[void 0]},c=[{value:"The Problem: Google's Timeline Limitations",id:"the-problem-googles-timeline-limitations",level:2},{value:"Privacy-First Architecture",id:"privacy-first-architecture",level:2},{value:"How It Works",id:"how-it-works",level:2},{value:"Handling Massive Files",id:"handling-massive-files",level:3},{value:"Supported Formats",id:"supported-formats",level:2},{value:"Features",id:"features",level:2},{value:"Limitations",id:"limitations",level:2},{value:"Getting Your Data",id:"getting-your-data",level:2},{value:"When You Need More",id:"when-you-need-more",level:2},{value:"Technical Stack",id:"technical-stack",level:2},{value:"Future Improvements",id:"future-improvements",level:2},{value:"Try It Yourself",id:"try-it-yourself",level:2},{value:"Resources & Credits",id:"resources--credits",level:2}];function h(e){const i={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",hr:"hr",li:"li",ol:"ol",p:"p",strong:"strong",ul:"ul",...(0,n.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(i.p,{children:"Google Timeline has been tracking your location history for years, quietly collecting data about everywhere you've been. But what happens when you export that data? You get one or multiple JSON files that... well, most people have no idea what to do with them."}),"\n",(0,s.jsxs)(i.p,{children:["That's why we built the ",(0,s.jsx)(i.a,{href:"https://dawarich.app/tools/timeline-visualizer",children:"Google Timeline Visualizer"})," \u2014 a free, privacy-first tool that turns those cryptic JSON files into an interactive map you can actually explore."]}),"\n",(0,s.jsx)(i.h2,{id:"the-problem-googles-timeline-limitations",children:"The Problem: Google's Timeline Limitations"}),"\n",(0,s.jsxs)(i.p,{children:["Google recently made some controversial changes to Timeline. They killed the web-based timeline browser, moved all data to mobile devices, ",(0,s.jsx)(i.a,{href:"https://www.reddit.com/r/GoogleMaps/comments/1diivt3/megathread_google_maps_timeline_moving_to/",children:"lost years of users' data in the process"}),", and started limiting how long your location history is stored. If you want to keep your data or visualize it properly, you're basically on your own."]}),"\n",(0,s.jsx)(i.p,{children:"When you export your Google Timeline data through Takeout or from your phone, you get JSON files \u2014 sometimes hundreds of megabytes worth. These files contain years of location data, place visits, and activity segments, but there's no easy way to visualize them without uploading to yet another third-party service."}),"\n",(0,s.jsx)(i.p,{children:"We needed a solution that was fast, secure, and most importantly: kept your data private."}),"\n",(0,s.jsx)(i.h2,{id:"privacy-first-architecture",children:"Privacy-First Architecture"}),"\n",(0,s.jsx)(i.p,{children:"Location data is incredibly sensitive. It shows where you live, where you work, where you go for medical appointments, who you visit, and your daily routines. Uploading this to a random web service is a huge privacy risk (except for Dawarich Cloud haha)."}),"\n",(0,s.jsxs)(i.p,{children:["That's why our visualizer runs ",(0,s.jsx)(i.strong,{children:"entirely in your browser"}),". When you upload your JSON files:"]}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.strong,{children:"Nothing is sent to any server"})," \u2014 all processing happens locally on your device"]}),"\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.strong,{children:"No tracking or analytics"})," on your location data"]}),"\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.strong,{children:"Your data stays in your browser's memory"})," and disappears when you close the tab"]}),"\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.strong,{children:(0,s.jsx)(i.a,{href:"https://github.com/dawarich-app/site/blob/main/src/components/TimelineMap.js",children:"Open source and transparent"})})," \u2014 you can verify exactly what the code does"]}),"\n"]}),"\n",(0,s.jsx)(i.p,{children:"This approach means your location history never leaves your computer. It's the digital equivalent of opening a paper map in your living room instead of mailing it to a stranger."}),"\n",(0,s.jsx)(i.h2,{id:"how-it-works",children:"How It Works"}
1),"\n",(0,s.jsx)(i.p,{children:"The visualizer follows a straightforward process:"}),"\n",(0,s.jsxs)(i.ol,{children:["\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.strong,{children:"Upload Your Files"})," \u2014 Drop your Google Timeline JSON files into the browser"]}),"\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.strong,{children:"Auto-Detection"})," \u2014 The tool automatically identifies the format (Records.json, Semantic Timeline, Location History, etc.)"]}),"\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.strong,{children:"Progressive Processing"})," \u2014 Files are parsed in batches to keep your browser responsive"]}),"\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.strong,{children:"Interactive Map"})," \u2014 Points and paths appear on the map using Leaflet and OpenStreetMap"]}),"\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.strong,{children:"Year Filtering"})," \u2014 Filter by year to explore specific time periods without overwhelming your browser"]}),"\n"]}),"\n",(0,s.jsx)(i.p,{children:"The entire process happens in JavaScript running in your browser. For a 170 MB file with 630,000 location points, processing takes about 20-30 seconds on a modern computer."}),"\n",(0,s.jsx)(i.h3,{id:"handling-massive-files",children:"Handling Massive Files"}),"\n",(0,s.jsx)(i.p,{children:"One of the biggest technical challenges was performance. Google exports can contain hundreds of thousands of GPS points. Loading all of them at once would crash most browsers."}),"\n",(0,s.jsx)(i.p,{children:"We solved this with several optimizations:"}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"Batch Processing"})," \u2014 Points are streamed to the map in batches of 5,000, yielding control to the browser between batches. This keeps the UI responsive even while processing massive datasets."]}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"Year-Based Pagination"})," \u2014 The visualizer calculates how many points exist in each year, then defaults to showing only the earliest year. Users can switch between years or view all data at once. This typically reduces the initial render from 600k+ points to 40-60k points."]}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"Incremental Rendering"})," \u2014 When switching years, only the new points are added to the map. The library handles clustering and de-duplication automatically."]}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"Lazy Popups"})," \u2014 Instead of generating HTML for 600k popups upfront, popup content is created only when you click on a marker."]}),"\n",(0,s.jsx)(i.p,{children:"These optimizations mean you can visualize years of location history without your browser grinding to a halt."}),"\n",(0,s.jsx)(i.h2,{id:"supported-formats",children:"Supported Formats"}),"\n",(0,s.jsx)(i.p,{children:"Google exports location data in several different formats depending on when and how you export it. The visualizer supports all of them:"}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"Records.json"})," \u2014 Raw GPS location records in E7 coordinate format. This is the oldest format and typically the largest file, containing every GPS ping Google recorded."]}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"Semantic Timeline (YYYY_MONTH.json)"})," \u2014 Monthly files containing place visits and activity segments. These are more structured and include information about what you were doing (walking, driving, etc.) and which places you visited."]}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"Location History (from phone)"})," \u2014 The newer format exported directly from Google Maps on Android or iOS. This uses a different JSON structure with ",(0,s.jsx)(i.code,{children:"semanticSegments"})," and timeline paths."]}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"Semantic Segments"}),' \u2014 A processed format with geographic coordinates in "geo',":lat",',lng" string format, often created by parsing raw exports with tools like ',(0,s.jsx)(i.code,{children:"jq"}),"."]}),"\n",(0,s.jsx)(i.p,{children:"No matter which format Google gives you, the visualizer will detect it automatically and extract:"}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsx)(i.li,{children:"GPS coordinates and timestamps"}),"\n",(0,s.jsx)(i.li,{children:"Place visits with duration"}),"\n",(0,s.jsx)(i.li,{children:"Activity segments (walking, driving, cycling)"}),"\n",(0,s.jsx)(i.li,{children:"Activity paths showing your actual route"}),"\n"]}),"\n",(0,s.jsx)(i.h2,{id:"features",children:"Features"}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"Interactive Map"})," \u2014 Pan, zoom, and explore your location history on an OpenStreetMap base layer. Markers show individual locations, while colored polylines show your movement paths."]}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"Smart Filtering"})," \u2014 The side panel shows only meaningful visits and places, not every GPS ping. For a Records.json file with 600k raw points, the list shows only actual place visits \u2014 making it useful instead of overwhelming."]}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"Year Selector"})," \u2014 Filter by year to focus on specific time periods. The dropdown shows how many points exist in each year, making it easy to explore your data chronologically."]}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"Auto-Fit Bounds"})," \u2014 When you switch years, the map automatically zooms to show all points for that period. Traveled from Europe to the USA in different years? The map adapts to each dataset."]}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"Dark Mode"})," \u2014 Full support for light and dark themes with proper contrast."]}),"\n",(0,s.jsx)(i.h2,{id:"limitations",children:"Limitations"}),"\n",(0,s.jsx)(i.p,{children:"Bigger files take time to process. A 170 MB file with hundreds of thousands of points needs 20-30 seconds to parse and render. This happens once when you first load the file."}),"\n",(0,s.jsx)(i.p,{children:"Browser memory limits apply. While we've tested files with 600k+ points across 15 years successfully, extremely large exports (multiple years, multiple large files) might struggle on older computers with limited RAM."}),"\n",(0,s.jsx)(i.p,{children:"The visualizer shows your data but doesn't edit it. If you want to keep your location history accessible, export it to formats like GPX, or store it long-term, you'll need additional tools."}),"\n",(0,s.jsx)(i.h2,{id:"getting-your-data",children:"Getting Your Data"}),"\n",(0,s.jsx)(i.p,{children:"The visualizer includes detailed instructions for exporting your Google Timeline data:"}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"Google Takeout"})," \u2014 Visit ",(0,s.jsx)(i.a,{href:"https://takeout.google.com",children:"takeout.google.com"}),", select \"Location History (Timeline)\", and export. Note that this method doesn't work for everyone due to Google's policy changes."]}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"Android"})," \u2014 Open Google Maps \u2192 Settings \u2192 Location \u2192 Location Services \u2192 Timeline \u2192 Export Timeline"]}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.strong,{children:"iOS"})," \u2014 Open Google Maps \u2192 Settings \u2192 Personal Content \u2192 Export Timeline data"]}),"\n",(0,s.jsx)(i.p,{children:"Once you have your JSON files, just drag and drop them into the visualizer."}),"\n",(0,s.jsx)(i.h2,{id:"when-you-need-more",children:"When You Need More"}),"\n",(0,s.jsx)(i.p,{children:"The Timeline Visualizer is great for quick exploration and one-time analysis. But if you want to:"}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsx)(i.li,{children:"Store your location history securely long-term"}),"\n",(0,s.jsx)(i.li,{children:"Import data from multiple sources (GPX, GeoJSON, etc.)"}),"\n",(0,s.jsx)(i.li,{children:"Track ongoing location data from your devices"}),"\n",(0,s.jsx)(i.li,{children:"Access your timeline from anywhere"}),"\n",(0,s.jsx)(i.li,{children:"Share specific trips or areas"}),"\n"]}),"\n",(0,s.jsx)(i.p,{children:"...then you need a proper location tracking platform."}),"\n",(0,s.jsxs)(i.p,{children:["That's where ",(0,s.jsx)(i.a,{href:"https://dawarich.app",children:"Dawarich"})," comes in. It's an open-source location tracker that gives you full control over your location data. It supports all the same Google Timeline formats as the visualizer, plus GPX files from hiking apps, GeoJSON exports, and real-time tracking from mobile apps."]}),"\n",(0,s.jsx)(i.p,{children:"The visualizer shows you what's possible. Dawarich lets you keep it."}),"\n",(0,s.jsx)(i.h2,{id:"technical-stack",children:"Technical Stack"}),"\n",(0,s.jsx)(i.p,{children:"The visualizer is built with:"}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.strong,{children:"React 18"})," \u2014 UI components and state management"]}),"\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.strong,{children:"Leaflet"})," \u2014 Interactive maps with OpenStreetMap tiles"]}),"\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.strong,{children:"Leaflet.markercluster"})," \u2014 Efficient clustering of thousands of markers"]}),"\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.strong,{children:"Docusaurus"})," \u2014 Static site generation and documentation"]}),"\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.strong,{children:"Custom JavaScript parsers"}
1)," \u2014 Handle Google's various export formats"]}),"\n"]}),"\n",(0,s.jsx)(i.p,{children:"All processing happens client-side. No backend, no database, no user tracking."}),"\n",(0,s.jsx)(i.h2,{id:"future-improvements",children:"Future Improvements"}),"\n",(0,s.jsx)(i.p,{children:"We're exploring additional visualizations like heatmaps, timeline charts, and statistics (most visited places, total distance traveled, etc.). Better performance optimizations are always on the roadmap."}),"\n",(0,s.jsx)(i.h2,{id:"try-it-yourself",children:"Try It Yourself"}),"\n",(0,s.jsxs)(i.p,{children:["The Google Timeline Visualizer is free to use at ",(0,s.jsx)(i.a,{href:"https://dawarich.app/tools/timeline-visualizer",children:"dawarich.app/tools/timeline-visualizer"}),"."]}),"\n",(0,s.jsx)(i.p,{children:"Export your Google Timeline data, drop it in, and see where you've been. All in your browser, all private, all yours."}),"\n",(0,s.jsx)(i.hr,{}),"\n",(0,s.jsx)(i.h2,{id:"resources--credits",children:"Resources & Credits"}),"\n",(0,s.jsx)(i.p,{children:"Building this visualizer required understanding Google's various export formats and parsing their different JSON structures. Here are the key resources and tools that made it possible:"}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.a,{href:"https://locationhistoryformat.com/",children:"https://locationhistoryformat.com/"})," \u2014 Comprehensive documentation of Google Location History formats"]}),"\n",(0,s.jsx)(i.li,{children:"jq \u2014 Command-line JSON processor used for parsing and transforming Google Location History (the exports from user's devices)"}),"\n",(0,s.jsx)(i.li,{children:"Leaflet.js \u2014 Open-source JavaScript library for interactive maps"}),"\n"]}),"\n",(0,s.jsx)(i.hr,{}),"\n",(0,s.jsx)(i.p,{children:(0,s.jsx)(i.em,{children:"The Google Timeline Visualizer is part of the Dawarich ecosystem. All code is open source and available on GitHub."})})]})}function d(e={}){const{wrapper:i}={...(0,n.R)(),...e.components};return i?(0,s.jsx)(i,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},28453(e,i,t){t.d(i,{R:()=>r,x:()=>a});var o=t(96540);const s={},n=o.createContext(s);function r(e){const i=o.useContext(n);return o.useMemo(function(){return"function"==typeof e?e(i):{...i,...e}},[i,e])}function a(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),o.createElement(n.Provider,{value:i},e.children)}},50706(e){e.exports=JSON.parse('{"permalink":"/blog/building-a-privacy-first-google-timeline-visualizer","source":"@site/blog/2025-10-26-google-timeline-visualizer.md","title":"Building a Privacy-First Google Timeline Visualizer","description":"Google Timeline has been tracking your location history for years, quietly collecting data about everywhere you\'ve been. But what happens when you export that data? You get one or multiple JSON files that... well, most people have no idea what to do with them.","date":"2025-10-26T00:00:00.000Z","tags":[{"inline":false,"label":"Tools","permalink":"/blog/tags/tools","description":"Tools provided by Dawarich"}],"readingTime":7.28,"hasTruncateMarker":true,"authors":[{"name":"Evgenii Burmakin","title":"Author of Dawarich","url":"https://github.com/Freika","imageURL":"https://github.com/Freika.png","key":"evgenii","page":null}],"frontMatter":{"slug":"building-a-privacy-first-google-timeline-visualizer","title":"Building a Privacy-First Google Timeline Visualizer","authors":"evgenii","tags":["tools"]},"unlisted":false,"prevItem":{"title":"October 2025 Update: The Search and The Family","permalink":"/blog/october-2025-update"},"nextItem":{"title":"Carefully Preserve Your Memories","permalink":"/blog/carefully-preserve-your-memories"}}')}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.