Google Timeline & Location History: Building my first Chrome Extension using React.js

Jonathan Gan
12 min readApr 20, 2021

Hi there, my name Jonathan Gan and this is the breakdown of my journey building my first chrome extension from scratch.

Chrome Extensions are mini programs that add features to the core browser.

What is a Chrome extension?

Well, by necessity, most extensions are simple icon click executions that perform a given action. That action can literally be anything you want the Chrome browser to do.

Now the goal of the project was to create a survey that could be administered on a tablet at hospitals to patients who had covid-19 to see if they could remember where they’ve been in comparison to their Google Timeline Data if the data is present.

Pulling a template

I am natively a react/react-native developer so if possible, I wanted a way to build the project as fast as possible as it was behind schedule.

I found this repo for retrieving Google timeline data:

and also

https://janlauge.github.io/2017/extracting-location-history/

And then found

The links above guided me as I was unfamiliar with how to get started with building a chrome extension so once I read those I had a general idea.

First I git cloned An Object is As repo for a template React Chrome Extension and then reverse engineered the inject scripts used to generate divs into the outputs of the webpack.config using the manifest.json

An Object is A React template

Once I figured that out, I learned I could basically code a react app and then have web-pack convert the library and its components into strict HTML/CCSS/JS as the chrome extension.

I then got the fetch-google-timeline code from the other mentioned repository and used it to bring in user Google Timeline KML data and converting it to JSON

Then I started building a popup that would take answers from the users and then compare them to the Google timeline data to produce results in the extension for users to view.

I used Figma to design the original screens for what was supposed to be a react native app but later made another for the chrome extension popup screen.

Original Screen Designs in figma and Sorting Algorithm planning in lucid charts

I used Trello to plan out the apps tasks

and used lucid charts to plan out the data structure and sorting algorithm required to produce meaningful results.

Progress:

Fast forward a couple steps, I start a repo, got the extension building and then started to flesh out the vague idea the professor gave me on how to make the survey look, the project is on a time crunch for the grant and just required a working product so that was the focus.

I created a pop as below to be a place holder

Initial Popup component

Added some conditional rendering

Added Google Maps Api to the search for accurate result comparison

And now we have to:

  1. Save the data properly for every added location from user
  2. Parse Google timeline data into matching format
  3. Compare results and display in table

I went ahead and added the table component using material ui (copy pasted simple table react)

and formatted it for demonstration purposes of how the data would be formatted

https://tools.ietf.org/html/rfc7946

The above link shows how toGeoJSON works on a KML file to extract the needed information properly for comparison.

Here’s my thought process at this point:

saveAddress is the variable that will collects the form information and passes it to the Local Storage where is under savedAddress

So now I need to get my app properly saving the data to local storage as its only currently pushing the state and display that state on the list but is not passing that state to the local storage.

I was given a ChromeBook running Chrome OS that the survey is to be delivered on, I need to finish getting the results from the retrieved data before I can begin testing on the device.

Areas of concern include the cache of the device as far as login and timeline data is concerned.

The results should be exportable to an email and then a logout procedure / cache wiping procedure needs to be implemented in order for the survey to fit the specified guidelines given by the USF Grant providers.

Time crunch

Now at this point time is extremely short as the deadline was last week while but we’re trying to finish this app before Friday (today is Wednesday)

So to speed up development I did some digging and found a helper function for comparing two objects:

https://gomakethings.com/getting-the-differences-between-two-objects-with-vanilla-js/

Using this code snippet I am able to retrieve the difference between two defined objects so if I replace the defined objects with the two retrieved objects I should be able to find difference between the two and determine correct or incorrect responses and returning them to display into the material ui table

Sorting Algorithm

Now to be more specific with the results, we are aiming to at first display 3 key metrics:

  1. Number of correct answer
  2. Number of incorrect answers
  3. Number of close responses based on proximity

The first two metrics will be relatively easy to obtain

a. do the addresses match

b. do the dates line match

