Closest facility routing

closest-facility

Routes to the three closest facilities created with the routing service

What is closest facility routing?

Closest facility routing is the process of finding one or more nearby facilities from incidents based on travel time or travel distance. Once you've found the closest facilities, you can display the best route to them and include the travel time, travel distance, and driving directions to each facility in multiple languages.

You can use closest facility routing to build applications that:

  • Find the closest hospital to an accident.
  • Dispatch the two closest police cars to a crime scene.
  • Find the three closest fire stations that can respond to a fire incident within five minutes' drive time.

How closest facility routing works

The typical workflow for closest facility routing is to define:

  1. A set of locations from which to choose the nearest locations (facilities).
  2. One or more locations from which to start searching for the nearby locations (incidents).
  3. The type of travel for the analysis.
  4. The number of closest facilities to find per incident.
  5. Call the service to find the closest facilities and generate route and directions to each nearby facility.

URL requests

You can perform closest facility routing by making an HTTPS request to the closest facility service solveClosestFacility operation or by using client APIs. Specify the facilities to search for, one or more incidents, and optionally, additional parameters to refine the operation. Some of most common parameters are described below.

Required parameters

NameDescriptionExamples
fThe format of the data returned.f=json f=pjson
tokenAn API key or OAuth 2.0 access token.token=<ACCESS_TOKEN>

Direct

Use for shorter transactions to find up to 10 facilities from 100 facilities and 100 incidents in less than 5 minutes.

Use dark colors for code blocksCopy
1
https://route-api.arcgis.com/arcgis/rest/services/World/ClosestFacility/NAServer/ClosestFacility_World/solveClosestFacility?<parameters>
Use dark colors for code blocksCopy
1
https://route.arcgis.com/arcgis/rest/services/World/ClosestFacility/NAServer/ClosestFacility_World/solveClosestFacility?<parameters>

Key parameters

Name (Direct)DescriptionExamples
facilitiesSet of locations from which to choose the nearest locations.facilities=-117.190774,34.057301;-117.199781,34.06047
incidentsOne or more locations from which to start searching for the nearby locations.incidents=-117.195696,34.056503
travelModeThe mode of transportation such as driving a car or a truck or walking.travelMode=JSON Object
defaultTargetFacilityCountThe number of closest facilities to find per incident.defaultTargetFacilityCount=3
defaultCutoffThe travel time or travel distance value at which to stop searching for facilities for a given incident.defaultCutoff=5
travelDirectionWhether you want to search for the closest facility as measured from the incident to the facility or from the facility to the incident.travelDirection=esriNATravelDirectionToFacility

Additional parameters: Set additional constraints when finding closest facilities such as timeOfDay to use live traffic conditions or returnDirections and directionsLanguage to generate driving directions to each nearby facility.

Job

Use for longer transactions to find up to 100 facilities from 5,000 facilities and 5,000 incidents in less than 60 minutes.

Use dark colors for code blocksCopy
1
https://logistics.arcgis.com/arcgis/rest/services/World/ClosestFacility/GPServer/FindClosestFacilities/submitJob?<parameters>

Key parameters

Name (Direct)DescriptionExamples
facilitiesSet of locations from which to choose the nearest locations.facilities={"features":[{"geometry":{"x":-117.190774,"y":34.057301}},{"geometry":{"x":-117.199781,"y":34.06047}}]}
incidentsOne or more locations from which to start searching for the nearby locations.incidents={"features":[{"geometry":{"x":-117.195696,"y":34.056503}}]}
travel_modeThe mode of transportation such as driving a car or a truck or walking.travelMode=JSON Object
number_of_facilities_to_findThe number of closest facilities to find per incident.number_of_facilities_to_find=3
cutoffThe travel time or travel distance value at which to stop searching for facilities for a given incident.cutoff=5
travel_directionWhether you want to search for the closest facility as measured from the incident to the facility or from the facility to the incident.travel_direction=Incident To Facility

Additional parameters: Set additional constraints when finding closest facilities such as time_of_day to use live traffic conditions or populate_directions and directions_language to generate driving directions to each nearby facility.

Code examples

Direct: Find closest grocery stores

In this example, use the Closest facility service to find the three closest grocery stores from a start location and find the best routes to visit the stores.

To find the closest grocery stores, you need to define all grocery stores as facilities, and a start location, for example an address or your current GPS location as incidents. The defaultTargetFacilityCount value is set to 3 so that the service will find three closest grocery stores from the current location instead of one. You set returnCFRoutes to true to get the best routes to the closest grocery stores. In order to determine which three grocery stores are nearest from the list of all available grocery stores, you should set the returnFacilities to true so that you can correlate the chosen grocery stores from the returned facilities and routes.

