diff --git a/src/common/tools/object_factory/EndPoint.py b/src/common/tools/object_factory/EndPoint.py
index 326c67e1e942e5c4056389a633c70e2830737217..a38ad0d5c59ee75742459729003d43ef01612f53 100644
--- a/src/common/tools/object_factory/EndPoint.py
+++ b/src/common/tools/object_factory/EndPoint.py
@@ -30,7 +30,7 @@ def json_endpoint_ids(
 
 def json_endpoint(
         device_id : Dict, endpoint_uuid : str, endpoint_type : str, topology_id : Optional[Dict] = None,
-        kpi_sample_types : List[int] = []
+        kpi_sample_types : List[int] = [], location : Optional[Dict] = None
     ):
 
     result = {
@@ -38,6 +38,7 @@ def json_endpoint(
         'endpoint_type': endpoint_type,
     }
     if len(kpi_sample_types) > 0: result['kpi_sample_types'] = copy.deepcopy(kpi_sample_types)
+    if location: result['endpoint_location'] = copy.deepcopy(location)
     return result
 
 def json_endpoints(
diff --git a/src/common/tools/object_factory/Location.py b/src/common/tools/object_factory/Location.py
new file mode 100644
index 0000000000000000000000000000000000000000..ac44ef4c64d8466be123c5a722bf7fe69f5e48a8
--- /dev/null
+++ b/src/common/tools/object_factory/Location.py
@@ -0,0 +1,30 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import copy
+from typing import Dict, Optional
+
+
+def json_gps_position(latitude : float, longitude : float):
+    return {'latitude': latitude, 'longitude': longitude}
+
+def json_location(region : Optional[str] = None, gps_position : Optional[Dict] = None):
+    if not region and not gps_position:
+        raise Exception('One of "region" or "gps_position" arguments must be filled')
+    if region:
+        result = {'region': region}
+    else:
+        result = {'gps_position': copy.deepcopy(gps_position)}
+
+    return result
diff --git a/src/service/requirements.in b/src/service/requirements.in
index 83b6342c0c0ed5e969ba03e8af5ac502b1f525c9..bb321e22a1bd56df4193d06c0481acc44640ea7e 100644
--- a/src/service/requirements.in
+++ b/src/service/requirements.in
@@ -17,3 +17,4 @@ anytree==2.8.0
 networkx==2.6.3
 pydot==1.4.2
 redis==4.1.2
+geopy==2.3.0
diff --git a/src/service/service/ServiceServiceServicerImpl.py b/src/service/service/ServiceServiceServicerImpl.py
index 0b2e0760161c109a2ba6a5feecc931e8bcf5c14f..767ba2a58ac73673df5e0c24c2c3e952da471fac 100644
--- a/src/service/service/ServiceServiceServicerImpl.py
+++ b/src/service/service/ServiceServiceServicerImpl.py
@@ -25,6 +25,7 @@ from pathcomp.frontend.client.PathCompClient import PathCompClient
 from .service_handler_api.ServiceHandlerFactory import ServiceHandlerFactory
 from .task_scheduler.TaskScheduler import TasksScheduler
 from .tools.ContextGetters import get_service
+from .tools.GeodesicDistance import gps_distance
 
 LOGGER = logging.getLogger(__name__)
 
@@ -113,21 +114,42 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
             if constraint.WhichOneof('constraint') == 'sla_availability':
                 num_disjoint_paths = constraint.sla_availability.num_disjoint_paths
                 break
+        service_locations = []
+        for constraint in request.service_constraints:
+            if constraint.WhichOneof('constraint') == 'endpoint_location':
+                service_locations.append(constraint.endpoint_location.location)
+
 
         num_disjoint_paths = 1 if num_disjoint_paths is None or num_disjoint_paths == 0 else num_disjoint_paths
         num_expected_endpoints = num_disjoint_paths * 2
 
         tasks_scheduler = TasksScheduler(self.service_handler_factory)
-        if len(service_with_uuids.service_endpoint_ids) >= num_expected_endpoints:
+        if len(service_with_uuids.service_endpoint_ids) >= num_expected_endpoints or\
+           len(service_locations) >= num_expected_endpoints:
             pathcomp_request = PathCompRequest()
             pathcomp_request.services.append(service_with_uuids)    # pylint: disable=no-member
 
+            if service_locations:
+                context_client = ContextClient()
+                device_list = context_client.ListDevices(Empty())
+
+                closer_endpoint_ids = []
+                for service_location in service_locations:
+                    distances = {}
+                    for device in device_list.devices:
+                        for endpoint in device.device_endpoints:
+                            distances[gps_distance(service_location.gps_position, endpoint.endpoint_location.gps_position)] = endpoint.endpoint_id
+                    min_distance = min(distances)
+                    closer_endpoint_ids.append(distances[min_distance])
+
+                pathcomp_request.services[0].service_endpoint_ids.extend(closer_endpoint_ids)
+
             if num_disjoint_paths is None or num_disjoint_paths in {0, 1}:
                 pathcomp_request.shortest_path.Clear()              # pylint: disable=no-member
             else:
                 pathcomp_request.k_disjoint_path.num_disjoint = num_disjoint_paths  # pylint: disable=no-member
 
-            LOGGER.debug('pathcomp_request={:s}'.format(grpc_message_to_json_string(pathcomp_request)))
+            LOGGER.info('pathcomp_request={:s}'.format(grpc_message_to_json_string(pathcomp_request)))
             pathcomp = PathCompClient()
             pathcomp_reply = pathcomp.Compute(pathcomp_request)
             pathcomp.close()
diff --git a/src/service/service/tools/GeodesicDistance.py b/src/service/service/tools/GeodesicDistance.py
new file mode 100644
index 0000000000000000000000000000000000000000..b66d336f0f617aa834905785e2e49f95073a2df9
--- /dev/null
+++ b/src/service/service/tools/GeodesicDistance.py
@@ -0,0 +1,18 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from geopy.distance import geodesic
+
+def gps_distance(gps1, gps2):
+    return geodesic((gps1.latitude, gps1.longitude), (gps2.latitude, gps2.longitude)).km
diff --git a/src/service/tests/ServiceHandler_L3NM_EMU.py b/src/service/tests/ServiceHandler_L3NM_EMU.py
index 3df27b439626dad652e443cca4195ce36f4ac86f..4e1fe5c01c57836417fc1a9e8f6436a6b32eedd5 100644
--- a/src/service/tests/ServiceHandler_L3NM_EMU.py
+++ b/src/service/tests/ServiceHandler_L3NM_EMU.py
@@ -13,8 +13,10 @@
 # limitations under the License.
 
 from typing import Dict, List, Tuple
+
+from common.tools.object_factory.Location import json_location, json_gps_position
 from common.tools.object_factory.ConfigRule import json_config_rule_set
-from common.tools.object_factory.Constraint import json_constraint_custom
+from common.tools.object_factory.Constraint import json_constraint_custom, json_constraint_endpoint_location_gps
 from common.tools.object_factory.Device import (
     json_device_emulated_packet_router_disabled, json_device_emulated_tapi_disabled, json_device_id)
 from common.tools.object_factory.EndPoint import json_endpoint, json_endpoint_id
@@ -24,21 +26,32 @@ from .CommonObjects import CONTEXT, CONTEXT_ID, PACKET_PORT_SAMPLE_TYPES, TOPOLO
 
 SERVICE_HANDLER_NAME = 'l3nm_emulated'
 
-def json_endpoint_ids(device_id : Dict, endpoint_descriptors : List[Tuple[str, str]]):
+def json_endpoint_ids(device_id : Dict, endpoint_descriptors : List[Tuple[str, str, str]]):
     return [
         json_endpoint_id(device_id, ep_uuid)
-        for ep_uuid, _ in endpoint_descriptors
+        for ep_uuid, _, _ in endpoint_descriptors
     ]
 
-def json_endpoints(device_id : Dict, endpoint_descriptors : List[Tuple[str, str]]):
+def json_endpoints(device_id : Dict, endpoint_descriptors : List[Tuple[str, str, str]]):
     return [
-        json_endpoint(device_id, ep_uuid, ep_type, kpi_sample_types=PACKET_PORT_SAMPLE_TYPES)
-        for ep_uuid, ep_type in endpoint_descriptors
+        json_endpoint(device_id, ep_uuid, ep_type, kpi_sample_types=PACKET_PORT_SAMPLE_TYPES, location=ep_location)
+        for ep_uuid, ep_type, ep_location in endpoint_descriptors
     ]
 
+
+BARCELONA_GPS = (41.386726, 2.170107)
+MALAGA_GPS = (36.721162, -4.418339)
+ZARAGOZA_GPS = (41.655552, -0.876442)
+MADRID_GPS = (40.416741, -3.703285)
+TOLEDO_GPS = (39.862947, -4.027485)
+ANDORRA_GPS = (42.506017, 1.525923)
+SANTIAGO_GPS = (42.876254, -8.543588)
+ALBACETE_GPS = (38.998249, -1.858145)
+
+
 # ----- Devices --------------------------------------------------------------------------------------------------------
 DEVICE_R1_UUID          = 'R1'
-DEVICE_R1_ENDPOINT_DEFS = [('EP1', 'optical'), ('EP100', 'copper')]
+DEVICE_R1_ENDPOINT_DEFS = [('EP1', 'optical', json_location(gps_position=json_gps_position(*BARCELONA_GPS))), ('EP100', 'copper', json_location(gps_position=json_gps_position(*BARCELONA_GPS)))]
 DEVICE_R1_ID            = json_device_id(DEVICE_R1_UUID)
 DEVICE_R1_ENDPOINTS     = json_endpoints(DEVICE_R1_ID, DEVICE_R1_ENDPOINT_DEFS)
 DEVICE_R1_ENDPOINT_IDS  = json_endpoint_ids(DEVICE_R1_ID, DEVICE_R1_ENDPOINT_DEFS)
@@ -47,7 +60,7 @@ ENDPOINT_ID_R1_EP1      = DEVICE_R1_ENDPOINT_IDS[0]
 ENDPOINT_ID_R1_EP100    = DEVICE_R1_ENDPOINT_IDS[1]
 
 DEVICE_R2_UUID          = 'R2'
-DEVICE_R2_ENDPOINT_DEFS = [('EP1', 'optical'), ('EP100', 'copper')]
+DEVICE_R2_ENDPOINT_DEFS = [('EP1', 'optical', json_location(gps_position=json_gps_position(*MADRID_GPS))), ('EP100', 'copper', json_location(gps_position=json_gps_position(*MADRID_GPS)))]
 DEVICE_R2_ID            = json_device_id(DEVICE_R2_UUID)
 DEVICE_R2_ENDPOINTS     = json_endpoints(DEVICE_R2_ID, DEVICE_R2_ENDPOINT_DEFS)
 DEVICE_R2_ENDPOINT_IDS  = json_endpoint_ids(DEVICE_R2_ID, DEVICE_R2_ENDPOINT_DEFS)
@@ -56,7 +69,7 @@ ENDPOINT_ID_R2_EP1      = DEVICE_R2_ENDPOINT_IDS[0]
 ENDPOINT_ID_R2_EP100    = DEVICE_R2_ENDPOINT_IDS[1]
 
 DEVICE_R3_UUID          = 'R3'
-DEVICE_R3_ENDPOINT_DEFS = [('EP1', 'optical'), ('EP100', 'copper')]
+DEVICE_R3_ENDPOINT_DEFS = [('EP1', 'optical', json_location(gps_position=json_gps_position(*MALAGA_GPS))), ('EP100', 'copper', json_location(gps_position=json_gps_position(*MALAGA_GPS)))]
 DEVICE_R3_ID            = json_device_id(DEVICE_R3_UUID)
 DEVICE_R3_ENDPOINTS     = json_endpoints(DEVICE_R3_ID, DEVICE_R3_ENDPOINT_DEFS)
 DEVICE_R3_ENDPOINT_IDS  = json_endpoint_ids(DEVICE_R3_ID, DEVICE_R3_ENDPOINT_DEFS)
@@ -65,7 +78,7 @@ ENDPOINT_ID_R3_EP1      = DEVICE_R3_ENDPOINT_IDS[0]
 ENDPOINT_ID_R3_EP100    = DEVICE_R3_ENDPOINT_IDS[1]
 
 DEVICE_O1_UUID          = 'O1'
-DEVICE_O1_ENDPOINT_DEFS = [('EP1', 'optical'), ('EP2', 'optical'), ('EP3', 'optical')]
+DEVICE_O1_ENDPOINT_DEFS = [('EP1', 'optical', json_location(gps_position=json_gps_position(*ANDORRA_GPS))), ('EP2', 'optical', json_location(gps_position=json_gps_position(*ALBACETE_GPS))), ('EP3', 'optical', json_location(gps_position=json_gps_position(*SANTIAGO_GPS)))]
 DEVICE_O1_ID            = json_device_id(DEVICE_O1_UUID)
 DEVICE_O1_ENDPOINTS     = json_endpoints(DEVICE_O1_ID, DEVICE_O1_ENDPOINT_DEFS)
 DEVICE_O1_ENDPOINT_IDS  = json_endpoint_ids(DEVICE_O1_ID, DEVICE_O1_ENDPOINT_DEFS)
@@ -104,6 +117,12 @@ SERVICE_R1_R3_CONSTRAINTS  = [
     json_constraint_custom('latency_ms', 15.2),
     json_constraint_custom('jitter_us', 1.2),
 ]
+
+
+SERVICE_R1_R3_CONSTRAINTS_LOCATION = [
+    json_constraint_endpoint_location_gps(None, ZARAGOZA_GPS[0], ZARAGOZA_GPS[1]),
+    json_constraint_endpoint_location_gps(None, TOLEDO_GPS[0], TOLEDO_GPS[1]),
+]
 SERVICE_R1_R3_CONFIG_RULES = [
     json_config_rule_set(
         '/settings',
@@ -123,14 +142,14 @@ SERVICE_R1_R3_DESCRIPTOR   = json_service_l3nm_planned(SERVICE_R1_R3_UUID)
 
 # ----- Test Descriptor ------------------------------------------------------------------------------------------------
 TEST_SERVICE_HANDLER = (SERVICE_HANDLER_NAME, {
-    'contexts'              : [CONTEXT],
-    'topologies'            : [TOPOLOGY],
-    'devices'               : [DEVICE_R1, DEVICE_R2, DEVICE_R3, DEVICE_O1],
-    'links'                 : [LINK_R1_O1, LINK_R2_O1, LINK_R3_O1],
-
-    'service_id'            : SERVICE_R1_R3_ID,
-    'service_descriptor'    : SERVICE_R1_R3_DESCRIPTOR,
-    'service_endpoint_ids'  : SERVICE_R1_R3_ENDPOINT_IDS,
-    'service_config_rules'  : SERVICE_R1_R3_CONFIG_RULES,
-    'service_constraints'   : SERVICE_R1_R3_CONSTRAINTS,
+    'contexts'                      : [CONTEXT],
+    'topologies'                    : [TOPOLOGY],
+    'devices'                       : [DEVICE_R1, DEVICE_R2, DEVICE_R3, DEVICE_O1],
+    'links'                         : [LINK_R1_O1, LINK_R2_O1, LINK_R3_O1],
+    'service_id'                    : SERVICE_R1_R3_ID,
+    'service_descriptor'            : SERVICE_R1_R3_DESCRIPTOR,
+    'service_endpoint_ids'          : SERVICE_R1_R3_ENDPOINT_IDS,
+    'service_config_rules'          : SERVICE_R1_R3_CONFIG_RULES,
+    'service_constraints'           : SERVICE_R1_R3_CONSTRAINTS,
+    'service_constraints_location'  : SERVICE_R1_R3_CONSTRAINTS_LOCATION,
 })