[{"data":1,"prerenderedAt":1767},["ShallowReactive",2],{"doc:\u002Fspatial-data-processing-automation\u002Fweb-services-and-remote-data\u002Fload-arcgis-rest-feature-service-pyqgis":3},{"id":4,"title":5,"body":6,"description":1756,"extension":1757,"meta":1758,"navigation":326,"path":1763,"seo":1764,"stem":1765,"__hash__":1766},"docs\u002Fspatial-data-processing-automation\u002Fweb-services-and-remote-data\u002Fload-arcgis-rest-feature-service-pyqgis\u002Findex.md","Load an ArcGIS REST Feature Service in PyQGIS",{"type":7,"value":8,"toc":1743},"minimark",[9,13,34,43,213,218,249,253,260,643,664,668,679,810,827,928,932,935,1076,1093,1097,1100,1247,1273,1277,1280,1341,1575,1591,1595,1616,1620,1654,1658,1667,1671,1677,1693,1699,1705,1709,1739],[10,11,5],"h1",{"id":12},"load-an-arcgis-rest-feature-service-in-pyqgis",[14,15,16,17,21,22,25,26,29,30,33],"p",{},"A great deal of public and organisational geodata is published through Esri's ArcGIS REST API rather than OGC standards: council open data portals, utility networks, environmental agencies, emergency management dashboards. QGIS reads these services natively — vector features from a ",[18,19,20],"code",{},"FeatureServer"," or ",[18,23,24],{},"MapServer"," layer through the ",[18,27,28],{},"arcgisfeatureserver"," provider, and rendered map images through ",[18,31,32],{},"arcgismapserver"," — so a PyQGIS script can pull them into an analysis without any Esri software.",[14,35,36,37,42],{},"This recipe belongs to ",[38,39,41],"a",{"href":40},"\u002Fspatial-data-processing-automation\u002Fweb-services-and-remote-data\u002F","Web Services and Remote Data in PyQGIS",". It finds the right layer URL, loads features and map images, handles authentication, respects the server's paging limits, and copies the data locally when the work needs more than a quick look.",[14,44,45],{},[46,47,52,56,60,67,84,93,102,108,114,116,119,121,126,130,135,138,143,146,152,157,160,163,168,173,176,180,186,192,196,201,205,209],"svg",{"viewBox":48,"role":49,"ariaLabel":50,"xmlns":51},"0 0 760 300","img","The anatomy of an ArcGIS REST service URL and which QGIS provider reads each part: a services directory, a FeatureServer holding numbered layers read as vectors, and a MapServer returning images read as a raster","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg",[53,54,55],"title",{},"Which endpoint, which provider",[57,58,59],"desc",{},"A URL tree: the rest\u002Fservices directory contains folders and services. A FeatureServer service contains numbered layers 0, 1 and 2, each of which is loaded as a vector layer with the arcgisfeatureserver provider using the URL ending in the layer number. A MapServer service is loaded whole as a raster layer with the arcgismapserver provider, which requests rendered images; its numbered layers can also be queried for features with the vector provider.",[61,62],"rect",{"x":63,"y":63,"width":64,"height":65,"fill":66},"0","760","300","#f6f3ea",[68,69,70],"defs",{},[71,72,79],"marker",{"id":73,"viewBox":74,"refX":75,"refY":76,"markerWidth":77,"markerHeight":77,"orient":78},"agsTreeArrow","0 0 10 10","8","5","7","auto-start-reverse",[80,81],"path",{"d":82,"fill":83},"M0 0 L10 5 L0 10 z","#2f3b35",[85,86,92],"text",{"x":87,"y":88,"style":89,"fill":90,"textAnchor":91},"380","28","text-anchor:middle;font-size:14px;font-weight:bold;font-family:sans-serif","#17211d","middle","Point the provider at the right level of the URL",[61,94],{"x":95,"y":96,"width":97,"height":98,"rx":75,"fill":99,"stroke":100,"style":101},"24","52","210","44","#fffdf7","#59645f","stroke-width:1.8",[85,103,107],{"x":104,"y":105,"style":106,"fill":83,"textAnchor":91},"129","79","text-anchor:middle;font-size:10px;font-family:monospace","…\u002Farcgis\u002Frest\u002Fservices",[109,110],"line",{"x1":104,"y1":111,"x2":104,"y2":112,"stroke":100,"style":113},"96","118","stroke-width:1.6",[109,115],{"x1":104,"y1":112,"x2":87,"y2":112,"stroke":100,"style":113},[109,117],{"x1":104,"y1":112,"x2":104,"y2":118,"stroke":100,"style":113},"138",[109,120],{"x1":87,"y1":112,"x2":87,"y2":118,"stroke":100,"style":113},[61,122],{"x":95,"y":118,"width":97,"height":98,"rx":75,"fill":123,"stroke":124,"style":125},"#eef7f4","#0f766e","stroke-width:2",[85,127,129],{"x":104,"y":128,"style":106,"fill":83,"textAnchor":91},"165","Utilities\u002FFeatureServer",[61,131],{"x":132,"y":118,"width":97,"height":98,"rx":75,"fill":133,"stroke":134,"style":125},"275","#fdf2e2","#b45309",[85,136,137],{"x":87,"y":128,"style":106,"fill":83,"textAnchor":91},"Basemap\u002FMapServer",[109,139],{"x1":140,"y1":141,"x2":140,"y2":142,"stroke":100,"style":113},"80","182","208",[109,144],{"x1":145,"y1":141,"x2":145,"y2":142,"stroke":100,"style":113},"178",[61,147],{"x":95,"y":142,"width":148,"height":149,"rx":150,"fill":99,"stroke":124,"style":151},"104","36","6","stroke-width:1.5",[85,153,156],{"x":154,"y":155,"style":106,"fill":83,"textAnchor":91},"76","231","\u002F0 mains",[61,158],{"x":159,"y":142,"width":148,"height":149,"rx":150,"fill":99,"stroke":124,"style":151},"130",[85,161,162],{"x":141,"y":155,"style":106,"fill":83,"textAnchor":91},"\u002F1 valves",[109,164],{"x1":104,"y1":165,"x2":104,"y2":166,"stroke":83,"style":167},"244","262","stroke-width:1.6;marker-end:url(#agsTreeArrow)",[85,169,172],{"x":104,"y":170,"style":171,"fill":124,"textAnchor":91},"282","text-anchor:middle;font-size:10.5px;font-weight:bold;font-family:sans-serif","arcgisfeatureserver → vector",[109,174],{"x1":87,"y1":141,"x2":87,"y2":175,"stroke":83,"style":167},"248",[85,177,179],{"x":87,"y":178,"style":171,"fill":134,"textAnchor":91},"272","arcgismapserver → raster",[61,181],{"x":182,"y":96,"width":183,"height":184,"rx":185,"fill":99,"stroke":100,"style":125},"520","216","192","10",[85,187,191],{"x":188,"y":189,"style":190,"fill":90,"textAnchor":91},"628","78","text-anchor:middle;font-size:11px;font-weight:bold;font-family:sans-serif","check first",[85,193,195],{"x":188,"y":194,"style":106,"fill":83,"textAnchor":91},"106","…\u002FFeatureServer\u002F0?f=pjson",[85,197,200],{"x":188,"y":198,"style":199,"fill":83,"textAnchor":91},"136","text-anchor:middle;font-size:10px;font-family:sans-serif","geometryType",[85,202,204],{"x":188,"y":203,"style":199,"fill":83,"textAnchor":91},"156","maxRecordCount",[85,206,208],{"x":188,"y":207,"style":199,"fill":83,"textAnchor":91},"176","supportedQueryFormats",[85,210,212],{"x":188,"y":211,"style":199,"fill":83,"textAnchor":91},"196","spatialReference",[214,215,217],"h2",{"id":216},"prerequisites","Prerequisites",[219,220,221,229,241],"ul",{},[222,223,224,228],"li",{},[225,226,227],"strong",{},"QGIS 3.40 LTR"," or newer, or the QGIS 4 series.",[222,230,231,232,235,236,21,238,240],{},"The REST URL of a service. Open data portals usually expose it under an \"API\" or \"View service\" link; it contains ",[18,233,234],{},"\u002Frest\u002Fservices\u002F"," and ends in ",[18,237,20],{},[18,239,24],{},", optionally followed by a layer number.",[222,242,243,244,248],{},"For secured services, credentials or a token, stored in the QGIS authentication database rather than in scripts — see ",[38,245,247],{"href":246},"\u002Fpyqgis-fundamentals-environment-setup\u002Fheadless-qgis-and-server-automation\u002Fstore-credentials-with-qgsauthmanager-pyqgis\u002F","storing credentials with QgsAuthManager",".",[214,250,252],{"id":251},"inspect-the-service-before-loading-it","Inspect the service before loading it",[14,254,255,256,259],{},"Every ArcGIS REST endpoint describes itself as JSON when ",[18,257,258],{},"f=json"," is added to the URL. Reading that description first tells you the layer's geometry type, its spatial reference, how many records the server returns per request, and whether queries are allowed at all.",[261,262,267],"pre",{"className":263,"code":264,"language":265,"meta":266,"style":266},"language-python shiki shiki-themes github-dark","import json\nfrom qgis.PyQt.QtCore import QUrl\nfrom qgis.PyQt.QtNetwork import QNetworkRequest\nfrom qgis.core import QgsBlockingNetworkRequest\n\nLAYER_URL = \"https:\u002F\u002Fgis.example.gov\u002Farcgis\u002Frest\u002Fservices\u002FUtilities\u002FFeatureServer\u002F0\"\n\ndef rest_json(url, **params):\n    q = QUrl(url)\n    query = \"&\".join(f\"{k}={v}\" for k, v in {\"f\": \"json\", **params}.items())\n    q.setQuery(query)\n    request = QgsBlockingNetworkRequest()\n    if request.get(QNetworkRequest(q)) != QgsBlockingNetworkRequest.NoError:\n        raise RuntimeError(request.errorMessage())\n    return json.loads(bytes(request.reply().content()))\n\ninfo = rest_json(LAYER_URL)\nprint(info[\"name\"], info[\"geometryType\"], info.get(\"maxRecordCount\"))\nprint(\"spatial reference:\", info[\"extent\"][\"spatialReference\"])\ncount = rest_json(f\"{LAYER_URL}\u002Fquery\", where=\"1=1\", returnCountOnly=\"true\")[\"count\"]\nprint(\"features on the server:\", count)\n","python","",[18,268,269,281,295,308,321,328,342,347,366,378,447,453,464,479,491,506,511,527,554,580,630],{"__ignoreMap":266},[270,271,273,277],"span",{"class":109,"line":272},1,[270,274,276],{"class":275},"snl16","import",[270,278,280],{"class":279},"s95oV"," json\n",[270,282,284,287,290,292],{"class":109,"line":283},2,[270,285,286],{"class":275},"from",[270,288,289],{"class":279}," qgis.PyQt.QtCore ",[270,291,276],{"class":275},[270,293,294],{"class":279}," QUrl\n",[270,296,298,300,303,305],{"class":109,"line":297},3,[270,299,286],{"class":275},[270,301,302],{"class":279}," qgis.PyQt.QtNetwork ",[270,304,276],{"class":275},[270,306,307],{"class":279}," QNetworkRequest\n",[270,309,311,313,316,318],{"class":109,"line":310},4,[270,312,286],{"class":275},[270,314,315],{"class":279}," qgis.core ",[270,317,276],{"class":275},[270,319,320],{"class":279}," QgsBlockingNetworkRequest\n",[270,322,324],{"class":109,"line":323},5,[270,325,327],{"emptyLinePlaceholder":326},true,"\n",[270,329,331,335,338],{"class":109,"line":330},6,[270,332,334],{"class":333},"sDLfK","LAYER_URL",[270,336,337],{"class":275}," =",[270,339,341],{"class":340},"sU2Wk"," \"https:\u002F\u002Fgis.example.gov\u002Farcgis\u002Frest\u002Fservices\u002FUtilities\u002FFeatureServer\u002F0\"\n",[270,343,345],{"class":109,"line":344},7,[270,346,327],{"emptyLinePlaceholder":326},[270,348,350,353,357,360,363],{"class":109,"line":349},8,[270,351,352],{"class":275},"def",[270,354,356],{"class":355},"svObZ"," rest_json",[270,358,359],{"class":279},"(url, ",[270,361,362],{"class":275},"**",[270,364,365],{"class":279},"params):\n",[270,367,369,372,375],{"class":109,"line":368},9,[270,370,371],{"class":279},"    q ",[270,373,374],{"class":275},"=",[270,376,377],{"class":279}," QUrl(url)\n",[270,379,381,384,386,389,392,395,398,401,404,407,409,411,414,416,418,421,424,427,430,433,436,439,442,444],{"class":109,"line":380},10,[270,382,383],{"class":279},"    query ",[270,385,374],{"class":275},[270,387,388],{"class":340}," \"&\"",[270,390,391],{"class":279},".join(",[270,393,394],{"class":275},"f",[270,396,397],{"class":340},"\"",[270,399,400],{"class":333},"{",[270,402,403],{"class":279},"k",[270,405,406],{"class":333},"}",[270,408,374],{"class":340},[270,410,400],{"class":333},[270,412,413],{"class":279},"v",[270,415,406],{"class":333},[270,417,397],{"class":340},[270,419,420],{"class":275}," for",[270,422,423],{"class":279}," k, v ",[270,425,426],{"class":275},"in",[270,428,429],{"class":279}," {",[270,431,432],{"class":340},"\"f\"",[270,434,435],{"class":279},": ",[270,437,438],{"class":340},"\"json\"",[270,440,441],{"class":279},", ",[270,443,362],{"class":275},[270,445,446],{"class":279},"params}.items())\n",[270,448,450],{"class":109,"line":449},11,[270,451,452],{"class":279},"    q.setQuery(query)\n",[270,454,456,459,461],{"class":109,"line":455},12,[270,457,458],{"class":279},"    request ",[270,460,374],{"class":275},[270,462,463],{"class":279}," QgsBlockingNetworkRequest()\n",[270,465,467,470,473,476],{"class":109,"line":466},13,[270,468,469],{"class":275},"    if",[270,471,472],{"class":279}," request.get(QNetworkRequest(q)) ",[270,474,475],{"class":275},"!=",[270,477,478],{"class":279}," QgsBlockingNetworkRequest.NoError:\n",[270,480,482,485,488],{"class":109,"line":481},14,[270,483,484],{"class":275},"        raise",[270,486,487],{"class":333}," RuntimeError",[270,489,490],{"class":279},"(request.errorMessage())\n",[270,492,494,497,500,503],{"class":109,"line":493},15,[270,495,496],{"class":275},"    return",[270,498,499],{"class":279}," json.loads(",[270,501,502],{"class":333},"bytes",[270,504,505],{"class":279},"(request.reply().content()))\n",[270,507,509],{"class":109,"line":508},16,[270,510,327],{"emptyLinePlaceholder":326},[270,512,514,517,519,522,524],{"class":109,"line":513},17,[270,515,516],{"class":279},"info ",[270,518,374],{"class":275},[270,520,521],{"class":279}," rest_json(",[270,523,334],{"class":333},[270,525,526],{"class":279},")\n",[270,528,530,533,536,539,542,545,548,551],{"class":109,"line":529},18,[270,531,532],{"class":333},"print",[270,534,535],{"class":279},"(info[",[270,537,538],{"class":340},"\"name\"",[270,540,541],{"class":279},"], info[",[270,543,544],{"class":340},"\"geometryType\"",[270,546,547],{"class":279},"], info.get(",[270,549,550],{"class":340},"\"maxRecordCount\"",[270,552,553],{"class":279},"))\n",[270,555,557,559,562,565,568,571,574,577],{"class":109,"line":556},19,[270,558,532],{"class":333},[270,560,561],{"class":279},"(",[270,563,564],{"class":340},"\"spatial reference:\"",[270,566,567],{"class":279},", info[",[270,569,570],{"class":340},"\"extent\"",[270,572,573],{"class":279},"][",[270,575,576],{"class":340},"\"spatialReference\"",[270,578,579],{"class":279},"])\n",[270,581,583,586,588,590,592,594,597,600,602,606,608,611,613,616,618,621,624,627],{"class":109,"line":582},20,[270,584,585],{"class":279},"count ",[270,587,374],{"class":275},[270,589,521],{"class":279},[270,591,394],{"class":275},[270,593,397],{"class":340},[270,595,596],{"class":333},"{LAYER_URL}",[270,598,599],{"class":340},"\u002Fquery\"",[270,601,441],{"class":279},[270,603,605],{"class":604},"s9osk","where",[270,607,374],{"class":275},[270,609,610],{"class":340},"\"1=1\"",[270,612,441],{"class":279},[270,614,615],{"class":604},"returnCountOnly",[270,617,374],{"class":275},[270,619,620],{"class":340},"\"true\"",[270,622,623],{"class":279},")[",[270,625,626],{"class":340},"\"count\"",[270,628,629],{"class":279},"]\n",[270,631,633,635,637,640],{"class":109,"line":632},21,[270,634,532],{"class":333},[270,636,561],{"class":279},[270,638,639],{"class":340},"\"features on the server:\"",[270,641,642],{"class":279},", count)\n",[14,644,645,648,649,652,653,657,658,660,661,663],{},[225,646,647],{},"Breakdown:"," ",[18,650,651],{},"QgsBlockingNetworkRequest"," goes through QGIS's own network stack, so proxy settings, SSL configuration and custom certificate authorities configured in QGIS apply to this request exactly as they will to the provider — the pattern is covered in ",[38,654,656],{"href":655},"\u002Fspatial-data-processing-automation\u002Fweb-services-and-remote-data\u002Fmake-http-requests-with-qgsnetworkaccessmanager-pyqgis\u002F","making HTTP requests with QgsNetworkAccessManager",". ",[18,659,204],{}," is the most features the server returns in one response; the provider pages through larger layers automatically, but a layer of 400,000 features at 1,000 per page is 400 requests, and knowing that before starting is worth one extra call. ",[18,662,615],{}," asks the server to count without sending geometry, which is cheap even for very large layers.",[214,665,667],{"id":666},"load-features-as-a-vector-layer","Load features as a vector layer",[14,669,670,671,674,675,678],{},"The vector provider takes a URI of ",[18,672,673],{},"key='value'"," pairs, the same format as database layers, so ",[18,676,677],{},"QgsDataSourceUri"," builds it correctly.",[261,680,682],{"className":263,"code":681,"language":265,"meta":266,"style":266},"from qgis.core import QgsDataSourceUri, QgsVectorLayer, QgsProject\n\nuri = QgsDataSourceUri()\nuri.setParam(\"url\", LAYER_URL)\nuri.setParam(\"crs\", \"EPSG:27700\")\n\nmains = QgsVectorLayer(uri.uri(False), \"water mains (service)\", \"arcgisfeatureserver\")\nif not mains.isValid():\n    raise RuntimeError(mains.error().summary())\n\nprint(mains.featureCount(), \"features;\", mains.wkbType(), mains.crs().authid())\nQgsProject.instance().addMapLayer(mains)\n",[18,683,684,695,699,709,723,737,741,767,778,788,792,805],{"__ignoreMap":266},[270,685,686,688,690,692],{"class":109,"line":272},[270,687,286],{"class":275},[270,689,315],{"class":279},[270,691,276],{"class":275},[270,693,694],{"class":279}," QgsDataSourceUri, QgsVectorLayer, QgsProject\n",[270,696,697],{"class":109,"line":283},[270,698,327],{"emptyLinePlaceholder":326},[270,700,701,704,706],{"class":109,"line":297},[270,702,703],{"class":279},"uri ",[270,705,374],{"class":275},[270,707,708],{"class":279}," QgsDataSourceUri()\n",[270,710,711,714,717,719,721],{"class":109,"line":310},[270,712,713],{"class":279},"uri.setParam(",[270,715,716],{"class":340},"\"url\"",[270,718,441],{"class":279},[270,720,334],{"class":333},[270,722,526],{"class":279},[270,724,725,727,730,732,735],{"class":109,"line":323},[270,726,713],{"class":279},[270,728,729],{"class":340},"\"crs\"",[270,731,441],{"class":279},[270,733,734],{"class":340},"\"EPSG:27700\"",[270,736,526],{"class":279},[270,738,739],{"class":109,"line":330},[270,740,327],{"emptyLinePlaceholder":326},[270,742,743,746,748,751,754,757,760,762,765],{"class":109,"line":344},[270,744,745],{"class":279},"mains ",[270,747,374],{"class":275},[270,749,750],{"class":279}," QgsVectorLayer(uri.uri(",[270,752,753],{"class":333},"False",[270,755,756],{"class":279},"), ",[270,758,759],{"class":340},"\"water mains (service)\"",[270,761,441],{"class":279},[270,763,764],{"class":340},"\"arcgisfeatureserver\"",[270,766,526],{"class":279},[270,768,769,772,775],{"class":109,"line":349},[270,770,771],{"class":275},"if",[270,773,774],{"class":275}," not",[270,776,777],{"class":279}," mains.isValid():\n",[270,779,780,783,785],{"class":109,"line":368},[270,781,782],{"class":275},"    raise",[270,784,487],{"class":333},[270,786,787],{"class":279},"(mains.error().summary())\n",[270,789,790],{"class":109,"line":380},[270,791,327],{"emptyLinePlaceholder":326},[270,793,794,796,799,802],{"class":109,"line":449},[270,795,532],{"class":333},[270,797,798],{"class":279},"(mains.featureCount(), ",[270,800,801],{"class":340},"\"features;\"",[270,803,804],{"class":279},", mains.wkbType(), mains.crs().authid())\n",[270,806,807],{"class":109,"line":455},[270,808,809],{"class":279},"QgsProject.instance().addMapLayer(mains)\n",[14,811,812,814,815,818,819,822,823,826],{},[225,813,647],{}," The ",[18,816,817],{},"url"," points at a single layer — note the trailing ",[18,820,821],{},"\u002F0"," — because each vector layer maps to one REST layer. The ",[18,824,825],{},"crs"," parameter asks the server to return coordinates already projected into that CRS, which avoids reprojecting every feature locally; leave it out to receive the service's native spatial reference. The provider fetches features for the visible extent as you pan and caches them for the session, so the first draw of a large layer is slow and subsequent draws are fast. Attribute types come from the service's field definitions, including coded-value domains, which appear as plain codes rather than labels.",[14,828,829],{},[46,830,833,836,839,842,849,853,859,864,868,874,877,881,884,888,891,895,898,902,908,913,916,921,925],{"viewBox":831,"role":49,"ariaLabel":832,"xmlns":51},"0 0 760 256","How the provider pages through a large service: requests are made per visible extent, each response is capped at maxRecordCount, and the provider continues with offsets until the extent is complete, caching results for later draws",[53,834,835],{},"Paging through maxRecordCount",[57,837,838],{},"A map extent is requested from a service with a maximum record count of 2,000. The first response returns 2,000 features and signals more exist. The provider requests the next page with a result offset of 2,000, then 4,000, until the final page returns fewer than 2,000. The combined features are cached, so panning back to the same area does not repeat the requests. Copying the layer locally performs the same paging once for the whole service.",[61,840],{"x":63,"y":63,"width":64,"height":841,"fill":66},"256",[68,843,844],{},[71,845,847],{"id":846,"viewBox":74,"refX":75,"refY":76,"markerWidth":77,"markerHeight":77,"orient":78},"agsPageArrow",[80,848],{"d":82,"fill":83},[85,850,852],{"x":87,"y":851,"style":89,"fill":90,"textAnchor":91},"26","One extent, several pages, one cache",[61,854],{"x":95,"y":855,"width":856,"height":140,"rx":185,"fill":857,"stroke":858,"style":125},"60","150","#eff3ff","#2563eb",[85,860,863],{"x":861,"y":862,"style":171,"fill":858,"textAnchor":91},"99","92","page 1",[85,865,867],{"x":861,"y":866,"style":106,"fill":83,"textAnchor":91},"114","offset 0",[109,869],{"x1":870,"y1":871,"x2":872,"y2":871,"stroke":83,"style":873},"174","100","206","stroke-width:1.8;marker-end:url(#agsPageArrow)",[61,875],{"x":876,"y":855,"width":856,"height":140,"rx":185,"fill":857,"stroke":858,"style":125},"214",[85,878,880],{"x":879,"y":862,"style":171,"fill":858,"textAnchor":91},"289","page 2",[85,882,883],{"x":879,"y":866,"style":106,"fill":83,"textAnchor":91},"offset 2000",[109,885],{"x1":886,"y1":871,"x2":887,"y2":871,"stroke":83,"style":873},"364","396",[61,889],{"x":890,"y":855,"width":856,"height":140,"rx":185,"fill":857,"stroke":858,"style":125},"404",[85,892,894],{"x":893,"y":862,"style":171,"fill":858,"textAnchor":91},"479","page 3",[85,896,897],{"x":893,"y":866,"style":106,"fill":83,"textAnchor":91},"offset 4000 · 873",[109,899],{"x1":900,"y1":871,"x2":901,"y2":871,"stroke":83,"style":873},"554","586",[61,903],{"x":904,"y":855,"width":905,"height":140,"rx":185,"fill":906,"stroke":907,"style":125},"594","142","#e8efe6","#15803d",[85,909,912],{"x":910,"y":862,"style":171,"fill":911,"textAnchor":91},"665","#166534","cached",[85,914,915],{"x":910,"y":866,"style":199,"fill":83,"textAnchor":91},"4,873 features",[61,917],{"x":918,"y":919,"width":182,"height":920,"rx":185,"fill":99,"stroke":100,"style":101},"120","172","56",[85,922,924],{"x":87,"y":211,"style":923,"fill":83,"textAnchor":91},"text-anchor:middle;font-size:10.5px;font-family:sans-serif","the last page is short, so the provider stops",[85,926,927],{"x":87,"y":183,"style":199,"fill":100,"textAnchor":91},"a local copy pays this cost once instead of every session",[214,929,931],{"id":930},"add-a-mapserver-as-a-raster-basemap","Add a MapServer as a raster basemap",[14,933,934],{},"Map services render images on the server. They are the right choice for backdrops — aerial imagery, a cadastral basemap, a styled utility overview — where you want the publisher's cartography and do not need the features themselves.",[261,936,938],{"className":263,"code":937,"language":265,"meta":266,"style":266},"from qgis.core import QgsRasterLayer\n\nms = QgsDataSourceUri()\nms.setParam(\"url\", \"https:\u002F\u002Fgis.example.gov\u002Farcgis\u002Frest\u002Fservices\u002FBasemap\u002FMapServer\")\nms.setParam(\"format\", \"png32\")\nms.setParam(\"crs\", \"EPSG:27700\")\nms.setParam(\"layer\", \"\")\n\nbasemap = QgsRasterLayer(ms.uri(False), \"council basemap\", \"arcgismapserver\")\nprint(basemap.isValid(), basemap.dataProvider().description())\nQgsProject.instance().addMapLayer(basemap, False)\nQgsProject.instance().layerTreeRoot().insertLayer(-1, basemap)\n",[18,939,940,951,955,964,978,992,1004,1018,1022,1046,1053,1062],{"__ignoreMap":266},[270,941,942,944,946,948],{"class":109,"line":272},[270,943,286],{"class":275},[270,945,315],{"class":279},[270,947,276],{"class":275},[270,949,950],{"class":279}," QgsRasterLayer\n",[270,952,953],{"class":109,"line":283},[270,954,327],{"emptyLinePlaceholder":326},[270,956,957,960,962],{"class":109,"line":297},[270,958,959],{"class":279},"ms ",[270,961,374],{"class":275},[270,963,708],{"class":279},[270,965,966,969,971,973,976],{"class":109,"line":310},[270,967,968],{"class":279},"ms.setParam(",[270,970,716],{"class":340},[270,972,441],{"class":279},[270,974,975],{"class":340},"\"https:\u002F\u002Fgis.example.gov\u002Farcgis\u002Frest\u002Fservices\u002FBasemap\u002FMapServer\"",[270,977,526],{"class":279},[270,979,980,982,985,987,990],{"class":109,"line":323},[270,981,968],{"class":279},[270,983,984],{"class":340},"\"format\"",[270,986,441],{"class":279},[270,988,989],{"class":340},"\"png32\"",[270,991,526],{"class":279},[270,993,994,996,998,1000,1002],{"class":109,"line":330},[270,995,968],{"class":279},[270,997,729],{"class":340},[270,999,441],{"class":279},[270,1001,734],{"class":340},[270,1003,526],{"class":279},[270,1005,1006,1008,1011,1013,1016],{"class":109,"line":344},[270,1007,968],{"class":279},[270,1009,1010],{"class":340},"\"layer\"",[270,1012,441],{"class":279},[270,1014,1015],{"class":340},"\"\"",[270,1017,526],{"class":279},[270,1019,1020],{"class":109,"line":349},[270,1021,327],{"emptyLinePlaceholder":326},[270,1023,1024,1027,1029,1032,1034,1036,1039,1041,1044],{"class":109,"line":368},[270,1025,1026],{"class":279},"basemap ",[270,1028,374],{"class":275},[270,1030,1031],{"class":279}," QgsRasterLayer(ms.uri(",[270,1033,753],{"class":333},[270,1035,756],{"class":279},[270,1037,1038],{"class":340},"\"council basemap\"",[270,1040,441],{"class":279},[270,1042,1043],{"class":340},"\"arcgismapserver\"",[270,1045,526],{"class":279},[270,1047,1048,1050],{"class":109,"line":380},[270,1049,532],{"class":333},[270,1051,1052],{"class":279},"(basemap.isValid(), basemap.dataProvider().description())\n",[270,1054,1055,1058,1060],{"class":109,"line":449},[270,1056,1057],{"class":279},"QgsProject.instance().addMapLayer(basemap, ",[270,1059,753],{"class":333},[270,1061,526],{"class":279},[270,1063,1064,1067,1070,1073],{"class":109,"line":455},[270,1065,1066],{"class":279},"QgsProject.instance().layerTreeRoot().insertLayer(",[270,1068,1069],{"class":275},"-",[270,1071,1072],{"class":333},"1",[270,1074,1075],{"class":279},", basemap)\n",[14,1077,1078,1080,1081,1084,1085,1088,1089,248],{},[225,1079,647],{}," Leaving ",[18,1082,1083],{},"layer"," empty requests the whole map with the publisher's layer visibility; naming a layer id restricts the image to that sublayer. ",[18,1086,1087],{},"png32"," keeps transparency, which matters when the basemap sits above another layer. Services that publish pre-rendered tile caches are served as tiles, which is much faster than dynamic images at every pan. Inserting the layer at the bottom of the layer tree keeps it underneath the vector data, as in ",[38,1090,1092],{"href":1091},"\u002Fspatial-data-processing-automation\u002Fweb-services-and-remote-data\u002Fadd-xyz-tile-basemap-pyqgis\u002F","adding an XYZ tile basemap",[214,1094,1096],{"id":1095},"authenticate-against-secured-services","Authenticate against secured services",[14,1098,1099],{},"Many services require an Esri token or an organisation login. QGIS handles both through authentication configurations, so the credential never appears in a script, a project file or a layer source.",[261,1101,1103],{"className":263,"code":1102,"language":265,"meta":266,"style":266},"from qgis.core import QgsApplication\n\nmanager = QgsApplication.authManager()\nconfig_id = \"ags0001\"\nif config_id not in manager.configIds():\n    raise RuntimeError(f\"create auth config {config_id} in Settings → Options → Authentication\")\n\nsecured = QgsDataSourceUri()\nsecured.setParam(\"url\", \"https:\u002F\u002Fgis.example.gov\u002Farcgis\u002Frest\u002Fservices\u002FSecure\u002FAssets\u002FFeatureServer\u002F2\")\nsecured.setAuthConfigId(config_id)\n\nassets = QgsVectorLayer(secured.uri(False), \"assets (secured)\", \"arcgisfeatureserver\")\nprint(assets.isValid(), assets.featureCount())\n",[18,1104,1105,1116,1120,1130,1140,1156,1181,1185,1194,1208,1213,1217,1240],{"__ignoreMap":266},[270,1106,1107,1109,1111,1113],{"class":109,"line":272},[270,1108,286],{"class":275},[270,1110,315],{"class":279},[270,1112,276],{"class":275},[270,1114,1115],{"class":279}," QgsApplication\n",[270,1117,1118],{"class":109,"line":283},[270,1119,327],{"emptyLinePlaceholder":326},[270,1121,1122,1125,1127],{"class":109,"line":297},[270,1123,1124],{"class":279},"manager ",[270,1126,374],{"class":275},[270,1128,1129],{"class":279}," QgsApplication.authManager()\n",[270,1131,1132,1135,1137],{"class":109,"line":310},[270,1133,1134],{"class":279},"config_id ",[270,1136,374],{"class":275},[270,1138,1139],{"class":340}," \"ags0001\"\n",[270,1141,1142,1144,1147,1150,1153],{"class":109,"line":323},[270,1143,771],{"class":275},[270,1145,1146],{"class":279}," config_id ",[270,1148,1149],{"class":275},"not",[270,1151,1152],{"class":275}," in",[270,1154,1155],{"class":279}," manager.configIds():\n",[270,1157,1158,1160,1162,1164,1166,1169,1171,1174,1176,1179],{"class":109,"line":330},[270,1159,782],{"class":275},[270,1161,487],{"class":333},[270,1163,561],{"class":279},[270,1165,394],{"class":275},[270,1167,1168],{"class":340},"\"create auth config ",[270,1170,400],{"class":333},[270,1172,1173],{"class":279},"config_id",[270,1175,406],{"class":333},[270,1177,1178],{"class":340}," in Settings → Options → Authentication\"",[270,1180,526],{"class":279},[270,1182,1183],{"class":109,"line":344},[270,1184,327],{"emptyLinePlaceholder":326},[270,1186,1187,1190,1192],{"class":109,"line":349},[270,1188,1189],{"class":279},"secured ",[270,1191,374],{"class":275},[270,1193,708],{"class":279},[270,1195,1196,1199,1201,1203,1206],{"class":109,"line":368},[270,1197,1198],{"class":279},"secured.setParam(",[270,1200,716],{"class":340},[270,1202,441],{"class":279},[270,1204,1205],{"class":340},"\"https:\u002F\u002Fgis.example.gov\u002Farcgis\u002Frest\u002Fservices\u002FSecure\u002FAssets\u002FFeatureServer\u002F2\"",[270,1207,526],{"class":279},[270,1209,1210],{"class":109,"line":380},[270,1211,1212],{"class":279},"secured.setAuthConfigId(config_id)\n",[270,1214,1215],{"class":109,"line":449},[270,1216,327],{"emptyLinePlaceholder":326},[270,1218,1219,1222,1224,1227,1229,1231,1234,1236,1238],{"class":109,"line":455},[270,1220,1221],{"class":279},"assets ",[270,1223,374],{"class":275},[270,1225,1226],{"class":279}," QgsVectorLayer(secured.uri(",[270,1228,753],{"class":333},[270,1230,756],{"class":279},[270,1232,1233],{"class":340},"\"assets (secured)\"",[270,1235,441],{"class":279},[270,1237,764],{"class":340},[270,1239,526],{"class":279},[270,1241,1242,1244],{"class":109,"line":466},[270,1243,532],{"class":333},[270,1245,1246],{"class":279},"(assets.isValid(), assets.featureCount())\n",[14,1248,1249,1251,1252,1256,1257,1260,1261,1264,1265,1268,1269,1272],{},[225,1250,647],{}," The authentication configuration — typically ",[1253,1254,1255],"em",{},"Basic"," for ArcGIS Server's built-in token exchange, ",[1253,1258,1259],{},"OAuth2"," for ArcGIS Online and Portal, or ",[1253,1262,1263],{},"ESRI token"," for a pre-issued token — is created once per machine, interactively or by a setup script, and scripts refer to it only by its seven-character id. ",[18,1266,1267],{},"setAuthConfigId"," adds ",[18,1270,1271],{},"authcfg="," to the URI, and the provider attaches the credential to every request, refreshing tokens as needed. For unattended jobs on servers, create the configuration during provisioning and protect the authentication database with a master password supplied from the environment.",[214,1274,1276],{"id":1275},"copy-the-data-locally-for-analysis","Copy the data locally for analysis",[14,1278,1279],{},"Working directly against a remote layer is fine for display and small queries. For analysis — joins, overlays, repeated iteration — copy the features into a GeoPackage once. It is faster, it is reproducible, and it stops a long script failing half-way because the server rate-limited you.",[14,1281,1282],{},[46,1283,1286,1289,1292,1295,1298,1302,1307,1311,1315,1318,1322,1325,1329,1332,1335,1338],{"viewBox":1284,"role":49,"ariaLabel":1285,"xmlns":51},"0 0 760 236","Remote versus local layer for analysis: every operation on a remote layer triggers network requests and depends on the server being up, while a local copy reads from disk and records when the snapshot was taken",[53,1287,1288],{},"Snapshot before you analyse",[57,1290,1291],{},"Left: an overlay against a remote service layer triggers paged requests for every read, is slowed by network latency, fails if the server is down, and produces results that change as the service updates. Right: a GeoPackage snapshot with a download timestamp in its metadata reads from disk, runs the same overlay in a fraction of the time, and gives the same answer every time.",[61,1293],{"x":63,"y":63,"width":64,"height":1294,"fill":66},"236",[85,1296,1297],{"x":87,"y":851,"style":89,"fill":90,"textAnchor":91},"Download once, analyse many times",[61,1299],{"x":95,"y":98,"width":1300,"height":919,"rx":185,"fill":133,"stroke":134,"style":1301},"344","stroke-width:2.5",[85,1303,1306],{"x":211,"y":1304,"style":1305,"fill":134,"textAnchor":91},"70","text-anchor:middle;font-size:12px;font-weight:bold;font-family:sans-serif","analyse the service directly",[85,1308,1310],{"x":211,"y":1309,"style":923,"fill":83,"textAnchor":91},"102","requests on every read",[85,1312,1314],{"x":211,"y":1313,"style":923,"fill":83,"textAnchor":91},"126","fails when the server does",[85,1316,1317],{"x":211,"y":856,"style":923,"fill":83,"textAnchor":91},"results change as data updates",[85,1319,1321],{"x":211,"y":1320,"style":199,"fill":100,"textAnchor":91},"190","fine for a quick look",[61,1323],{"x":1324,"y":98,"width":1300,"height":919,"rx":185,"fill":906,"stroke":907,"style":1301},"392",[85,1326,1328],{"x":1327,"y":1304,"style":1305,"fill":911,"textAnchor":91},"564","analyse a local snapshot",[85,1330,1331],{"x":1327,"y":1309,"style":923,"fill":83,"textAnchor":91},"reads from disk",[85,1333,1334],{"x":1327,"y":1313,"style":923,"fill":83,"textAnchor":91},"works offline",[85,1336,1337],{"x":1327,"y":856,"style":923,"fill":83,"textAnchor":91},"same answer every run",[85,1339,1340],{"x":1327,"y":1320,"style":199,"fill":100,"textAnchor":91},"record when it was taken",[261,1342,1344],{"className":263,"code":1343,"language":265,"meta":266,"style":266},"import processing\nfrom datetime import datetime, timezone\n\nsnapshot = processing.run(\"native:savefeatures\", {\n    \"INPUT\": mains,\n    \"OUTPUT\": \"\u002Fdata\u002Fcache\u002Fwater_mains.gpkg\",\n    \"LAYER_NAME\": \"water_mains\",\n})[\"OUTPUT\"]\n\nlocal = QgsVectorLayer(snapshot, \"water mains\", \"ogr\")\nmetadata = local.metadata()\nmetadata.setAbstract(f\"Snapshot of {LAYER_URL} taken \"\n                     f\"{datetime.now(timezone.utc):%Y-%m-%d %H:%M} UTC; \"\n                     f\"{local.featureCount()} features.\")\nlocal.setMetadata(metadata)\nlocal.saveNamedMetadata(snapshot + \"|layername=water_mains\")\nprint(local.featureCount(), \"of\", count, \"features copied\")\n",[18,1345,1346,1353,1365,1369,1385,1393,1406,1418,1428,1432,1452,1462,1477,1521,1539,1544,1557],{"__ignoreMap":266},[270,1347,1348,1350],{"class":109,"line":272},[270,1349,276],{"class":275},[270,1351,1352],{"class":279}," processing\n",[270,1354,1355,1357,1360,1362],{"class":109,"line":283},[270,1356,286],{"class":275},[270,1358,1359],{"class":279}," datetime ",[270,1361,276],{"class":275},[270,1363,1364],{"class":279}," datetime, timezone\n",[270,1366,1367],{"class":109,"line":297},[270,1368,327],{"emptyLinePlaceholder":326},[270,1370,1371,1374,1376,1379,1382],{"class":109,"line":310},[270,1372,1373],{"class":279},"snapshot ",[270,1375,374],{"class":275},[270,1377,1378],{"class":279}," processing.run(",[270,1380,1381],{"class":340},"\"native:savefeatures\"",[270,1383,1384],{"class":279},", {\n",[270,1386,1387,1390],{"class":109,"line":323},[270,1388,1389],{"class":340},"    \"INPUT\"",[270,1391,1392],{"class":279},": mains,\n",[270,1394,1395,1398,1400,1403],{"class":109,"line":330},[270,1396,1397],{"class":340},"    \"OUTPUT\"",[270,1399,435],{"class":279},[270,1401,1402],{"class":340},"\"\u002Fdata\u002Fcache\u002Fwater_mains.gpkg\"",[270,1404,1405],{"class":279},",\n",[270,1407,1408,1411,1413,1416],{"class":109,"line":344},[270,1409,1410],{"class":340},"    \"LAYER_NAME\"",[270,1412,435],{"class":279},[270,1414,1415],{"class":340},"\"water_mains\"",[270,1417,1405],{"class":279},[270,1419,1420,1423,1426],{"class":109,"line":349},[270,1421,1422],{"class":279},"})[",[270,1424,1425],{"class":340},"\"OUTPUT\"",[270,1427,629],{"class":279},[270,1429,1430],{"class":109,"line":368},[270,1431,327],{"emptyLinePlaceholder":326},[270,1433,1434,1437,1439,1442,1445,1447,1450],{"class":109,"line":380},[270,1435,1436],{"class":279},"local ",[270,1438,374],{"class":275},[270,1440,1441],{"class":279}," QgsVectorLayer(snapshot, ",[270,1443,1444],{"class":340},"\"water mains\"",[270,1446,441],{"class":279},[270,1448,1449],{"class":340},"\"ogr\"",[270,1451,526],{"class":279},[270,1453,1454,1457,1459],{"class":109,"line":449},[270,1455,1456],{"class":279},"metadata ",[270,1458,374],{"class":275},[270,1460,1461],{"class":279}," local.metadata()\n",[270,1463,1464,1467,1469,1472,1474],{"class":109,"line":455},[270,1465,1466],{"class":279},"metadata.setAbstract(",[270,1468,394],{"class":275},[270,1470,1471],{"class":340},"\"Snapshot of ",[270,1473,596],{"class":333},[270,1475,1476],{"class":340}," taken \"\n",[270,1478,1479,1482,1484,1486,1489,1492,1495,1498,1501,1503,1506,1508,1511,1513,1516,1518],{"class":109,"line":466},[270,1480,1481],{"class":275},"                     f",[270,1483,397],{"class":340},[270,1485,400],{"class":333},[270,1487,1488],{"class":279},"datetime.now(timezone.utc):",[270,1490,1491],{"class":275},"%",[270,1493,1494],{"class":279},"Y",[270,1496,1497],{"class":275},"-%",[270,1499,1500],{"class":279},"m",[270,1502,1497],{"class":275},[270,1504,1505],{"class":279},"d ",[270,1507,1491],{"class":275},[270,1509,1510],{"class":279},"H:",[270,1512,1491],{"class":275},[270,1514,1515],{"class":279},"M",[270,1517,406],{"class":333},[270,1519,1520],{"class":340}," UTC; \"\n",[270,1522,1523,1525,1527,1529,1532,1534,1537],{"class":109,"line":481},[270,1524,1481],{"class":275},[270,1526,397],{"class":340},[270,1528,400],{"class":333},[270,1530,1531],{"class":279},"local.featureCount()",[270,1533,406],{"class":333},[270,1535,1536],{"class":340}," features.\"",[270,1538,526],{"class":279},[270,1540,1541],{"class":109,"line":493},[270,1542,1543],{"class":279},"local.setMetadata(metadata)\n",[270,1545,1546,1549,1552,1555],{"class":109,"line":508},[270,1547,1548],{"class":279},"local.saveNamedMetadata(snapshot ",[270,1550,1551],{"class":275},"+",[270,1553,1554],{"class":340}," \"|layername=water_mains\"",[270,1556,526],{"class":279},[270,1558,1559,1561,1564,1567,1570,1573],{"class":109,"line":513},[270,1560,532],{"class":333},[270,1562,1563],{"class":279},"(local.featureCount(), ",[270,1565,1566],{"class":340},"\"of\"",[270,1568,1569],{"class":279},", count, ",[270,1571,1572],{"class":340},"\"features copied\"",[270,1574,526],{"class":279},[14,1576,1577,648,1579,1582,1583,1585,1586,1590],{},[225,1578,647],{},[18,1580,1581],{},"native:savefeatures"," pages through the whole service once and writes everything to disk. Comparing the copied count with the server's ",[18,1584,615],{}," answer catches a truncated download — the classic symptom of a service whose paging is misconfigured. Recording the source URL and a UTC timestamp in the layer's metadata answers the question every reviewer eventually asks, \"how old is this?\", and is the same idea as ",[38,1587,1589],{"href":1588},"\u002Fpyqgis-fundamentals-environment-setup\u002Fworking-with-qgis-projects\u002Fread-and-write-layer-metadata-pyqgis\u002F","reading and writing layer metadata",". Refresh the snapshot on a schedule when the analysis needs current data.",[214,1592,1594],{"id":1593},"qgis-version-compatibility","QGIS version compatibility",[14,1596,1597,1598,1600,1601,1603,1604,1607,1608,1611,1612,1615],{},"The ",[18,1599,28],{}," and ",[18,1602,32],{}," providers have been part of QGIS since 3.0. Support for services that return PBF-encoded features, OAuth2 against ArcGIS Online, and automatic paging with ",[18,1605,1606],{},"resultOffset"," improved through the 3.2x releases, so use 3.40 or later against modern services. ",[18,1609,1610],{},"QgsBlockingNetworkRequest.NoError"," becomes ",[18,1613,1614],{},"QgsBlockingNetworkRequest.ErrorCode.NoError"," on the QGIS 4 series. Esri may change the REST API independently of QGIS; test scripts against the services they use after major server upgrades.",[214,1617,1619],{"id":1618},"troubleshooting","Troubleshooting",[219,1621,1622,1628,1634,1642,1648],{},[222,1623,1624,1627],{},[225,1625,1626],{},"The layer is invalid."," The URL points at the service rather than a numbered layer, or the server requires authentication.",[222,1629,1630,1633],{},[225,1631,1632],{},"Only 1,000 or 2,000 features arrive."," The server does not support pagination; request smaller extents or ask the publisher for a download.",[222,1635,1636,1639,1640,248],{},[225,1637,1638],{},"Coordinates land in the wrong place."," The service's spatial reference is a custom WKID QGIS cannot resolve; pass an explicit ",[18,1641,825],{},[222,1643,1644,1647],{},[225,1645,1646],{},"Field values are codes."," Coded-value domains are not translated; join a lookup table or read the domain from the layer's JSON.",[222,1649,1650,1653],{},[225,1651,1652],{},"Requests fail with SSL errors."," The server uses an internal certificate authority; add it in QGIS's SSL settings.",[214,1655,1657],{"id":1656},"conclusion","Conclusion",[14,1659,1660,1661,1663,1664,1666],{},"Inspect the layer's JSON first to learn its geometry, spatial reference, record limit and feature count. Load single REST layers with ",[18,1662,28],{},", basemaps with ",[18,1665,32],{},", and attach credentials through an authentication configuration. For anything more than display, copy the service into a GeoPackage, check the count, and record when the snapshot was taken.",[214,1668,1670],{"id":1669},"frequently-asked-questions","Frequently Asked Questions",[14,1672,1673,1676],{},[225,1674,1675],{},"Can I edit features on an ArcGIS Feature Service from QGIS?","\nEditing support depends on the QGIS version and service capabilities and is more limited than for WFS-T or PostGIS. Treat these services as read sources in scripts.",[14,1678,1679,1682,1683,1685,1686,1600,1689,1692],{},[225,1680,1681],{},"How do I list all layers in a service?","\nRequest the service URL with ",[18,1684,258],{},"; the ",[18,1687,1688],{},"layers",[18,1690,1691],{},"tables"," arrays list ids, names and types.",[14,1694,1695,1698],{},[225,1696,1697],{},"Do non-spatial tables work?","\nYes. Tables in a FeatureServer load as geometryless layers through the same provider.",[14,1700,1701,1704],{},[225,1702,1703],{},"Is this the same as the Esri \"ArcGIS REST\" connection in the browser panel?","\nYes. Connections saved there use the same providers, and a layer added from the browser shows the exact source string in its properties.",[214,1706,1708],{"id":1707},"related","Related",[219,1710,1711,1716,1722,1728,1733],{},[222,1712,1713,1715],{},[38,1714,41],{"href":40}," — the guide this recipe belongs to",[222,1717,1718],{},[38,1719,1721],{"href":1720},"\u002Fspatial-data-processing-automation\u002Fweb-services-and-remote-data\u002Fload-ogc-api-features-layer-pyqgis\u002F","Load an OGC API Features Layer in PyQGIS",[222,1723,1724],{},[38,1725,1727],{"href":1726},"\u002Fspatial-data-processing-automation\u002Fweb-services-and-remote-data\u002Fload-wfs-layer-pyqgis\u002F","Load a WFS Layer in PyQGIS",[222,1729,1730],{},[38,1731,1732],{"href":655},"Make HTTP Requests with QgsNetworkAccessManager in PyQGIS",[222,1734,1735],{},[38,1736,1738],{"href":1737},"\u002Fspatial-data-processing-automation\u002Flayer-data-sources-and-formats\u002Fdecode-and-build-data-source-uris-pyqgis\u002F","Decode and Build Data Source URIs in PyQGIS",[1740,1741,1742],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":266,"searchDepth":283,"depth":283,"links":1744},[1745,1746,1747,1748,1749,1750,1751,1752,1753,1754,1755],{"id":216,"depth":283,"text":217},{"id":251,"depth":283,"text":252},{"id":666,"depth":283,"text":667},{"id":930,"depth":283,"text":931},{"id":1095,"depth":283,"text":1096},{"id":1275,"depth":283,"text":1276},{"id":1593,"depth":283,"text":1594},{"id":1618,"depth":283,"text":1619},{"id":1656,"depth":283,"text":1657},{"id":1669,"depth":283,"text":1670},{"id":1707,"depth":283,"text":1708},"Read vector layers from an ArcGIS Server or ArcGIS Online FeatureServer with the arcgisfeatureserver provider, add cached MapServer layers as rasters, authenticate with tokens through QgsAuthManager, inspect service limits and copy the data locally for analysis.","md",{"slug":1759,"type":1760,"breadcrumb":1761,"datePublished":1762,"dateModified":1762},"load-arcgis-rest-feature-service-pyqgis","article","Load an ArcGIS REST Feature Service","2026-09-17","\u002Fspatial-data-processing-automation\u002Fweb-services-and-remote-data\u002Fload-arcgis-rest-feature-service-pyqgis",{"title":5,"description":1756},"spatial-data-processing-automation\u002Fweb-services-and-remote-data\u002Fload-arcgis-rest-feature-service-pyqgis\u002Findex","ELPORQNiuOkCSHJZwdaL2u3r155B7Y4zI5SSu8ViDYQ",1789632908645]