Outcomes:

  • if both are true, answer is correct
  • if both are false, answer is incorrect
  • Now to determine if close, answer must be wrong on the address but correct on the date, and then coordinates of the two locations must be within less than 50 meter
  • And if possible, return addresses that Google may be incorrect about (Answers that were marked wrong, not close, but not in Google timeline data on the date at all)

The priority for time sake the first two metrics and hopefully a table to be able to debug the answers/google data

We are only worried about 14 days of previous timeline data so we don’t need a table with more than a header +14 rows (1 for each day of data)

Debugging and Roadblocks

Here is a screenshot of the browser console where I can spit out the current state and values of different pieces for debug and understanding purposes

So obviously this project has a lot of room to be made better so my first and foremost goal is to get to a ‘functional’ state to run trials.

Roadblocks thus far:

  • Getting saveAddress state to push/save properly to local storage
  • Making the Google timeline data comparable to Answer results
  • Passing the finalized respective answer and result objects the researched snippet above
  • Displaying ONLY number of correct and incorrect answers to user

Once the above steps are complete without issues/bugs, we will have arrived at the requested MVP

After arguing with git conflicts briefly we are able to load the basic chrome extension with working ui and the working implementation of the Object sorting code, now we. must examine the snippet to understand how the data being passed in must look to be properly sorted.

Current status of saveAddress (after 1+ address added):

[
{
“id”: 1,
“day”: 7,
“month”: “April”,
“value”: “12675 Citrus Plaza Dr, Tampa, FL 33625, USA”
}
]

Current retrieval of Google data:

{
“items”: [
{
“name”: “location”,
“address”: “Address”,
“timeBegin”: “2021–03–25T01:13:04.631Z”,
“timeEnd”: “2021–03–25T19:00:27.534Z”,
“duration”: 64042903,
“category”: “”,
“distance”: “0”
}
]
}

To do: Get saveAddress to store each entry as an items array of answer Addresses

This data is saved in around line 86 of the Popup.js file, using state just sets the saveAddress is set to the state of setAddress, adding a minor change allows us to save the state to an items array.

setAddress({
“items”: [
…saveAddrress,
{
id: count,
address: Address,
“date”: “date”
}
]
});

Now we get

[
{
“items”: [
{
“id”: 1,
“day”: 7,
“month”: “April”,
“value”: “12675 Citrus Plaza Dr, Tampa, FL 33625, USA”
}
]
}
]

This still isn’t totally what we need but we’re pivoting anyway: goal is compare data as fast as possible not store data as cleanly as possible so this object return will work fine:

{
“date”: “\”2021–04–07T23:07:38.191Z\””,
“address”: “3450 Palencia Dr #2018, Tampa, FL 33618, USA”
}

Now we need the dates and address of each object to match in syntax for accurate comparison/results

Examining the Chromebook, you cant run dev tools easily and since its school property I will have to package and install the final product separately for the sole sake of installation.

Day 49 of watching webpack compile…

jk

anyways, I got the two data sets in a matching syntax that will allow me to sort them properly into each category.

I will see if for demonstration purposes I can display the datas of each side by side with date

Conditional rendering Intermission:

The code and it’s initial outputs after evaluating the conditions

By using the above code I am able to render certain components on certain conditions being met, in this instance the data needed to build the table must be present or the table will not build.

I initialized the necessary variables to allow the table to operate but at present nothing loads.

I want to get a working table before finishing the sorting algorithm as it will be a lot more valuable for the project to appear complete/more full

At this point I have a table component using material UI that is ready to render but isn’t receiving the data needed to display.

At this point to summarize:

  • We have a displaying popup
  • We have a function for checking for google data
  • We have a conditional rendering google maps search bar
  • A working list element
  • A generated table

And now we’re attempting to manipulate the data we have to display on the table.

Welp, broke up with the girl mid project, I’m just trusting my gut at this point.