The response contains the best routes to the three closest grocery stores as well as all the grocery stores provided as input. In order to find the three closest grocery stores, you can match the FacilityID field in routes with the ObjectID field in facilities.

APIs

ArcGIS Maps SDK for JavaScriptArcGIS Maps SDK for JavaScriptArcGIS Maps SDK for .NETArcGIS Maps SDK for SwiftArcGIS Maps SDK for KotlinArcGIS Maps SDK for JavaArcGIS Maps SDK for QtArcGIS API for PythonArcGIS REST JSEsri LeafletMapLibre GL JSOpenLayersCesiumJS
Expand
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
      function findClosestFacility(startFeature, facilityFeatures) {

        const params = new ClosestFacilityParameters({
          incidents: new FeatureSet({
            features: [startFeature],
          }),
          facilities: new FeatureSet({
            features: facilityFeatures.toArray(),
          }),
          returnRoutes: true,
          returnFacilities: true,
          defaultTargetFacilityCount: 3,
        });

        const url = "https://route-api.arcgis.com/arcgis/rest/services/World/ClosestFacility/NAServer/ClosestFacility_World";

        closestFacility.solve(url, params).then(
          (results) => {
            showRoutes(results.routes);
          },
          (error) => {
            console.log(error.details);
          }
        );
      }

REST API

cURLcURLHTTP
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
curl https://route-api.arcgis.com/arcgis/rest/services/World/ClosestFacility/NAServer/ClosestFacility_World/solveClosestFacility? \
-d "f=json" \
-d "token=<ACCESS_TOKEN>" \
-d "facilities={'spatialReference':{'latestWkid':3857,'wkid':102100},'features':[{'geometry':{'x':-13656100.72194608,'y':5703897.952531632},'attributes':{'Name':'Downtown Grocery, 310 SW 4th Ave, Portland, OR, 97204, USA'}},{'geometry':{'x':-13657081.446659965,'y':5704279.273731899},'attributes':{'Name':'Whole Foods Market, 1210 NW Couch St, Portland, OR, 97209, USA'}},{'geometry':{'x':-13654900.697835328,'y':5704360.306582605},'attributes':{'Name':'Pacific Coast Fruit Company, 201 NE 2nd Ave, Portland, Oregon, 97232'}},{'geometry':{'x':-13654793.831124166,'y':5703907.485363393},'attributes':{'Name':'Nicky USA, 223 SE 3rd Ave, Portland, OR, 97214, USA'}},{'geometry':{'x':-13654829.453361219,'y':5703721.596977669},'attributes':{'Name':'Alexis Foods, 215 SE Stark St, Portland, OR, 97214, USA'}},{'geometry':{'x':-13654680.285243554,'y':5703712.064344136},'attributes':{'Name':'Sheridan Fruit Company, 408 SE Martin Luther King, Portland, OR, 97214, USA'}},{'geometry':{'x':-13654723.699844966,'y':5703513.470124055},'attributes':{'Name':'Graziano Food Services, 302 SE Washington St, Portland, OR, 97214, USA'}},{'geometry':{'x':-13654781.585980177,'y':5703484.872919755},'attributes':{'Name':'Rinella Produce, 231 SE Alder St, Portland, OR, 97214, USA'}}]}" \
-d "incidents={'spatialReference':{'latestWkid':3857,'wkid':102100},'features':[{'geometry':{'x':-13656119.041436872,'y':5703857.952531632},'attributes':{'Name':'322 SW 4th Ave, Portland, OR, 97204, USA'}}]}" \
-d "defaultTargetFacilityCount=3" \
-d "returnFacilities=true" \
-d "returnCFRoutes=true"

Job: Find closest fire stations

In this example, you will find the two fire stations that can provide the quickest response to a fire at a given address. You will also generate routes and driving directions for the firefighters.

All the fire stations in the neighborhood are specified as the facilities parameter, and the location of the fire is specified as the incidents parameter. To include the name of the fire station in the driving directions, you should specify Name field in the facilities. Because you want to model the fire engines traveling from the stations to the location of the fire, you specify Facility to Incident as the value for the travel_direction parameter. You need to find the two closest fire stations within five minutes of the fire, so specify 2 as the value for the number_of_facilities_to_find parameter and 5 as the value for the cutoff parameter. You need to calculate the best routes that account for the current traffic conditions, so specify the current time in milliseconds since epoch as the time_of_day parameter and specify Start Time as the time_of_day_usage parameter. Specify populate_directions parameter in order to generate the driving directions.

