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):

typenamelabelparametersrequired
geopointgpsRecord the location outside the household's main doorcapture-accuracy=10 warning-accuracy=30yes

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)), noobs

Interviews 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)), noobs

Set 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
restore

The 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) noobs

In 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

What to do with each flag

FlagLikely causesWhat to do
No pointLocation off, permission refused, no fix indoors, question skippedAsk why; show the team how to turn location on; if it is mostly one enumerator, look at their other measures
Poor accuracyPoint taken indoors, or saved before the phone had a fixRemind the team to take the point outside and wait for a fix; raise the capture accuracy in the form
Accuracy of exactly 0Placed by hand on a map, a mock-location app, or no accuracy reportedAsk how the point was taken; back-check if it keeps happening
Outside the study areaA wrong reading, swapped coordinates, a point from the office, an interview in the wrong placeCheck with the supervisor; back-check if the interview may have been done elsewhere
Far from its village or listed householdA wrong village code or ID, the wrong household, a household that movedCompare with the sample list; correct the code or ID with a logged reason, or send it back to the field
Impossible travelA wrong tablet clock, a point taken elsewhere, an interview not done in personCheck the times first, then ask the enumerator; back-check if neither explains it
Many interviews at one spotA shared compound or building, a meeting point, interviews filled in away from the householdsFind out whether the households live together; if not, back-check those interviews first
Two interviews a few metres apart in a listingThe same dwelling listed twiceCompare 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:

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.

Read next