From public geodata to a honey-production estimate.
This is the practical handoff for another software team: which services SiBeela calls, how it calls them, how it turns their responses into parcels, and where each country's coverage stops.
Eduardo Marcos Alejos · Senior Programmer and Data Scientist · BeeLife — BeeLife European Beekeeping Coordination
Core distinction. A WMS layer paints an image on the map. A WFS, vector tile or ArcGIS feature request returns records and attributes that the model can actually calculate with. Seeing a cadastral layer does not mean crop data is available for prediction.
Every example URL in this document is a public provider URL or a placeholder such as YOUR_BACKEND. The document contains no production server address, service-account identity, private key, access token, API key or billing identifier. Example coordinates and JSON values are illustrative.
The reusable integration recipe
For Sweden, France, Italy, Belgium and Germany, the browser calls the public feature service through SiBeela's Node endpoint GET /proxy?url=.... The proxy relays the response, caches successful URLs for 10 minutes, retries server errors and rejects private/internal destinations. Spain's preferred vector route is implemented directly in the backend.
Build a geographic window. From the apiary centre and radius in kilometres: dLat = radiusKm / 111, dLon = radiusKm / (111 × cos(latitude)). Send the resulting bounding box in the axis order expected by that provider.
Request features in pages. Most country adapters use WFS 2.0 GetFeature with typeNames, outputFormat, srsName=EPSG:4326, bbox, count and startIndex. Request another page until it has fewer features than the page size.
Make records comparable. Read each polygon's centre, discard centres outside the requested circle, deduplicate on the provider ID, map local crop fields to cropKey/usoCode, record hectares and provenance.
Apply the bee model. The country crop catalogue maps recognised uses to floral species; monthly phenology, parcel area, distance and biological limits shape the estimate. Uncertain or forest parcels can be enriched with OSM and Dynamic World.
const upstream = new URL('https://data.geopf.fr/wfs');
upstream.search = new URLSearchParams({
SERVICE: 'WFS', VERSION: '2.0.0', REQUEST: 'GetFeature',
TYPENAMES: 'RPG.LATEST:parcelles_graphiques',
outputFormat: 'application/json', SRSNAME: 'EPSG:4326',
COUNT: '500', startIndex: '0',
BBOX: '2.30,48.80,2.40,48.90,EPSG:4326'
});
const response = await fetch('/proxy?url=' + encodeURIComponent(upstream));
if (!response.ok) throw new Error(`WFS HTTP ${response.status}`);
const geojson = await response.json();The country's production adapter is selected by BeeLifeCountries. Both the grid and geometric prediction choices route non-Spanish countries to the same country adapter. Their WFS census is therefore the operative parcel connection for those countries.
| Country | Actual analytical connection | Map connection | How specific is the source? |
|---|---|---|---|
| Spain | HubCloud GeoJSON vector tiles via Node; Catastro + SIGPAC WMS fallback | SIGPAC WMS | Parcel and declared product when present |
| Sweden | Jordbruksverket block WFS | Block/skifte WMS | Block land-use class; skifte shown, not sampled |
| France | IGN RPG WFS + code dictionary | RPG WMS | Declared agricultural parcel and culture code |
| Italy | Emilia-Romagna land-use WFS | National Catasto WMS; regional WFS overlay | Regional land-use category, not a national crop census |
| Belgium | Flanders WFS + Wallonia legacy 2023 WFS | Flanders WMS; Wallonia WFS overlay | Regional crop name/code; Wallonia migration required |
| Germany | Land-specific WFS JSON, WFS GML or ArcGIS REST | Fetched GeoJSON overlay | Crop parcels in some Länder; reference blocks in others |
How to make a request that can be reproduced
The provider's URL is only one part of a working connection. The layer name, CRS, BBOX order, output format, pagination and interpretation of the response are equally important. The examples below show the exact mechanics used by the adapters.
Find the layer first
Call ?service=WFS&request=GetCapabilities to discover feature type names, supported formats and CRS. Call ?service=WMS&request=GetCapabilities to discover image-layer names. A layer name can change by year; hard-coded names should be checked before release.
Know the coordinate order
GeoJSON geometry uses [longitude, latitude]. A WFS 2.0 EPSG:4326 BBOX is not consistent among these servers: the actual adapters use provider-specific orders. Never transpose a BBOX without testing a known point.
Page and test the circle
Use count and startIndex; stop after a short page. The BBOX only reduces the remote search area. The code then keeps parcels whose computed centre is within the requested radius and deduplicates IDs. Spain's vector route instead geometrically clips its polygons.
Separate observed and inferred
A declared culture code is stronger evidence than a generic land-use class. For forest/unknown records, the application may consult OSM tags and Dynamic World. Preserve the original source and the inferred/declared status with each result.
Concrete BBOX example
For an illustrative centre at latitude 48.8566, longitude 2.3522, radius 2.5 km, the approximation used by the adapters produces south 48.834077, west 2.317968, north 48.879123, east 2.386432. France sends 2.317968,48.834077,2.386432,48.879123,EPSG:4326. Wallonia and Emilia-Romagna reverse the coordinate pairs.
async function readPages({ baseUrl, typeName, outputFormat, bbox, pageSize = 500 }) {
const all = [];
for (let startIndex = 0; startIndex < 20000; startIndex += pageSize) {
const q = new URLSearchParams({
service: 'WFS', version: '2.0.0', request: 'GetFeature',
typeNames: typeName, outputFormat, srsName: 'EPSG:4326',
count: String(pageSize), startIndex: String(startIndex), bbox
});
const upstream = baseUrl + '?' + q.toString();
const response = await fetch('/proxy?url=' + encodeURIComponent(upstream));
if (!response.ok) throw new Error('Source HTTP ' + response.status);
const page = await response.json();
const features = Array.isArray(page.features) ? page.features : [];
all.push(...features);
if (features.length < pageSize) break;
}
return all;
}This is a didactic template for GeoJSON-producing sources. German GML and ArcGIS REST need their separate parsers and query parameters, shown in the Germany chapter. Production code should add timeouts, cache, response-size controls, cancellation and provider-specific maximum pages.
The normalized parcel object
The web app converts remote schemas into comparable records. The example below is illustrative, not a captured API response; the keys match fields used by the model.
{
"id": "FR_example-123", "countryCode": "FR",
"source": "RPG Geoplateforme WFS",
"lat": 48.851, "lng": 2.349,
"displayName": "Colza hiver", "cropKey": "CZH",
"usoCode": "TA", "cultivoEspecifico": "Colza hiver",
"superficieNum": 1.8, "superficie": "1.80 ha",
"regadio_secano": "SECANO",
"valorApicola": 0.73
}valorApicola is a local, season-sensitive ranking score, not measured honey yield. cropKey is the bridge to a country botanical catalogue. If a provider lacks an area value, some current adapters calculate it from geometry; Sweden, France and Italy can fall back to 1 ha. A receiving team should flag that as estimated rather than silently treating it as surveyed area.
Credentials, costs and safe handoff
The public geospatial URL templates are safe to explain. The ability to charge your account or consume your quota comes from credentials, project settings and access to your own backend. This guide deliberately contains none of those.
| Connection | How this repository authenticates | What the recipient must supply | Cost or access point to check |
|---|---|---|---|
| Country WMS/WFS, ArcGIS and SIGPAC public endpoints | No application key is embedded in the request construction. | Their own client/server, attribution and provider terms. | Public access does not automatically permit redistributing raw data or ignoring limits. |
| Google Earth Engine / Dynamic World | Private service-account JSON on the Node server; never sent to the browser. | Their own Google Cloud/Earth Engine project and identity. | Commercial use may require a paid Earth Engine setup; compute quotas are per project. Google access guide. |
| Open-Meteo forecast | The code calls the public api.open-meteo.com endpoint without a key. | Their own appropriate use agreement if commercial. | Open-Meteo says its free API is for non-commercial use; commercial access has a separate keyed endpoint. Pricing and terms. |
| Nominatim / OSM public map services | No key in these request URLs. | Their own usage policy compliance or suitable provider. | The public Nominatim service limits heavy use and asks for attribution and an identifying user agent/referer. Usage policy. |
Protect the billable backend, not only the JSON key. In the current application, Dynamic World requests reach Earth Engine through the application's Node endpoints. Publishing your production backend's address or giving unrestricted access to those endpoints could let others use your project indirectly. This handoff uses YOUR_BACKEND placeholders and shows no real deployment host. A receiving team should run its own backend and add authentication/rate limits to its Earth Engine routes before public deployment.
Public service base URLs, public layer names, parameter names, response field names, the high-level data flow and open-source integration examples.
Private-key contents, API keys, bearer tokens, cookies, Google project IDs, billing identifiers, your deployed server IP/host or private user data.
This explains the current source code. It does not claim every remote URL is healthy today, nor that every provider grants every downstream use.
Spain · SIGPAC / MAPA
National agricultural parcel data, with a fast vector route and older fallbacks.
Visual connection: Leaflet requests SIGPAC WMS version 1.3.0 as transparent PNG. The layer names are AU.Sigpac:recinto, AU.Sigpac:cultivo_declarado and AU.Sigpac:e_paisaje. A clicked pixel can be queried with WMS GetFeatureInfo through /proxy.
Calculation connection: the browser calls its own backend GET /sigpac-parcels-in-radius. That backend requests HubCloud recinto and cultivo_declarado GeoJSON tiles at zoom 15, joins them by SIGPAC identity, loads cod_producto.json and cod_uso_sigpac.json for labels, clips polygons to the circle with Turf, and returns parcel area and crop data.
GET /sigpac-parcels-in-radius?lat=40.4637&lng=-3.7492&radiusKm=2.5&minAreaM2=1000&strategy=stratified&maxParcels=600&minPerStratum=20&seedMode=deterministic
Upstream tile template:
https://sigpac-hubcloud.es/mvt/{recinto|cultivo_declarado}@3857@geojson/15/{x}/{y}.geojson
Code tables:
https://sigpac-hubcloud.es/codigossigpac/cod_producto.json
https://sigpac-hubcloud.es/codigossigpac/cod_uso_sigpac.jsonThe endpoint returns parcels, sampling, counts, tile errors and clipped area. Default sampling is stratified when needed; strategy=all requests every matching parcel. The current backend caps the circle radius at 10 km and rejects requests that need more than 160 z15 tiles.
Fallback and scope. If the vector route fails, the app tries /parcels-in-radius: Catastro INSPIRE WFS supplies geometry and SIGPAC WMS GetFeatureInfo enriches centroids. A separate grid mode samples WMS points. Catastro geometry is not a crop declaration. Spain's larger regional view uses /sigpac-regional-heatmap and /regional-progress/:jobId.
What each Spanish request contributes
| Request | Input | Output the app uses | Purpose |
|---|---|---|---|
HubCloud recinto z15 GeoJSON tile | z/x/y tile coordinates | Polygon, uso_sigpac, superficie, coef_regadio, SIGPAC identity columns | Parcel geometry and general agricultural use. |
HubCloud cultivo_declarado z15 GeoJSON tile | The same tile coordinates | parc_producto, parc_supcult, parc_sistexp, exp_ano, SIGPAC identity columns | Declared crop and cultivation system, when present. |
| HubCloud code tables | cod_producto.json, cod_uso_sigpac.json | Code-to-description maps | Turn numerical/short codes into readable product and use names. |
| Catastro INSPIRE WFS fallback | cp:CadastralParcel and a BBOX | GML parcel outline and reference | Geometry if HubCloud vector route is unavailable. |
SIGPAC WMS GetFeatureInfo fallback | Projected BBOX and image pixel i/j | HTML for recinto plus cultivo_declarado | Enrich a Catastro centroid with agricultural use/crop. |
The seven-part SIGPAC key is provincia:municipio:agregado:zona:poligono:parcela:recinto. The server uses it to join recinto and declared-crop tiles. The same complete polygon can be repeated in adjacent tiles, so it keeps the largest clipped intersection for each key rather than summing duplicates. Crop data is absent for some recintos; the model then uses a lower-confidence land-use profile or enrichment.
Catastro geometry:
GET https://ovc.catastro.meh.es/INSPIRE/wfsCP.aspx
?service=WFS&request=GetFeature&typenames=cp:CadastralParcel
&srsname=EPSG:4326&bbox={south},{west},{north},{east},EPSG:4326
&maxfeatures=800
SIGPAC WMS attribute lookup (the browser sends the URL through /proxy):
GET https://sigpac-hubcloud.es/wms
?service=WMS&version=1.3.0&request=GetFeatureInfo
&layers=AU.Sigpac:recinto,AU.Sigpac:cultivo_declarado
&query_layers=AU.Sigpac:recinto,AU.Sigpac:cultivo_declarado
&info_format=text/html&crs=EPSG:3857
&bbox={projectedWest},{projectedSouth},{projectedEast},{projectedNorth}
&width=256&height=256&i=128&j=128The GetFeatureInfo bounding box is in metres in EPSG:3857, centred on the queried point; its image pixel is 128/128. The backend Catastro fallback defaults to 800 features (hard cap 2,000) and clips them to the circle. The constant used by this fallback requests cultivo_declarado; an adjacent code comment calls it linea_declaracion, so the constant is authoritative here.
How a returned Spanish parcel enters the model
Decode + clip. Convert any 3857 tile geometry to longitude/latitude; intersect with a 128-step apiary circle and drop pieces below minAreaM2.
Join + classify. Join crop and recinto on the seven-part key; map uso_sigpac and parc_producto through the public code tables. Convert parc_supcult from m² to ha and infer irrigation from coef_regadio/parc_sistexp.
Sample transparently. With strategy=stratified, sample by land-use stratum when the parcel count exceeds the target, attach sampling_weight and retain the deterministic seed. With strategy=all, each parcel has weight 1.
Estimate. Feed clipped hectares, crop/use, irrigation, coordinates and source confidence to honey_model.js. The model estimates weekly floral potential, then aggregates at apiary scale.
Response to handle: n_parcels_total_in_radius, n_parcels_returned, n_tile_errors, coverage_of_circle_pct, sampling and parcels. A non-zero tile-error count means the output may be incomplete even if the HTTP request succeeds. HTTP 413 means the chosen radius would request too many tiles. The server caches tiles for six hours and code tables for one day.
Regional route: /sigpac-regional-heatmap?lat=&lng=&radiusKm=&gridKm=&jobId= divides a larger circle into subareas and returns aggregated cells instead of thousands of parcel records. It is a separate Spain-only analysis path; the other country adapters do not expose that regional function.
Sweden · Jordbruksverket
Agricultural blocks from a public INSPIRE WFS.
WFS endpoint: http://epub.sjv.se/inspire/inspire/wfs. Query inspire:senaste_arslager_block; request application/json, EPSG:4326 and a longitude–latitude bounding box. The adapter asks for 500 features per page, up to 40 pages, through /proxy.
GET http://epub.sjv.se/inspire/inspire/wfs
?service=WFS&version=2.0.0&request=GetFeature
&typeNames=inspire:senaste_arslager_block
&outputFormat=application/json&srsName=EPSG:4326
&count=500&startIndex=0
&bbox={west},{south},{east},{north},EPSG:4326Read agoslag as the land-use label, areal as hectares and blockid as the stable key. Swedish terms are mapped to a canonical cropKey, a broad usoCode, and a month-sensitive beekeeping score. Leaflet displays inspire:senaste_arslager_block and inspire:senaste_arslager_skifte from the matching WMS endpoint.
Interpretation: the prediction query currently uses the block layer, even though a skifte layer can be displayed. The two Swedish URLs use http in the code, so a team deploying an HTTPS page must account for mixed-content restrictions and route these requests through a secure server endpoint.
Fields, translation and pagination
| Remote field | Normalized field | Rule in the adapter |
|---|---|---|
blockid | id = "SE_" + blockid | Deduplicates records across pages. |
agoslag (fallback KATEGORI) | displayName, cropKey, usoCode | Text matching: oilseed/rapeseed → raps; clover → klover; grassland → vall; woodland → FO. |
areal (fallback area) | superficieNum, superficie | Parsed as hectares by the current code; a missing/invalid value becomes 1. |
region_kod, kategori | regionKod, kategori | Retained for provenance/display. |
| GeoJSON geometry | lat, lng | Polygon centre is computed; outside-circle centres are removed. |
The adapter caches by rounded centre and radius, fetches 500 records per page, pauses briefly between full pages, and stops at an empty/short page or after 40 pages. On a WFS failure it logs the error and returns the records already collected; therefore a non-empty result can still be incomplete. A receiving implementation should expose an incomplete flag rather than treating partial pages as a full census.
Remote feature.properties:
{ "blockid": "example-42", "agoslag": "oljeväxter", "areal": 2.4 }
Normalized parcel:
{ "id": "SE_example-42", "countryCode": "SE",
"displayName": "oljeväxter", "cropKey": "raps",
"usoCode": "TA", "superficieNum": 2.4,
"source": "Jordbruksverket WFS" }Map click: when a Swedish overlay is visible, a tiny BBOX around the clicked coordinate requests up to 10 features from the visible block and/or skifte types. That click lookup is separate from the 500-record prediction query.
Provider-published HTTPS option. The Jordbruksverket GIS page publishes https://epub.sjv.se/inspire/inspire/wfs and https://epub.sjv.se/inspire/inspire/wms. The current source uses http://. A new integration should prefer the provider's published HTTPS addresses after checking capabilities and response parity. The block database is agricultural-support data, not a direct measure of flowering or nectar.
France · IGN Géoplateforme RPG
Graphical agricultural parcels and a culture-code dictionary.
The adapter queries https://data.geopf.fr/wfs via /proxy. Before parcel retrieval it fetches up to 500 entries from RPG.LATEST:codes_cultures to turn short crop codes into labels; a local code dictionary remains available if that call fails. Parcel pages are 500 features, up to 40 pages.
GET https://data.geopf.fr/wfs
?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature
&TYPENAMES=RPG.LATEST:parcelles_graphiques
&outputFormat=application/json&SRSNAME=EPSG:4326
&COUNT=500&startIndex=0
&BBOX={west},{south},{east},{north},EPSG:4326Map code_cultu to the crop code, cat_cult_p to category, surf_parc (or sf_adm_de) to hectares and id_parcel to identity. The crop code is the French cropKey used by the floral catalogue. WMS overlays at https://data.geopf.fr/wms-r/wms use LANDUSE.AGRICULTURE.LATEST and IGNF_RPG_PARCELLES-AGRICOLES-CATEGORISEES_2024.
Dictionary, fields and a record through the adapter
GET https://data.geopf.fr/wfs
?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature
&TYPENAMES=RPG.LATEST:codes_cultures
&outputFormat=application/json&COUNT=500| Remote value | Local use | Important handling |
|---|---|---|
code_cultu | cropKey | Resolve its display label through the remote dictionary; use the bundled dictionary if lookup fails. |
cat_cult_p | Crop category and broad usoCode | Keep alongside the exact culture code; it is less specific than the code. |
surf_parc, fallback sf_adm_de | superficieNum in ha | The code defaults to 1 ha if parsing fails. A copy should flag this imputation. |
id_parcel, fallback iup/gid | Stable parcel ID | Deduplicate across pages; a coordinate-plus-code key is the final fallback. |
| GeoJSON polygon | Centre lat/lng | Accept only a centre inside the apiary circle. |
The adapter caches requests by rounded location and radius. A full page triggers the next startIndex; a short page stops the loop. Errors can leave a partial result, so retain the fetched-page count and communicate incompleteness. RPG.LATEST and the WMS layer labelled 2024 need independent version checks: the visual layer's year does not prove the feature layer has the same vintage.
Remote feature.properties:
{ "id_parcel": "example-123", "code_cultu": "CZH",
"cat_cult_p": "COLZA", "surf_parc": 1.8 }
Normalized parcel:
{ "id": "FR_example-123", "countryCode": "FR",
"cropKey": "CZH", "superficieNum": 1.8,
"source": "RPG Geoplateforme WFS" }Map interaction: the WMS paints the visible RPG layer; a clicked location uses a small WFS BBOX to retrieve nearby feature attributes. For a new build, start with the provider's Géoplateforme WFS instructions and GetCapabilities, then confirm that the requested type and JSON format still exist.
Italy · national Catasto, regional land use
Two different roles: national display and Emilia-Romagna calculation.
The national Catasto WMS exposes CP.CadastralParcel for parcel outlines. The adapter explicitly substitutes EPSG:4258 in the generated tile URL. Cadastral outlines contain no dependable crop identity for this model.
For the estimate, query Emilia-Romagna WFS layer _020_uso_suolo_ed2023 through /proxy. The code uses WFS 2.0, outputFormat=geojson, 500-feature pages and a latitude–longitude bounding box. The query is attempted only when the chosen circle overlaps the configured Emilia-Romagna bounds.
GET http://servizigis.regione.emilia-romagna.it/wfs/uso_del_suolo
?service=WFS&version=2.0.0&request=GetFeature
&typeNames=_020_uso_suolo_ed2023
&outputFormat=geojson&srsName=EPSG:4326
&count=500&startIndex=0
&bbox={south},{west},{north},{east},EPSG:4326Map DESCR to the land-use description, SIGLA to the class code, HECTARES to area and OBJECTID to identity. The text classifier makes the Italian cropKey; non-productive land is scored very low. The land-use overlay is itself drawn from WFS GeoJSON for the visible map area.
Coverage rule: outside the Emilia-Romagna query window the app raises an explicit coverage error. Piemonte's agricultural WMS is mentioned in the UI but is not an integrated analytical source. The regional WFS URL uses http in the source code; use a secure server-side relay for an HTTPS deployment.
Connection roles and field mapping
| Input | What it supplies | What it cannot tell us |
|---|---|---|
National Catasto WMS CP.CadastralParcel | Rendered cadastral parcel outlines in EPSG:4258 | Declared crop or flowering potential; the WMS image is not a crop feature census. |
Emilia-Romagna WFS _020_uso_suolo_ed2023 | Regional land-use polygons and class attributes | Nationwide coverage or a farmer's current crop declaration. |
| WFS property | Normalized use | Rule |
|---|---|---|
SIGLA | Class key | Retain original short code for traceability. |
DESCR | displayName, cropKey | Text classifier maps recognized land-use words to the Italian floral catalogue. |
HECTARES or SHAPE.AREA | superficieNum | Use hectares directly, or divide square metres by 10,000; an invalid value defaults to 1 ha in the current adapter. |
OBJECTID or FID | Parcel ID | Deduplicate features across 500-record pages, up to 40 pages. |
| GeoJSON geometry | Polygon centre | Retain a record only when its centre falls inside the circle. |
Remote feature.properties:
{ "OBJECTID": 123, "SIGLA": "SEMIN", "DESCR": "Seminativi",
"HECTARES": 2.7 }
Local interpretation:
{ "id": "IT_123", "displayName": "Seminativi",
"superficieNum": 2.7, "source": "Regione Emilia-Romagna WFS",
"evidence": "regional land-use class" }Version to revisit. The code hard-codes a 2023-edition feature type. The regional catalogue also publishes a newer type, portale_uso_del_suolo:_023_uso_suolo_ed2025, on the same WFS family. That is a documented migration candidate, not an integrated or schema-validated replacement. Discover its exact type in GetCapabilities, compare fields and geometry, then change the adapter deliberately.
Belgium · Flanders and Wallonia
Two regional LPIS services, two schemas, two bounding-box conventions.
| Region | Feature endpoint and type | BBOX | Crop / area / ID |
|---|---|---|---|
| Flanders | geo.api.vlaanderen.be/Landbgebrperc/wfsLandbgebrperc:Lbgebrperc | west,south,east,northapplication/json | LBLHFDTLT / GRAF_OPP ÷ 10000 / UIDN |
| Wallonia | SIGeC ArcGIS WFSSIGEC_PARC_AGRI_ANON:Parcelles_agricoles___2023_ | south,west,north,eastGEOJSON | CULT_NOM / SURF_HA / OBJECTID |
Both requests use WFS 2.0, EPSG:4326, count=500 and startIndex; each regional loop allows up to 30 pages. Flanders also supplies GEWASGROEP and HFDTLT; Wallonia supplies GROUPE_CULT and CULT_COD. The adapter translates Dutch and French crop names into one Belgian crop catalogue and de-duplicates by region plus ID.
Flanders:
GET https://geo.api.vlaanderen.be/Landbgebrperc/wfs?service=WFS&version=2.0.0&request=GetFeature&typeNames=Landbgebrperc:Lbgebrperc&outputFormat=application/json&srsName=EPSG:4326&count=500&startIndex=0&bbox={west},{south},{east},{north},EPSG:4326
Wallonia:
GET https://geoservices.wallonie.be/arcgis/services/WFS/SIGEC_PARC_AGRI_ANON/MapServer/WFSServer?service=WFS&version=2.0.0&request=GetFeature&typeNames=SIGEC_PARC_AGRI_ANON:Parcelles_agricoles___2023_&outputFormat=GEOJSON&srsName=EPSG:4326&count=500&startIndex=0&bbox={south},{west},{north},{east},EPSG:4326For visual display, Flanders has ALV WMS layer LbGebrPerc2023. The Wallonia overlay is painted from returned WFS GeoJSON because the chosen MapServer does not expose a WMS in this implementation.
Normalize the two regional schemas separately
| Meaning | Flanders fields and rule | Wallonia fields and rule |
|---|---|---|
| Crop description | LBLHFDTLT is preferred; GEWASGROEP gives the group and HFDTLT the crop code. | CULT_NOM is preferred; GROUPE_CULT and CULT_COD support classification. |
| Area in hectares | GRAF_OPP / 10000 (square metres to hectares), fallback OPPERVL, then geometric area. | SURF_HA, fallback geometric area. |
| Identity | UIDN, fallback OIDN/ALVID. | OBJECTID, fallback GmlID. |
| Geometry filter | Compute polygon centre, discard outside-circle centres, deduplicate with a region-prefixed key. | |
The adapter translates Dutch and French names to its own Belgian cropKey and usoCode; those keys point to web/data/melliferous_be.js. It queries both services rather than preselecting one region, so a circle near the regional boundary can receive both. The result contains an adapter-level census annotation; it is not proof that the providers returned a complete census when a page failed.
Flanders remote: { "UIDN": "example-fl", "LBLHFDTLT": "Koolzaad",
"GRAF_OPP": 18000 }
Flanders local: { "countryCode": "BE", "superficieNum": 1.8,
"displayName": "Koolzaad", "region": "Vlaanderen" }
Wallonia remote: { "OBJECTID": "example-wa", "CULT_NOM": "Colza",
"SURF_HA": 1.8 }
Wallonia local: { "countryCode": "BE", "superficieNum": 1.8,
"displayName": "Colza", "region": "Wallonie" }Wallonia migration required. The integrated WFS type is a 2023 legacy parcel layer. Wallonia's official service notice says the older anonymous agricultural-parcel services are being withdrawn by the end of 2026 as a newer SIGeC model replaces them. The new dataset catalogue covers 2024 onward. The application has not been migrated: obtain the new capabilities, feature type and field schema, then update the Wallonia mapping and check attribution and reuse terms before deployment.
Optional provider route: Digitaal Vlaanderen also publishes an OGC API Features collections endpoint. It is a possible modern alternative for a new client, not the route this repository currently calls.
Germany · regional InVeKoS
One adapter dispatches to different Land services; there is no national WFS in the implementation.
The code defines a REGIONS table with geographical bounds and a preferred parcel source (falling back to a reference block). It selects regions intersecting the apiary's bounding box, reads at most 12 pages of 1,000 features per region, and normalizes WFS GeoJSON, WFS GML or ArcGIS REST output to WGS84 GeoJSON. Each row below is an actual configured source.
| Land / area | Preferred request | Type / method | What the adapter reads |
|---|---|---|---|
| North Rhine-Westphalia | NRW WFS | umwelt_lwk_eufoerderung:Beantragte_und_als_foerderfaehig_festgestellte_Teilschlaege_in_NRW · GeoJSON | CODE_TXT, AREA_HA, ID |
| Lower Saxony | SLA WFS | agrar_ref:feldbloecke · JSON blocks | bnk_txt, flaeche, flik |
| Baden-Württemberg | FIONA WFS | lw:v_fiona_flaecheninformation · JSON | Bezeichnung, FlaecheInHa, object_id |
| Hesse | Hesse WFS | lawi:Landwirtschaftliche Parzellen 2024 · JSON | mainCrop, declaredArea, id |
| Mecklenburg-Vorpommern | MV WFS | mv:feldbloecke · JSON blocks | bodennutzu, groesse_p, fbid |
| Saxony | Saxony WFS | invekos:AgriculturalParcel · GeoJSON, coordinates swapped | mainCrop, declaredArea, OBJECTID |
| Saxony-Anhalt | ArcGIS MapServer /0 | /query?f=geojson · ArcGIS REST | CLASS_CODE, geometric area, ID_LOCALID |
| Bremen / Hamburg | SLA INSPIRE WFS | agrar_ref_inspire:LPIS_AgriculturalArea · JSON | name, geometric area, id |
| Bavaria | Bavaria WFS | lpis:AgriculturalArea · GML/XML | agriculturalAreaType, geometric area, identifier |
| Brandenburg / Berlin | BB WFS | refbb:Feldblock · GML/XML blocks | HBN_KAT, FL_BRUTTO_HA, FB_ID |
| Saarland | Saarland WFS | elu:ExistingLandUseObject · GML/XML | name, area/FLIK parsed from description |
// JSON WFS (type, format and BBOX order come from the selected Land row)
GET {base}?service=WFS&version=2.0.0&request=GetFeature&typeNames={type}&outputFormat={format}&srsName=EPSG:4326&count=1000&startIndex=0&bbox={providerSpecificBbox}
// GML-only WFS (Bavaria, Brandenburg/Berlin, Saarland)
GET {base}?service=WFS&version=2.0.0&request=GetFeature&typeNames={type}&count=1000&startIndex=0&srsName=urn:ogc:def:crs:EPSG::4326&bbox={south},{west},{north},{east},urn:ogc:def:crs:EPSG::4326
// Saxony-Anhalt ArcGIS REST
GET {base}/query?where=1%3D1&outFields=*&f=geojson&outSR=4326&geometryType=esriGeometryEnvelope&inSR=4326&spatialRel=esriSpatialRelIntersects&geometry={west},{south},{east},{north}&resultRecordCount=1000&resultOffset=0The adapter uses provider-specific field extractors, swaps Saxony's returned coordinates, parses GML for three providers and computes area from geometry when no usable area field exists. It turns German/INSPIRE crop labels into the German cropKey and monthly score. Its map overlays are drawn from normalized GeoJSON, rather than one country-wide WMS.
The decisions inside the dispatcher
| Provider group | BBOX order in the current code | Response handling |
|---|---|---|
| NRW, Mecklenburg-Vorpommern, Saxony | south,west,north,east | WFS GeoJSON; Saxony swaps each returned coordinate pair before geometry calculations. |
| Lower Saxony, Baden-Württemberg, Hesse, Bremen, Hamburg | west,south,east,north | WFS JSON; configured property readers select crop, area and ID. |
| Bavaria, Brandenburg/Berlin, Saarland | south,west,north,east with the full EPSG URN | WFS GML/XML; the parser reads posList and converts latitude/longitude to GeoJSON longitude/latitude. |
| Saxony-Anhalt | ArcGIS envelope west,south,east,north | ArcGIS REST GeoJSON; use resultOffset rather than WFS startIndex. |
Remote properties:
{ "ID": "example-7", "CODE_TXT": "Raps",
"USE_TXT": "Ackerland", "AREA_HA": 1.6 }
Adapter output:
{ "id": "DE_NRW_P_example-7", "countryCode": "DE",
"region": "Nordrhein-Westfalen", "cropKey": "raps",
"usoCode": "TA", "superficieNum": 1.6,
"source": "InVeKoS Nordrhein-Westfalen" }The source choice is one per Land: prefer a configured parcel source, otherwise use the block source. The adapter does not merge a parcel layer with its block fallback, which avoids counting both representations for the same area. A page error stops only that source's loop; a full final page at the 12-page cap can leave undiscovered records. Expose source, fetched count and truncation/error state in a fresh implementation.
GML limit: the in-repository parser is deliberately small. It reads posList rings and simple properties, but may not preserve every complex GML geometry relationship. For a production reimplementation, use a full GML parser and validate a known polygon, area and axis order for each service.
Coverage is 13 of 16 Länder in the application's configured regions: the 11 source rows represent Bremen and Hamburg separately, and the Brandenburg source also covers Berlin. Rhineland-Palatinate, Schleswig-Holstein and Thuringia are not connected for detailed analysis. Some connected areas expose only reference blocks or broad land-use classes, so crop specificity varies by Land. The opening comment in web/countries/de/index.js still says “9 Länder”; the current REGIONS table and UI list 13.
Worked example: recreate a French query
This example is intentionally synthetic. It shows how another team can reproduce the connection and data transformation without any SiBeela credential, backend address or private observation.
Choose a centre. Latitude 48.8566, longitude 2.3522, radius 2.5 km. Calculate the BBOX: west 2.317968, south 48.834077, east 2.386432, north 48.879123.
Resolve culture names. Request the RPG.LATEST:codes_cultures type once and map its culture codes to descriptions; keep the local dictionary as a fallback.
Page parcels. Request RPG.LATEST:parcelles_graphiques with that BBOX, COUNT=500 and startIndex=0. If 500 features arrive, request startIndex=500. Stop after a shorter page, an error or the adapter's 40-page cap.
Validate and normalize. For each polygon, calculate its centre; retain centres within 2.5 km, deduplicate id_parcel, parse surf_parc in hectares and keep code_cultu as cropKey. Record dictionary misses and imputed areas.
Estimate and disclose limitations. Match cropKey to the French floral catalogue, calculate 52 weeks of parcel potential, aggregate and report assumptions plus any missing pages. The source year and crop declaration may differ from the current flowering season.
const base = 'https://data.geopf.fr/wfs';
const q = new URLSearchParams({
SERVICE: 'WFS', VERSION: '2.0.0', REQUEST: 'GetFeature',
TYPENAMES: 'RPG.LATEST:parcelles_graphiques',
outputFormat: 'application/json', SRSNAME: 'EPSG:4326',
COUNT: '500', startIndex: '0',
BBOX: '2.317968,48.834077,2.386432,48.879123,EPSG:4326'
});
const upstream = `${base}?${q}`;
const response = await fetch(
'https://YOUR_BACKEND/proxy?url=' + encodeURIComponent(upstream)
);
if (!response.ok) throw new Error(`Source HTTP ${response.status}`);
const { features = [] } = await response.json();
console.log('Features in first page:', features.length);The placeholder relay must be your own service. For direct server-to-server use, call the public provider URL without a browser proxy. The example's coordinates and records are teaching values; no production request result is embedded here.
Implementation checklist for another team
- Choose a country and confirm the selected apiary is inside that adapter's actual analytical coverage.
- Use WMS only for map images; use the listed feature endpoint for parcel and crop attributes.
- Keep provider-specific
typeNames, output format, bounding-box axis order, coordinate correction and field mapping. These details are especially important for Belgium, Italy and Germany. - Page through features and deduplicate on the provider's ID. Then test each polygon centre against the circle; a BBOX alone is rectangular.
- Keep source name, original crop label, area, country, region, canonical
cropKeyand data-quality flags with each normalized parcel. - Use local floral mappings and phenology to turn land use into a potential estimate. Do not treat a land-use score as kilograms of honey by itself.
- Prepare caching, timeouts, retry/backoff and a truthful “source unavailable” state. The country's public service can be slow, partial or temporarily offline.
- If you use Earth Engine, configure your own service account. Keep secrets on the server and proxy HTTP-only sources through an HTTPS backend.
- Protect any billable or quota-limited backend route with authentication, rate limits and request caps. Never give another team access to your existing Earth Engine project or deployed server.
- Review the provider's attribution, reuse and rate-limit terms. Replace Wallonia's legacy layer after inspecting the new SIGeC schema; treat Emilia-Romagna's newer layer as a candidate until field mapping is verified.
What the result means. SiBeela estimates a landscape's beekeeping potential from external land-use and environmental data plus its own botanical model. It does not receive a measured honey harvest from any of these APIs, and the forecast is not a guarantee of kilograms per hive.
Source-code map
These local files are the implementation behind the requests and limits above. The HTML example sibeela_explicacion_v2.html supplied the visual language of this guide.
Signed, Eduardo Marcos Alejos
Senior Programmer and Data Scientist · BeeLife
BeeLife European Beekeeping Coordination