APIs

ArcGIS API for Python
Expand
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
    # Connect to the closest facility service
    api_key = "YOUR_ACCESS_TOKEN"
    arcgis.GIS("https://www.arcgis.com", api_key=api_key)

    # Call the closest facility service
    result = arcgis.network.analysis.find_closest_facilities(facilities=facilities,
                                                             incidents=incidents,
                                                             number_of_facilities_to_find=2,
                                                             cutoff=5,
                                                             travel_direction="Facility to Incident",
                                                             time_of_day=datetime.datetime.utcnow(),
                                                             time_of_day_usage="Start Time",
                                                             populate_directions=True
                                                             )
    print_result(result)

REST API

Unlike Direct request type which allows you to make a request and get back all the results in the response, when working with a Job request type, you need to follow a three step workflow:

  1. Make the submitJob request with the appropriate request parameters to get a job id.
  2. Using the job id, check the job status to see if the job completed successfully.
  3. Use the job id to get one or more results.
cURLcURLHTTP
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
curl https://logistics.arcgis.com/arcgis/rest/services/World/ClosestFacility/GPServer/FindClosestFacilities/submitJob? \
-d "f=json" \
-d "token=<ACCESS_TOKEN>" \
-d "facilities={'displayFieldName':'','fieldAliases':{'OBJECTID':'OBJECTID','Address':'Address','Name':'Name'},'geometryType':'esriGeometryPoint','spatialReference':{'wkid':2913,'latestWkid':2913},'fields':[{'name':'OBJECTID','type':'esriFieldTypeOID','alias':'OBJECTID'},{'name':'Address','type':'esriFieldTypeString','alias':'Address','length':38},{'name':'Name','type':'esriFieldTypeString','alias':'Name','length':255}],'features':[{'attributes':{'OBJECTID':1,'Address':'5247 N LOMBARD ST','Name':'Station 26 - Portsmouth/University Park'},'geometry':{'x':7633115.889,'y':706174.192}},{'attributes':{'OBJECTID':2,'Address':'8720 SW 30TH AVE','Name':'Station 18 - Multnomah Village'},'geometry':{'x':7635782.577,'y':662289.687}},{'attributes':{'OBJECTID':3,'Address':'5211 SE MALL ST','Name':'Station 25 - Woodstock'},'geometry':{'x':7661431,'y':672359.313}},{'attributes':{'OBJECTID':4,'Address':'7134 N MARYLAND AVE','Name':'Station 08 - Kenton'},'geometry':{'x':7643794.792,'y':703290.389}},{'attributes':{'OBJECTID':5,'Address':'511 SW COLLEGE ST','Name':'Station 04 - Portland State University'},'geometry':{'x':7642550.5,'y':679519.813}},{'attributes':{'OBJECTID':6,'Address':'1920 SW SPRING ST','Name':'Station 15 - Portland Heights'},'geometry':{'x':7638483.5,'y':679335.625}},{'attributes':{'OBJECTID':7,'Address':'7205 N ALTA AVE','Name':'Station 22 - St. Johns'},'geometry':{'x':7624439.852,'y':709314.646}},{'attributes':{'OBJECTID':8,'Address':'5540 NE SANDY BLVD','Name':'Station 28 - Rose City/Hollywood'},'geometry':{'x':7662615.362,'y':690552.356}},{'attributes':{'OBJECTID':9,'Address':'1500 SE 122ND AVE','Name':'Station 07 - Mill Park'},'geometry':{'x':7679927.014,'y':679567.305}},{'attributes':{'OBJECTID':10,'Address':'2915 SE 13TH PL','Name':'Station 23'},'geometry':{'x':7650264.798,'y':676428.937}},{'attributes':{'OBJECTID':11,'Address':'1905 NE KILLINGSWORTH ST','Name':'Station 14 - Alberta Park'},'geometry':{'x':7652607.5,'y':698666.187}},{'attributes':{'OBJECTID':12,'Address':'3130 NW SKYLINE BLVD','Name':'Station 27 - Forest Heights'},'geometry':{'x':7622995.190,'y':692838.978}},{'attributes':{'OBJECTID':13,'Address':'55 SW ASH ST','Name':' Station 01 - Old Town'},'geometry':{'x':7645808.735,'y':683815.505}},{'attributes':{'OBJECTID':14,'Address':'1715 SW SKYLINE BLVD','Name':'Station 16 - Sylvan'},'geometry':{'x':7628988.073,'y':680269.34}},{'attributes':{'OBJECTID':15,'Address':'3660 NW FRONT AVE','Name':'Station 06 - NW Industrial'},'geometry':{'x':7637036.822,'y':693920.006}},{'attributes':{'OBJECTID':16,'Address':'926 NE WEIDLER ST','Name':' Station 13 - Lloyd District'},'geometry':{'x':7649727.5,'y':688199.5}},{'attributes':{'OBJECTID':17,'Address':'2235 SE BYBEE BLVD','Name':'Station 20 - Sellwood/Moreland'},'geometry':{'x':7652687.5,'y':666304.5}},{'attributes':{'OBJECTID':18,'Address':'848 N TOMAHAWK ISLAND DR','Name':'Station 17 - Hayden Island'},'geometry':{'x':7645359.5,'y':715887.625}},{'attributes':{'OBJECTID':19,'Address':'4515 N MARYLAND AVE','Name':'Station 24 - Overlook/Swan Island'},'geometry':{'x':7643391.5,'y':696263.312}},{'attributes':{'OBJECTID':20,'Address':'13310 SE FOSTER RD','Name':'Station 29 - Powellhurst Fire Station'},'geometry':{'x':7682355,'y':666334.813}},{'attributes':{'OBJECTID':21,'Address':'1505 SW DEWITT ST','Name':'Station 05 - Hillsdale'},'geometry':{'x':7639618,'y':668875.813}},{'attributes':{'OBJECTID':22,'Address':'1706 SE CESAR E CHAVEZ BLVD','Name':'Station 09 - Hawthrone District'},'geometry':{'x':7658078.428,'y':679407.82}},{'attributes':{'OBJECTID':23,'Address':'4800 NE 122ND AVE','Name':'Station 02 - Parkrose'},'geometry':{'x':7680485.5,'y':695991.688}},{'attributes':{'OBJECTID':24,'Address':'1715 NW JOHNSON ST','Name':'Station 03 - Northwest Pearl District'},'geometry':{'x':7641263,'y':686484.063}},{'attributes':{'OBJECTID':25,'Address':'8645 NE SANDY BLVD','Name':'Station 12 - Sandy Blvd'},'geometry':{'x':7670903.955,'y':695130.753}},{'attributes':{'OBJECTID':26,'Address':'451 SW TAYLORS FERRY RD','Name':'Station 10 - Burlingame'},'geometry':{'x':7642023.5,'y':662635.312}},{'attributes':{'OBJECTID':27,'Address':'7301 E BURNSIDE ST','Name':'Station 19 - Mt. Tabor'},'geometry':{'x':7667098.674,'y':683759.966}},{'attributes':{'OBJECTID':28,'Address':'13313 NE SAN RAFAEL ST','Name':'Station 30 - Gateway'},'geometry':{'x':7683049.5,'y':688545.938}},{'attributes':{'OBJECTID':29,'Address':'5707 SE 92ND AVE','Name':'Station 11 - Lents'},'geometry':{'x':7671504,'y':668305.312}},{'attributes':{'OBJECTID':30,'Address':'5 SE MADISON ST','Name':'Station 21 - Eastbank/Hawthrone'},'geometry':{'x':7646356.982,'y':680651.469}},{'attributes':{'OBJECTID':31,'Address':'1927 SE 174TH AVE','Name':'Station 31 - Rockwood'},'geometry':{'x':7693238.495,'y':677792.48}}]}" \
-d "incidents={'displayFieldName':'','fieldAliases':{'OBJECTID':'OBJECTID','Name':'Name'},'geometryType':'esriGeometryPoint','spatialReference':{'wkid':2913,'latestWkid':2913},'fields':[{'name':'OBJECTID','type':'esriFieldTypeOID','alias':'OBJECTID'},{'name':'Name','type':'esriFieldTypeString','alias':'Name','length':500}],'features':[{'attributes':{'OBJECTID':1,'Name':'1020 SE 7th Ave, Portland, Oregon, 97214'},'geometry':{'x':7648955.177,'y':681403.651}}]}" \
-d "number_of_facilities_to_find=2" \
-d "cutoff=5" \
-d "travel_direction=Facility to Incident" \
-d "time_of_day=1611676800000" \
-d "time_of_day_usage=Start Time" \
-d "populate_directions=true"
Response (JSON)
Use dark colors for code blocksCopy
1
2
3
4
{
  "jobId": "j0c8bcdb041584d9f8e54243a23ea27f3",
  "jobStatus": "esriJobSubmitted"
}

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.