Project Nightingale: Building a Contact Tracing App for Louisiana
In the first week of Project Nightingale, we set out on two tracks:
- In Track A, our aim was to prove or disprove some hypotheses about technology choices and contact tracing, and to build a rough Proof of Concept to start experimenting with a potential solution to the contract tracing problem in Louisiana.
- In Track B, we began by framing the question, “How might we solve for the perceived challenge the audience is facing?” Through discovery and interviewing, we uncovered the challenges our audience is facing and applied those learnings to design studio exercises.
The United States of America has its own cultural norms and values. These are distinct from other countries across the world and we can’t assume that contact tracing apps approaches similar to, say, Singapore or Sweden or South Korea or Spain will work similarly in the U.S.
We know that our fellow citizens tend to be critical of governmental overreach and leery of government tracking. We know that the values of privacy and individual choice are stalwart.
In light of these norms and values, we emphasized building privacy and anonymity into the core features of the application. We also focused on giving each user agency over their data.
Additionally, we knew we needed to move fast (but NOT break things). We limited our scope to an iOS app only. However, we built on the React Native framework so that we could eventually utilize much of the same code to ship an Android version.
Finally, we entered the week knowing our Proof of Concept would leave a large portion of the population unaddressed or underserved. We understand that some of the hardest-hit communities are those that don’t have iPhones; and, even if using an Android phone, app usage is very low. In light of this significant flaw, we quickly identified opportunities to frame the challenge in ways that would allow us to explore solutions beyond a smartphone app. That’s where Track B comes in.
Each decision we made, even in this first Proof of Concept built over four days’ time, was heavily influenced by these core principles.
We started the Memorial Day holiday-shortened week with an outline of the work we hoped to accomplish, knowing that we would need plenty of flexibility to make necessary trade-offs and hard decisions along the way.
Instead of writing overly-prescriptive feature requirements, we outlined the shape of the work and communicated the goals we hoped to achieve.
A great example of this is with hotspot matching. We wanted to prototype the ability to compare a user’s own private location history against a list of known hotspots. This comparison could take many shapes: a map with overlapping pins and radiuses; a side-by-side list of my locations with matching hotspots; a list of only my locations decorated by a numeric counter indicating how many times I may have encountered a nearby hotspot; or some other solution.
In the end, the high level goals mattered more than the specific features.
Individual team members claimed goals and broad feature areas over which to take ownership or to pair with other team members to address. We were off to the races, and we started by trying to validate or invalidate a critical technology hypothesis within the first several hours:
Can we take advantage of the iOS “Significant Locations” API to let the app access the user’s preexisting, locally stored location history?
Proving Our First Hypothesis Wrong
Because location data is at the core of the contact tracing problem, we knew we needed to move quickly to identify our best path forward for gathering locations on behalf of our users.
Within the first day, we did indeed invalidate our hypothesis around iOS’s “Significant Locations.” Apple does not expose access to this built-in location history to third party developers. Instead, these locations are encrypted and only available to several first-party Apple apps, such as Calendar. The data is only available to third party developers as the “Significant-Change Location Service,” which (as the name suggests) only provides the app with locations that are collected after the user grants permission.
Having cleared the first hurdle (sometimes we call this “Identifying the Biggest Risk“), we moved on to identify the best geolocation library for our purposes and started to solve other problems: enabling background location services and storing locations locally on the device without sending them to our server.
The Core Loop
Working as a team, we refined what we call the “Core Loop” of the Proof of Concept to the following:
1. Track Locations Privately, Anonymously, Locally
A user can view and edit their location history stored locally on their device. The private, local list of locations can be valuable without any further action or sharing. It creates a private journal that the user can review to determine if they may have come in contact with COVID-19. It gives them an easy self-reference in the case that they choose to take part in contact tracing interviews with official tracers.
2. Optionally Share an Edited List of Locations
If a user tests positive for COVID-19, they can share an edited list of their locations from the prior two weeks to the Nightingale server. No personally-identifying details or even device fingerprints are sent to the server. Users can edit the list of locations to choose their own degree of privacy. For example, a user might choose to remove their home address from the list before sharing.
3. Compare Your Private Locations to Submitted Hotspots
A user who hasn’t tested positive can see a list of their own locations that might overlap with hotspot locations reported by users that tested positive while maintaining privacy and anonymity for all users. The app queries the server for proximate (in both distance and time) locations that may have crossed with a COVID-19 positive person. The server doesn’t keep any data about who queried these locations.
Assuring Data Privacy and Anonymity
With a plan in place for how to track locations, we were able to focus on how to address our first principle of privacy. Most location-tracking services rely on sending the user’s locations to a server for storage, analysis, and more. We knew that our solution needed to take a different approach from the outset.
In our Proof of Concept, all locations are stored on the individual user’s phone in their local storage. The location tracking happens automatically in the background without ever getting sent to or stored on the Nightingale server. If a user never chooses to share their locations to Nightingale (more on those sharing options below), we never see the data – and that’s the way we want it.
We don’t even ask users to create accounts! We have no need for user accounts, because we never want to store their information in a way that would allow for tracing it back to an identifiable account. Utilizing local storage and eliminating the need for user accounts are two ways we start to address our principle of anonymity.
In the app, we show users that we assume they have a negative/unknown COVID-19 status. If and when a user tests positive for COVID-19, we give them a way to change this status (again — privately, and only on their local phone) to positive.
When the user chooses to change their status, we then ask their permission to (again, privately and anonymously) upload their relevant location history to the server. We only upload the locations that are relevant to the user’s possible contagious period. And we do not upload any personally identifiable information: no user account because none was ever created, no device ID, no IP address … nothing except the location history with the timestamp for each location.
Enabling Agency Over Data
Making sure that data remained private and anonymous wasn’t enough. What if our automatic location tracking captured locations a user would never want to store, even locally; or locations a user would never want to optionally share up to the Nightingale service in order to contribute to building our hotspot dataset?
For the first iteration of this Proof of Concept, we considered many options. Some were more complex than others. Ultimately, in order to give the user agency over their own data, we decided to give them the ability to remove any location from their list of tracked locations.
When removed by the user, these locations cannot be restored to the list, are no longer stored locally, and will never be shared to the server.
Constraints Demand Trade-Offs
When working on any project, there are always limited resources. Typically, the biggest limited resource is time. Whether the timeframe is 4 days or 4 months, time is a constraint. This can serve as a helpful forcing mechanism when approached in a healthy manner.
The team knew we had just 4 days to ship a Proof of Concept. At every step, we asked ourselves if we were addressing the stated goals of the proposed features in a way that was not just sufficient but also expedient. And, ultimately, were the solutions as simple as possible while not sacrificing our principles?
A great example of where trade-offs had to occur was around sharing positive-status locations to the server. We know that the guidance for contact tracing relies heavily on the onset of symptoms and capturing locations starting 48 hours before that onset date. This introduced some significant complexity, both in terms of the user interface as well as the logic that would need to be built into the app.
Keeping in mind that we had 4 days, and also that our goal was a Proof of Concept – a prototype intended for learning purposes and not for immediate promotion and release to the public – we made the decision to simplify. For now, our prototype simply uploads the location history for the 14 days prior to the user marking themselves as having tested positive (and again, only uploads this history after an explicit sharing action by the user).
This allowed us to get closer to closing our “Core Loop” while still shipping a valuable first version of an inherently complex feature.
Creating Interstitial Value
In addition to using time-boxes and other constraints to help force decision making and trade-offs, we also consider “how can we ship value interstitially?” We try not to do a whole lot of work spread out horizontally across an application with the hope we can wire it all up together at the end to have a complete whole.
Instead, we think about valuable, useful “vertical slices” of an app. If we ship these slices as their own unit of work, we know we have the possibility of serving our user while building out the robust system.
For this Proof of Concept, we decided one of those slices was the location journal, stored locally and with the ability to remove locations. Why? Because humans’ brains are bad at memory. Computers are good at memory! If our users are interviewed by a human contact tracer, there’s a great burden to the process — trying to remember what places you visited in the past as well as trying to remember the rough time of day you were in that place.
By placing a focus on this private, only-on-the-device list of locations, we immediately provide value to the user – even without sharing those locations to the server to build a hotspot dataset and without providing the user a way to compare their private locations with the hotspot dataset itself.
Where We Landed
At the end of the 4 days, we were able to demo the following in our Proof of Concept iOS app:
- Private, anonymous, locally-stored location history list
- Reverse-geocode latitude/longitude locations into human-readable street addresses
- Switch COVID-19 status from negative/unknown to positive
- Optionally share, privately and anonymously, prior 14-day location history to the Nightingale server after marking oneself positive
- API query to the server for hotspot location matches within 10 meters and +/- 30 minutes of a provided location (demonstrated in a browser-based API call, not in the app)
- An information landing page website about the Project Nightingale efforts
- Lots of living, in-progress documentation on the project
And here are some things we had hoped to demo but were still in-flight Friday afternoon:
- Ability to remove locations from the private location history list (this was actually functioning, but was tied up in merge conflicts just prior to demo time!)
- Hotspot matching within the app
- Deploying a private, testable version to TestFlight (all demos and testing to this point have been limited to the iPhone Simulator in Xcode)
Feeling like we had more to learn and wanting to get to a point where we closed off the Core Loop, we decided to continue our efforts this week.
We have already resolved the merge conflicts and shipped the ability to remove locations from the private location history list. We’re a few short steps away (more like a day than a week) from having a useful first iteration of hotspot matching in the app.
We’re still battling TestFlight deploys. This has honestly been a major frustration, but the team is patiently doing the work to get it resolved. Within the next few days, we should be able to test the Proof of Concept on actual iPhones.
We have a few user experience improvements we want to ship. Our app navigation could be improved — it’s a simple app with three main views. But our standard app template defaults to a slide-out menu tray, which isn’t particularly intuitive or helpful in this case. We also want to clean up the interface and user flow around changing COVID-19 to positive and optionally sharing location history at this step.
Since we’re using React Native, we hope to create an Android version of the Proof of Concept. Android might not ship this week, but we hope to get a start.
And last but not least, we’re sharing our results with the world. We’re seeking contributors, partners, and sponsors for Project Nightingale. If you’re interested in contributing code, design, or product thinking; or if you’re interested in becoming a partner or a sponsor, you can:
- Visit nightingale.revelry.org for more information
- Dive in on GitHub and start contributing
- Join the conversation in our public Slack community
- Or email email@example.com
We learned a lot in our 4-day experiment and we’ll probably write up some of those learnings in a separate post — more to come.
We feel excited and privileged to contribute to the myriad efforts taking place to reduce the infection and fatality rate of COVID-19 in Louisiana and beyond. We hope you will join us.