GPS checks for survey data quality: where each interview was done
GPS checks use the location recorded with each interview to confirm it was done where the data says. Check every day that each interview has a point, that its accuracy is good enough, that it lies inside the study area and near the village or household it names, that the enumerator could have travelled there from their last interview, and that one person's interviews aren't all recorded from one spot. Treat the coordinates as personal data: check them where the identified data is kept, and share areas rather than exact points.
By Mehrab Ali, founder of DataFlow · Updated 7 November 2026
What a GPS point holds
A GPS (geopoint) question records where the phone or tablet was when the enumerator saved it. SurveyCTO exports a geopoint as four columns, such as gpsloc-Latitude, gpsloc-Longitude, gpsloc-Altitude and gpsloc-Accuracy, with altitude and accuracy set to exactly 0.0 when they aren't available. In ODK the answer is four numbers separated by spaces: latitude, longitude, altitude in metres and the accuracy radius in metres. KoboToolbox exports a column with the full set plus separate latitude, longitude, altitude and precision columns, where precision and accuracy mean the same value. The accuracy is the one to watch: the smaller it is, the closer the point is likely to be to where the interview happened.
The form decides much of the quality. In ODK Collect a geopoint is captured automatically once the device reaches its target accuracy, 5 m by default, which the capture-accuracy parameter changes; warning-accuracy, 100 m by default, turns the dialog red but doesn't stop the enumerator saving a worse point. Set both to what the study needs, make the question required where consent covers it, and train enumerators to take the point outside the house (SurveyLoopr's tip on GPS questions covers setting one up):
| type | name | label | parameters | required |
|---|---|---|---|---|
| geopoint | gps | Record the location outside the household's main door | capture-accuracy=10 warning-accuracy=30 | yes |
GPS checks only apply to interviews done in person, and only where the consent and the ethics approval cover recording a location. They belong in the daily high-frequency checks, read enumerator by enumerator.
Missing points and poor accuracy
A missing point usually means the phone's location was switched off, the app wasn't allowed to use it, the phone had no fix indoors, or the question was skipped. The submission doesn't say which, so the enumerator has to be asked. A point at latitude 0, longitude 0 is a failed reading, not a place, and should count as missing. Missing points spread across the team are a training or equipment problem; missing points from one enumerator can mean the GPS was switched off on purpose.
Poor accuracy (a large radius) means the point can't place the interview in a village, let alone at a household. Look for an accuracy of exactly 0 too. In ODK Collect a point placed by hand on a map with the placement-map appearance has an accuracy of 0, and so does a point from a mock-location app, which ODK sets to 0 on purpose so it can be detected. A run of zeros from one enumerator deserves a question.
* GPS in gps_lat, gps_lon and gps_acc (rename your export's columns to match)
use "survey.dta", clear
generate no_point = missing(gps_lat, gps_lon) | (gps_lat == 0 & gps_lon == 0)
generate poor = gps_acc > 10 & !missing(gps_acc) & !no_point
generate zero_acc = gps_acc == 0 & !no_point
tabstat no_point poor zero_acc, by(enum_id) statistics(mean n)
* Points outside a box around the study area (set the limits for yours)
list hhid enum_id gps_lat gps_lon if !no_point & ///
(!inrange(gps_lat, 23.5, 24.5) | !inrange(gps_lon, 89.8, 91.0)), noobsInterviews outside the study area or far from where they should be
A point far outside the study area is a wrong reading, latitude and longitude swapped or typed with the wrong sign, a point recorded at the field office or at home, or an interview done somewhere it shouldn't have been. A box around the study area catches the obvious ones; a map of the day's points catches the rest.
Closer in, compare each interview with where it should be. If the sample list has coordinates (from a listing exercise, say), measure the distance from the sampled household. If not, measure it from the middle of the other interviews in the village the interview names; the median point is better than the average, because one bad reading doesn't pull it. Distances on the earth's surface come from the haversine formula, which needs only the two points:
* Distance from the sampled household's listed location, in metres
* (sample.dta holds hhid, list_lat and list_lon; resolve duplicate IDs first)
merge 1:1 hhid using "sample.dta", keep(master match) nogenerate
generate m_listed = 6371000 * 2 * asin(sqrt(sin((gps_lat - list_lat) * _pi / 360)^2 + ///
cos(gps_lat * _pi / 180) * cos(list_lat * _pi / 180) * sin((gps_lon - list_lon) * _pi / 360)^2)) if !no_point
* Distance from the middle of the village's interviews, in km
bysort village: egen mid_lat = median(gps_lat) if !no_point
bysort village: egen mid_lon = median(gps_lon) if !no_point
generate km_village = 6371 * 2 * asin(sqrt(sin((gps_lat - mid_lat) * _pi / 360)^2 + ///
cos(gps_lat * _pi / 180) * cos(mid_lat * _pi / 180) * sin((gps_lon - mid_lon) * _pi / 360)^2))
list hhid enum_id village m_listed km_village ///
if (m_listed > 200 & !missing(m_listed)) | (km_village > 5 & !missing(km_village)), noobsSet the limits from the ground: 200 m from a listed household may be generous in a town and tight where farms are spread out, and a village can be a few hundred metres across or several kilometres. An interview far from its village often has the wrong village code rather than the wrong location, so check the code before suspecting the enumerator.
Impossible travel and many interviews at one spot
Put each enumerator's interviews in order of start time and work out how fast they would have had to travel from the end of one interview to the start of the next. A speed no vehicle on those roads could reach means a wrong tablet clock, a point taken somewhere else, or an interview not done in person. Ignore short distances, which GPS error alone can produce.
* Speed needed from the same enumerator's previous interview
* (starttime and endtime as Stata datetimes, %tc, which count milliseconds)
preserve
drop if no_point
sort enum_id starttime
by enum_id: generate km_prev = 6371 * 2 * asin(sqrt(sin((gps_lat - gps_lat[_n-1]) * _pi / 360)^2 + ///
cos(gps_lat * _pi / 180) * cos(gps_lat[_n-1] * _pi / 180) * sin((gps_lon - gps_lon[_n-1]) * _pi / 360)^2))
by enum_id: generate hours = max((starttime - endtime[_n-1]) / 3600000, 5 / 60) ///
if _n > 1 & !missing(starttime, endtime[_n-1])
generate kmh = km_prev / hours
list enum_id hhid starttime km_prev kmh if kmh > 60 & km_prev > 2 & !missing(kmh), noobs
restoreThe opposite pattern is several of one enumerator's interviews recorded within a few metres of each other. It can mean the interviews were filled in at one place, such as a tea stall or the enumerator's lodging, instead of at each household. It can also be innocent: households sharing a compound or a building, or respondents interviewed at a meeting point. To find the pairs, compare each enumerator's points with each other, as the near-copy search on the duplicates page does with answers:
* Pairs of one enumerator's interviews less than 15 m apart
use "survey.dta", clear
keep hhid enum_id gps_lat gps_lon
drop if missing(gps_lat, gps_lon) | (gps_lat == 0 & gps_lon == 0)
save "points.dta", replace
rename (hhid gps_lat gps_lon) (hhid_b lat_b lon_b)
joinby enum_id using "points.dta"
keep if hhid < hhid_b
generate m = 6371000 * 2 * asin(sqrt(sin((gps_lat - lat_b) * _pi / 360)^2 + ///
cos(gps_lat * _pi / 180) * cos(lat_b * _pi / 180) * sin((gps_lon - lon_b) * _pi / 360)^2))
keep if m < 15
bysort enum_id: generate close_pairs = _N
list enum_id hhid hhid_b m close_pairs, sepby(enum_id) noobsIn a listing or census, where every dwelling should appear once, two points a few metres apart from any enumerators can be the same household listed twice. In an ordinary survey that is often just neighbours.
Reading GPS flags fairly
- GPS is noisy. Points taken indoors, under trees or between tall buildings drift by tens of metres, and phones differ. Compare enumerators working in similar places and with similar phones before drawing conclusions.
- Check the clock before the person. A tablet set to the wrong date or time makes ordinary travel look impossible.
- Read GPS with the other measures. Interviews from one spot, short interviews and near-copies together are a pattern; any one alone is often explained by the place. See signs of fabricated interviews and enumerator monitoring.
- A GPS flag says where a point was saved, which is close to, but not proof of, where an interview happened. A back-check settles it.
What to do with each flag
| Flag | Likely causes | What to do |
|---|---|---|
| No point | Location off, permission refused, no fix indoors, question skipped | Ask why; show the team how to turn location on; if it is mostly one enumerator, look at their other measures |
| Poor accuracy | Point taken indoors, or saved before the phone had a fix | Remind the team to take the point outside and wait for a fix; raise the capture accuracy in the form |
| Accuracy of exactly 0 | Placed by hand on a map, a mock-location app, or no accuracy reported | Ask how the point was taken; back-check if it keeps happening |
| Outside the study area | A wrong reading, swapped coordinates, a point from the office, an interview in the wrong place | Check with the supervisor; back-check if the interview may have been done elsewhere |
| Far from its village or listed household | A wrong village code or ID, the wrong household, a household that moved | Compare with the sample list; correct the code or ID with a logged reason, or send it back to the field |
| Impossible travel | A wrong tablet clock, a point taken elsewhere, an interview not done in person | Check the times first, then ask the enumerator; back-check if neither explains it |
| Many interviews at one spot | A shared compound or building, a meeting point, interviews filled in away from the households | Find out whether the households live together; if not, back-check those interviews first |
| Two interviews a few metres apart in a listing | The same dwelling listed twice | Compare the two and set one aside with a reason if it is the same household |
Keeping coordinates private
An exact GPS point identifies a household as surely as a name does. Run the checks where the identified data is kept, let only the people who follow up the flags see exact points, and share maps of areas rather than of households. Before data leaves the team, compute what the analysis needs from the coordinates (distance to the market, the cluster a household belongs to), then drop or coarsen them, as described in de-identifying survey data. GPS points also turn up in free text, typed into a comment, so read those too.
How DataFlow checks GPS
DataFlow finds GPS questions in the form, or columns named like gps-Latitude, and reads each point from one column (ODK's four numbers, or GeoJSON) or from separate latitude, longitude and accuracy columns as SurveyCTO exports them. A point at 0, 0 counts as no point. For each GPS question it adds these checks:
- The point is recorded: flags interviews with no GPS point.
- The point is accurate: flags points less accurate than the
capture-accuracythe question asks for in the form, or 10 m when it asks for none. If more than 5% of points are worse, and they aren't mostly one enumerator's, it starts switched off, with a note that the locations may not be good enough for analysis. - Near the other interviews: flags a point more than 20 km from every other interview, once at least 10 interviews have a point.
- Interviews are in the area they name, once you name an area variable: flags interviews more than 5 km from the middle (the median point) of their area's interviews, once the area has at least 5.
- Enumerators could travel between interviews, with an enumerator variable and start times: flags an interview the enumerator would have had to reach at over 60 km/h from the end of their previous one. Moves of 2 km or less are ignored as GPS noise, and at least 5 minutes is allowed between interviews.
- Interviews aren't all from one spot, with an enumerator variable: flags three or more of one enumerator's interviews within 15 m of each other.
- Each household is visited once: flags any two interviews within 5 m of each other, whoever recorded them. It starts switched on when the form or study is named as a listing, census, mapping, household list or enumeration, and off otherwise, because neighbours can live that close.
Every limit can be changed. A missing point and poor accuracy are minor flags by default: they don't stop an interview counting as ready, and the map shows those interviews as worth a look. Each kind of flag comes with a next step for the field team, such as “Remind the team to wait for a GPS fix before saving”.
The checks read GPS inside the app, and their flags carry distances, never coordinates. The field map shows hexagons with counts of interviews in each state (ready, worth a look, needs a look, set aside) unless someone asks for exact places, which is recorded in the activity log. When personal data is reviewed, DataFlow suggests GPS questions for its encrypted personal-data store, along with variables named like gps, latitude, longitude or location and variables whose values look like coordinates; once GPS is protected there, the checks read it from the store. DataFlow works alongside the collection platform: it connects to SurveyLoopr, SurveyCTO, ODK Central and KoboToolbox, and reads exports from other tools.
Questions
What GPS accuracy is good enough for a household survey?
It depends on what the location is for. To confirm an interview took place in the right village, a few tens of metres is enough; to tell neighbouring households apart, aim for 10 m or better. Set the target in the form (capture-accuracy in ODK) and check the accuracy column every day.
How do I check interview locations in Stata?
Flag missing points and poor accuracy by enumerator, list points outside a box around the study area, compute each interview's distance from its sampled household or from the median point of its village with the haversine formula, and compute the speed each enumerator would have needed between consecutive interviews.
What does a GPS accuracy of 0 mean?
SurveyCTO exports 0.0 when no accuracy was available, and in ODK Collect an accuracy of 0 means the point was placed by hand on a map or came from a mock-location app. Either way it deserves a question, especially when it keeps happening for one enumerator.
Do several interviews at one spot mean they were made up?
Not on their own. Households can share a compound or a building, and some interviews happen at a meeting point. Find out whether the households live together; if they don't, back-check those interviews, and read the GPS flags alongside interview length and other signs.
Can I share GPS coordinates from a survey?
Not as exact points. A GPS point identifies a household, so keep exact coordinates with the identified data, compute any distances you need first, then drop or coarsen the coordinates before the data is shared.