diff --git a/frontend/src/components/Map.vue b/frontend/src/components/Map.vue
index d42978c..73b6a35 100644
--- a/frontend/src/components/Map.vue
+++ b/frontend/src/components/Map.vue
@@ -37,10 +37,12 @@
                         :disabled="loading"
                         :has-next-page="hasNextPage"
                         :has-prev-page="hasPrevPage"
+                        :resolution="resolutionMeters"
                         @refresh="locationQuery = $event"
                         @reset-page="locationQuery.minId = locationQuery.maxId = null"
                         @next-page="fetchNextPage"
-                        @prev-page="fetchPrevPage" />
+                        @prev-page="fetchPrevPage"
+                        @set-resolution="setResolution" />
           </div>
           <FilterButton @input="showControls = !showControls"
                         :value="showControls" />
@@ -228,6 +230,7 @@ export default {
         {
           ...this.locationQuery,
           ...this.showMetrics.toQuery(),
+          resolutionMeters: this.resolutionMeters,
         }
       )
     },
@@ -252,6 +255,10 @@ export default {
       this.highlightPoint(this.pointsLayer as VectorLayer, point)
     },
 
+    setResolution(resolution: number) {
+      this.resolutionMeters = resolution
+    },
+
     setShowMetrics(metrics: any) {
       Object.assign(this.showMetrics, metrics)
     },
@@ -279,6 +286,7 @@ export default {
           {
             ...newQuery,
             ...this.showMetrics.toQuery(),
+            resolutionMeters: this.resolutionMeters,
           }
         )
 
@@ -321,11 +329,20 @@ export default {
       deep: true,
     },
 
+    resolutionMeters() {
+      this.setQuery({
+        ...this.locationQuery,
+        ...this.showMetrics.toQuery(),
+        resolutionMeters: this.resolutionMeters,
+      })
+    },
+
     showMetrics: {
       handler() {
         this.setQuery({
           ...this.locationQuery,
           ...this.showMetrics.toQuery(),
+          resolutionMeters: this.resolutionMeters,
         })
       },
       deep: true,
diff --git a/frontend/src/components/filter/Form.vue b/frontend/src/components/filter/Form.vue
index f0bf303..9c86ebe 100644
--- a/frontend/src/components/filter/Form.vue
+++ b/frontend/src/components/filter/Form.vue
@@ -94,6 +94,7 @@
           <font-awesome-icon icon="fas fa-chevron-left" />
         </button>
       </div>
+
       <div class="limit-container">
         <label for="limit">Max Results</label>
         <input type="number"
@@ -116,6 +117,27 @@
       </div>
     </div>
 
+    <div class="resolution-container">
+      <label for="resolution">
+        <p class="title">
+          Resolution (m)
+        </p>
+
+        <p class="help">
+          Adjacent points will be at least this far apart.
+        </p>
+      </label>
+
+      <input type="number"
+             id="resolution"
+             name="resolution"
+             :value="resolution"
+             :disabled="disabled"
+             @input="newResolution = Number($event.target.value)"
+             @change="newResolution = Number($event.target.value)"
+             min="0" />
+    </div>
+
     <div class="footer">
       <button type="submit" :disabled="disabled || !changed">
         <font-awesome-icon icon="fas fa-check" />&nbsp;Apply
@@ -133,6 +155,7 @@ export default {
     'prev-page',
     'reset-page',
     'refresh',
+    'set-resolution',
   ],
   props: {
     value: Object,
@@ -148,6 +171,10 @@ export default {
       type: Boolean,
       default: true,
     },
+    resolution: {
+      type: Number,
+      required: true,
+    },
   },
 
   computed: {
@@ -160,6 +187,7 @@ export default {
     return {
       changed: false,
       newFilter: {...this.value},
+      newResolution: this.resolution,
     }
   },
 
@@ -258,6 +286,9 @@ export default {
 
     handleSubmit() {
       this.$emit('refresh', this.newFilter)
+      if (this.newResolution !== this.resolution) {
+        this.$emit('set-resolution', this.newResolution)
+      }
     },
 
     setLimit(event: Event) {
@@ -282,6 +313,10 @@ export default {
       immediate: true,
       deep: true,
     },
+
+    newResolution(value) {
+      this.changed = this.changed || value !== this.resolution
+    },
   },
 }
 </script>
@@ -365,8 +400,34 @@ export default {
     }
   }
 
+  .resolution-container {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    margin: 0.5em;
+
+    label {
+      margin-bottom: 0.25em;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+    }
+
+    input {
+      width: 100%;
+    }
+
+    .help {
+      font-size: 0.75em;
+    }
+  }
+
   button[type=submit] {
     min-width: 10em;
   }
+
+  .help {
+    font-size: 0.75em;
+  }
 }
 </style>
diff --git a/frontend/src/mixins/Points.vue b/frontend/src/mixins/Points.vue
index ea486bb..b6513e5 100644
--- a/frontend/src/mixins/Points.vue
+++ b/frontend/src/mixins/Points.vue
@@ -40,9 +40,9 @@ export default {
   mixins: [Geo, Units],
   data() {
     return {
-      metersTolerance: 20,
       highlightedPointId: null as number | null,
       highlightedFeature: null as Feature | null,
+      resolutionMeters: 50,
     }
   },
 
@@ -57,7 +57,7 @@ export default {
       let prevPoint: GPSPoint = points[0]
 
       points.forEach((point: GPSPoint, index: number) => {
-        if (index === 0 || this.latLngToDistance(point, prevPoint) < this.metersTolerance) {
+        if (index === 0 || this.latLngToDistance(point, prevPoint) < this.resolutionMeters) {
           group.push(point)
         } else {
           if (group.length)