diff --git a/get_coordinates_by_zipcode.py b/get_coordinates_by_zipcode.py
index 8b37ce706fed659660897b579457cad4a998dff1..12cff768915d7eb4d2e64712ddf9030e5791bdaf 100644
--- a/get_coordinates_by_zipcode.py
+++ b/get_coordinates_by_zipcode.py
@@ -22,7 +22,6 @@ Also accepts multiple Zipcodes, or Zipcode prefix.
 """
 
 # TODO: Write tests
-# TODO: Use caching for shapes
 # TODO: Rename functions
 
 import argparse
@@ -35,37 +34,49 @@ from shapely.ops import unary_union
 INPUT_FOLDER = Path('plz')
 PLZ_FILENAME = 'plz-5stellig.geojson'
 PLZ_SHAPE_FILE = INPUT_FOLDER / PLZ_FILENAME
+PRECISION = 10  # [m]
+ONE_DEGREE = 40e6 / 360  # [m]
+
+PLZ_SHAPES = None
 
 
 def _download_plz_shapes_if_needed():
     if not PLZ_SHAPE_FILE.exists():
         from tqdm import tqdm
         import requests
+        print("Downloading %s..." % PLZ_FILENAME)
         URL = "https://downloads.suche-postleitzahl.org/v2/public/" + PLZ_FILENAME
         response = requests.get(URL, stream=True)
         INPUT_FOLDER.mkdir(exist_ok=True)
         with open(PLZ_SHAPE_FILE, "wb") as handle:
             for data in tqdm(response.iter_content(chunk_size=1024), unit='kB'):
                 handle.write(data)
+        print('  Done')
 
 
 def _get_plz_shapes():
-    print("Parsing %s..." % PLZ_FILENAME)
+    global PLZ_SHAPES
+    if PLZ_SHAPES:
+        return PLZ_SHAPES
+
     _download_plz_shapes_if_needed()
     try:
+        print("Parsing %s..." % PLZ_FILENAME)
         with open(PLZ_SHAPE_FILE) as f:
             print('  Done')
-            return json.load(f)
+            PLZ_SHAPES = json.load(f)
+            return PLZ_SHAPES
     except json.decoder.JSONDecodeError:
         PLZ_SHAPE_FILE.unlink()
         raise AttributeError(f"{PLZ_FILENAME} seems to be damaged. Removing it. Please try again!")
 
 
-def _get_coordinates(data, plz_patterns):
+def get_coordinates_by_zipcode(plz_patterns, precision=PRECISION):
+    plz_shapes = _get_plz_shapes()
     geometries = []
     for plz_pattern in plz_patterns:
         found = False
-        for plz_geojson in data['features']:
+        for plz_geojson in plz_shapes['features']:
             if re.match(plz_pattern, plz_geojson['properties']['plz']):
                 found = True
 
@@ -85,7 +96,7 @@ def _get_coordinates(data, plz_patterns):
             raise AttributeError(f"Sorry, no information could be found for PLZ={plz_pattern}")
 
     merged = unary_union(geometries)
-    wkt_polygon = merged.simplify(0.0001).wkt
+    wkt_polygon = merged.simplify(precision / ONE_DEGREE).wkt
     print(wkt_polygon)
     try:
         import pyperclip
@@ -99,11 +110,6 @@ def _get_coordinates(data, plz_patterns):
     return wkt_polygon
 
 
-def get_coordinates_by_zipcode(plzs):
-    plz_shapes = _get_plz_shapes()
-    return _get_coordinates(plz_shapes, plzs)
-
-
 if __name__ == '__main__':
     parser = argparse.ArgumentParser(description='Get WKT geometry for desired PLZs')
     parser.add_argument('plzs', metavar='PLZ', type=str, nargs='+',
diff --git a/requirements.txt b/requirements.txt
index 49ddecbfcd33182c7f7e44e15ad0dd19a681746f..0083c46082253b8bbfd6c6aec277a33c140c8dcc 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,4 @@
 pyproj
 requests
 pyperclip
+tqdm
diff --git a/test_zipcode.py b/test_zipcode.py
index e3342a7b8d69e7ec37aa3cce5206941ac6c0fcb7..f70d40b52a722f106f451cbf7616ebbf95eed368 100644
--- a/test_zipcode.py
+++ b/test_zipcode.py
@@ -7,6 +7,7 @@ class TestClass(unittest.TestCase):
     def test_method(self):
         self.assertEqual('foo'.upper(), 'FOO')
         get_coordinates_by_zipcode.get_coordinates_by_zipcode(['70567'])
+        get_coordinates_by_zipcode.get_coordinates_by_zipcode(['70567'], 1_000)
 
 
 if __name__ == '__main__':