Anyways,

  • Load data
  • So far both pieces of data load
  • Now they need to be successfully passed to the table component
  • Sort data
  • - [ x] Once the data is in the table component, we need to create an array of entries tied to the corresponding date of the entry up to 14 days ago
  • [x ] First check that all dates are from answer we’re within the past 14 days
  • [x] Then iterate through the answer and add the corresponding address to the corresponding answer address field of the answer date object
  • [ x] Then iterate through the Google timeline data and add the corresponding address to the corresponding day
  • [ ] Result is just comparing the Google data array to the answer date array to see which ones the answer date array is missing

Sorting algorithm Code snippets and Thinking out loud (Basically the last piece)

// date and answers objects passed to create

function answerDate (Obj1, Obj2) {

for (var key in obj1, key<=obj1.length, key++) {

If (Obj1.date==Obj2.date) {

. Set Obj1[key] ==Obj2.address

} else {

return null

}

}

}

// date and Google timeline data objects passed to create a Googledate Array

function googleDate (Obj1, Obj2) {

for (var key in obj1, key<=obj1.length, key++) {

If (Obj1.date==Obj2.date) {

. Set Obj1[key] ==Obj2.address

} else {

return null

}

}

}

{[date: answeradrews1, answeraddress2]}

ie:

{[

04/21: {home work school}

04/26: {school bar library}

]}

{[date: googleaddress1, googleaddress2]}

ie:

{[

04/21: {home work school}

04/26: {school bar library}

]}

WiFi went out but I’ll watch some courses on making arrays and see if I can sort it once I learn how they operate.

Ok we’re back a bit late but whatever, Talked to my boss about the project and here’s where we will declare ‘working mvp’

  • User logs in on the given Chromebook using their Gmail account
  • Provide Extension compiled and ready to install from USB for user
  • User installs and runs the extension in browser
  • extension displays as a popup with operational survey
  • Once table displays, allow user to export their data to a local pdf
  • Instruct user to logout and remove their google account from the device

We are basically on the last two bullets at this point but they are unfortunately the hardest parts.

We’re passing our google data to the gplace component,

then were recording answers,

then on button click it compares the dates of the objects and creates an object of matching dates

then we compare that object to the object carrying the dates of the last 14 days and only add the corresponding dates that match.

Debug:

At this point the table is giving me a headache passing the data in properly.

SO I will try the ‘rubber ducky’ methodology

I have 2 arrays of objects that need to be combined into a single 3 dimensional array of 3 columns: Date, Google, and Answer

First I create two new arrays for just the date and address of the respective user and google data.

I take the dates array which contains the dates of the last 14 days

Iterate through the 14 days,

for each google entry

if the date matches the google entry day, push the google entry address to an empty array, skip to the next google entry

if the date doesn’t match, push the array and skip to the next day

use set rows to set the rows using the googleDates array and the answer Array

rows should be

[

0:

{date: ‘example’},

{googledate: ‘example’},

{answer: ‘example’}

1:
{date: ‘example’},

{googledate: ‘example’},

{answer: ‘example’}

]

return the rows

Display the rows on the table

Wrap up:

At this point:

  • We have a functional building chrome extension
  • We are getting all the data
  • We have the 2 arrays of data being passed into the table component building function
  • And our new result arrays corresponding date to address isn’t being built correctly yet making the table incorrect

Whats left (for MVP):

  • Massage the result data to display proper results on the material ui table

This fix will likely be quick, once this is done we can work on a sorting algorithm for more specific results.

What could/should be added(features)

  • Ability to export results
  • Ability to administer survey more fluidly (Google has implemented a number of roadblocks regarding extensions and even Google timeline data)
  • Easy to read data display

Overall the project is about complete but was severely mismanaged until given to me in a quick fix response to cover the project grants requirement.

I will update this when I post the extension on the chrome web-store at some point but will be adding to how the functionality and building process went if clarification is need be. Overall I learn a great amount of react and push into in arrays for creating new arrays. I also. now feel confident in my Chrome extension abilities even though this is not my strength at all.

I hope you enjoyed reading this and I will be posting more article as I get more projects to build in my more professional career!

Other References

And finally the repo:

--

--

Jonathan Gan

A Software Engineer who explores for clarity and observes for inspiration