GHG Protocol Scope 3 Spatial Mapping

GHG Protocol Scope 3 spatial mapping is the geospatial subsystem that turns fragmented procurement records, freight manifests, and supplier footprints into auditable, location-explicit emission allocations within the MRV Architecture & Carbon Accounting Fundamentals stack. Unlike Scope 1 and 2, which anchor to owned facilities or a defined grid boundary, Scope 3 is the most spatially diffuse category in corporate carbon accounting: it traces upstream and downstream activity across multi-tier supply chains, logistics corridors, and distributed product lifecycles, where every emission figure must be defensible against a third-party verifier.

Because that allocation depends entirely on geometry, this component sits directly downstream of geospatial CRS alignment and feeds its versioned outputs into MRV data lineage and provenance tracking. Get the spatial join wrong and the error does not stay local — it propagates into aggregate tonnage, double-counts across jurisdictions, and surfaces as a finding during ISO 14064-3 verification. This page covers where Scope 3 spatial mapping fits in the workflow, the failure modes that silently corrupt inventories, a deterministic Prefect implementation, and the mapping from code outputs to specific regulatory requirements.

Deterministic Scope 3 spatial allocation flow, with a confidence gate to manual reconciliation Procurement CSV, supplier polygons, and a land-cover raster converge into a sequential pipeline. Stage 1 geocodes records and normalizes them to the equal-area CRS EPSG:6933. Low-confidence geocodes (below 0.7) are routed upward to manual reconciliation rather than silently joined. Stage 2 is a double-count gate that dissolves overlapping footprints exceeding five percent shared area. Stage 3 computes cloud-masked zonal statistics, keeping pixels with cloud probability under 0.2. Stage 4 applies emission-factor weighting as area in hectares times the mean factor. Stage 5 writes a versioned Parquet artifact carrying immutable lineage for audit. SOURCES Procurement CSV addresses · postcodes Supplier polygons service-area footprints Land-cover raster NDVI · biomass proxy STAGE 1 Geocode & CRS-normalize → EPSG:6933 STAGE 2 · GATE Double-count gate >5% overlap → dissolve STAGE 3 Cloud-masked zonal stats cloud prob < 0.2 STAGE 4 Emission-factor weighting area_ha × mean_ef STAGE 5 Versioned Parquet + lineage audit-ready Manual reconciliation held, not aggregated confidence < 0.7 Identical inputs and factor versions must yield byte-identical tonnage — every stage is logged as immutable lineage.

Role in the MRV Workflow

Scope 3 spatial mapping executes during the spatial allocation and activity-data georeferencing stage, positioned between raw activity-data ingestion and emission-factor application. At this juncture, tabular procurement datasets are joined with administrative boundaries, satellite-derived land-cover rasters, and transport-network topologies. The stage must reconcile heterogeneous coordinate systems, resolve spatial drift across temporal snapshots, and apply cloud masking to optical inputs before emission factors are spatially weighted. Without deterministic spatial routing, Scope 3 inventories risk double-counting, misallocation across jurisdictional boundaries, or unverifiable aggregation.

Upstream dependencies. Activity data typically arrives as unstructured CSVs containing facility names, postal codes, or free-text addresses. These records must already pass through a canonical projection contract before they reach this stage — the equal-area target CRS established during CRS alignment is a hard precondition, because area-based emission weighting is mathematically invalid on unprojected degree geometries. Optical rasters used for land-use change attribution and biomass proxies must also have been atmospherically corrected and cloud-masked upstream, via Sentinel-2 and Landsat cloud-masking workflows, so that vegetation indices (NDVI, EVI) feeding this allocation are not biased by uncorrected surface reflectance.

Downstream consumers. Allocated emissions flow into two places. First, offset and removal claims are reconciled against the spatially bounded Scope 3 inventory through carbon credit registry data integration, ensuring credits are not retired against emissions outside the corporate value-chain boundary. Second, every transformation — raw ingestion, CRS normalization, raster intersection, factor application — is captured as immutable lineage so that CSRD ESRS E1 and SEC climate disclosures remain backward-traceable. Granular per-parcel parameters and factor-weighting matrices are documented separately in the step-by-step GHG Protocol Scope 3 geospatial calculation reference.

To keep the join deterministic, production pipelines validate geocoded points against administrative boundary layers (NUTS, GADM, or EPA eGRID regions), apply spatial tolerance buffers scaled to data-provenance quality, and flag records that fall outside expected logistics corridors for manual reconciliation rather than silently aggregating them.

Core Failure Modes

Scope 3 spatial pipelines fail in predictable, quantifiable ways. Three failure modes dominate production inventories.

  1. Geocoding positional drift and boundary misassignment. Free-text addresses and postal-code centroids carry positional uncertainty of tens to hundreds of meters. When a geocoded point lands on the wrong side of an administrative boundary, the entire activity record is attributed to the wrong jurisdiction’s emission factor and the wrong land-cover zone. In supplier datasets dominated by coarse postal-code geocoding, 10–30% of records can be misassigned across boundary lines, producing both factor-selection errors and zonal-statistics contamination. Root cause: positional uncertainty propagating into a hard spatial join with no confidence gate.

  2. Conformal projection area inflation. Land-use change attribution and biomass-proxy calculations multiply per-hectare emission factors by polygon area. If area is measured in a conformal projection such as Web Mercator (EPSG:3857), areal distortion grows with latitude — from a few percent in the tropics to 40%+ at high latitudes — directly inflating or deflating tonnage. Root cause: areal aggregation performed in an angle-preserving rather than an equal-area projection (EPSG:6933 for global coverage, or a regional Albers Equal-Area such as EPSG:9822 for continental North America). Observed impact: single-digit to double-digit percent error in allocated emissions, well beyond the ±0.5% audit tolerance auditors expect.

  3. Double-counting across overlapping supplier footprints. Multi-tier supply chains generate overlapping service-area buffers and shared facility polygons. When two supplier geometries cover the same hectares of land cover, the underlying emissions are counted twice. Root cause: union/overlap geometry not resolved before zonal statistics. Even 5% overlapping polygon area translates to roughly 5–15% inventory inflation once shared high-factor land cover is double-attributed — a direct violation of the GHG Protocol’s avoidance-of-double-counting requirement.

A fourth, subtler mode — projection drift in long-running pipelines — manifests as sub-pixel misregistration during repeated raster-vector intersections. It is handled the same way as in the upstream CRS alignment stage: enforce a canonical projection per operational region, reproject on ingestion with explicit transformation chains, and log affine residuals so datasets exceeding tolerance are flagged rather than aggregated.

Spatial resolution against attribution confidence across Scope 3 categories A chart plotting the spatial resolution at which each Scope 3 category can be located, from facility-level at the top through supplier-site, sourcing-region, and country-average at the bottom, against the confidence with which emissions can be attributed to a location. Purchased goods from direct suppliers sit at facility level with high confidence. Land-use change in agricultural supply chains sits at sourcing-region level with moderate confidence. Upstream transport sits at route level with moderate confidence. Purchased goods from tier-three suppliers and use of sold products sit at country-average level with low confidence. A panel notes that spatial MRV adds value only where the category can actually be located, and that presenting a country-average category on a map implies a precision the data does not have. Not every Scope 3 category can be put on a map Locatability varies by an order of magnitude across categories. The pipeline must record which tier each figure came from. facility supplier site sourcing region country average low high attribution confidence → cat. 1 · direct suppliers cat. 4 · upstream transport land-use change, agri supply cat. 1 · tier-3 · cat. 11 use phase Record the tier per figure Spatial MRV earns its cost in the upper band only. Mapping a country-average figure implies precision it does not have.

Deterministic Implementation Architecture

The following Prefect pipeline implements deterministic Scope 3 spatial allocation with explicit CRS handling, structured structlog telemetry, cloud-masked zonal weighting, and validation gates that reject — rather than silently process — degenerate inputs. It enforces an equal-area target CRS, repairs invalid topology, and emits a verification-ready Parquet output.

import structlog
import geopandas as gpd
import rasterio
from rasterio.mask import mask
from prefect import flow, task

# Structured logger configuration for audit trails
logger = structlog.get_logger()

# Equal-area canonical CRS — areal weighting is invalid on degree geometries.
TARGET_CRS = "EPSG:6933"
GEOCODE_CONFIDENCE_MIN = 0.7   # below this, route to manual reconciliation
OVERLAP_AREA_TOLERANCE = 0.05  # >5% overlapping area triggers double-count repair


@task
def ingest_and_normalize_crs(
    supplier_gdf_path: str,
    target_crs: str = TARGET_CRS,
) -> gpd.GeoDataFrame:
    """Load supplier polygons, validate geometry, and enforce canonical CRS."""
    gdf = gpd.read_file(supplier_gdf_path)
    if gdf.crs is None:
        raise ValueError("Input GeoDataFrame lacks a CRS definition. Rejecting ingestion.")

    logger.info(
        "crs_normalization",
        source_crs=gdf.crs.to_epsg(),
        target_crs=target_crs,
        records=len(gdf),
    )

    normalized = gdf.to_crs(target_crs)
    # Single-pass topology repair post-projection (self-intersection / slivers).
    if not normalized.is_valid.all():
        logger.warning("topology_repair", invalid=int((~normalized.is_valid).sum()))
        normalized["geometry"] = normalized.buffer(0)
    return normalized


@task
def resolve_double_counting(
    supplier_gdf: gpd.GeoDataFrame,
    tolerance: float = OVERLAP_AREA_TOLERANCE,
) -> gpd.GeoDataFrame:
    """Detect overlapping footprints and apportion shared area to avoid double-counting."""
    union = gpd.overlay(supplier_gdf, supplier_gdf, how="union", keep_geom_type=True)
    overlap_area = union.geometry.area.sum()
    base_area = supplier_gdf.geometry.area.sum()
    overlap_ratio = max(0.0, (overlap_area - base_area) / base_area)

    if overlap_ratio > tolerance:
        logger.warning("double_count_detected", overlap_ratio=round(overlap_ratio, 4))
        # Dissolve to a single non-overlapping coverage, apportioning by shared area.
        return supplier_gdf.dissolve(by="id", aggfunc="first").reset_index()
    return supplier_gdf


@task
def compute_spatial_emission_allocation(
    supplier_gdf: gpd.GeoDataFrame,
    raster_path: str,
    ef_column: str = "emission_factor_kgco2e_per_ha",
) -> gpd.GeoDataFrame:
    """Zonal statistics with explicit raster alignment and cloud-masked weighting."""
    results = []
    with rasterio.open(raster_path) as src:
        if src.crs != supplier_gdf.crs:
            # Reproject vector to the raster grid for a valid mask; never the reverse
            # mid-pipeline, to avoid resampling the source emissions raster.
            logger.warning("raster_crs_mismatch", raster_crs=str(src.crs),
                           vector_crs=str(supplier_gdf.crs))
            supplier_gdf = supplier_gdf.to_crs(src.crs)

        for _, row in supplier_gdf.iterrows():
            sid = row.get("id")
            try:
                out_image, _ = mask(src, [row.geometry], crop=True)
                # Band 0 = emission proxy; band 1 = cloud probability (if present).
                if out_image.shape[0] > 1:
                    valid = out_image[0][out_image[1] < 0.2]
                else:
                    valid = out_image[0].ravel()

                if valid.size == 0:
                    logger.debug("no_valid_pixels", supplier_id=sid)
                    continue

                area_ha = row.geometry.area / 10_000  # EPSG:6933 metres -> hectares
                mean_ef = float(valid.mean())
                total = area_ha * mean_ef * float(row.get(ef_column, 1.0))

                results.append({
                    "supplier_id": sid,
                    "area_ha": area_ha,
                    "mean_ef": mean_ef,
                    "scope3_emissions_kgco2e": total,
                    "verification_status": "spatially_allocated",
                })
            except Exception as exc:  # log, isolate, continue — never fail the batch
                logger.error("zonal_stats_failure", supplier_id=sid, error=str(exc))

    return gpd.GeoDataFrame(results)


@flow(log_prints=True)
def scope3_spatial_mapping_pipeline(
    supplier_vector: str,
    land_cover_raster: str,
    output_path: str,
):
    """End-to-end Scope 3 spatial allocation with compliance mapping."""
    logger.info("pipeline_start", flow="scope3_spatial_mapping")

    suppliers = ingest_and_normalize_crs(supplier_vector)
    suppliers = resolve_double_counting(suppliers)
    allocated = compute_spatial_emission_allocation(suppliers, land_cover_raster)

    # Attach regulatory mapping as immutable lineage attributes.
    allocated["iso_14064_compliance"] = "boundary_defined"
    allocated["csrd_esrs_e1_mapping"] = "upstream_category_1_2_4"

    allocated.to_parquet(output_path)
    logger.info("pipeline_complete", records_processed=len(allocated), output=output_path)
    return allocated


if __name__ == "__main__":
    scope3_spatial_mapping_pipeline(
        supplier_vector="data/suppliers.geojson",
        land_cover_raster="data/esa_worldcover_2023.tif",
        output_path="output/scope3_spatial_allocation.parquet",
    )

When scaling to continental or multi-tier supplier networks, the per-row mask loop is replaced with chunked array processing via xarray and dask. Memory-mapped, lazily evaluated workflows prevent out-of-memory failures during raster-vector intersection and enable efficient temporal aggregation across Sentinel-2 or Landsat 9 archives — the same lazy-evaluation pattern used for temporal aggregation of land-use change feeds directly into year-over-year Scope 3 attribution.

Validation, Debugging & Compliance Mapping

Technical outputs must map directly to verification requirements. Each failure mode above has a diagnostic signal, a deterministic remediation, and a specific clause it satisfies once gated.

Failure Mode Diagnostic Signal Remediation Verification Mapping
Geocoding misassignment Geocode confidence < 0.7; points outside expected corridor Validate against GADM/eGRID boundaries; route low-confidence records to manual review ISO 14064-3 §5.4.2 (Spatial Data Quality Controls)
Conformal area inflation Area variance > 2% vs equal-area baseline Enforce to_crs("EPSG:6933") before any area multiplication CSRD ESRS E1-AR4 (Data Quality & Uncertainty)
Double counting Overlapping supplier polygon area > 5% gpd.overlay(how="union") + dissolve, apportion by shared area GHG Protocol Scope 3 §4.3 (Avoidance of Double Counting)
Projection drift Affine residuals > 0.5 m across iterative runs Canonical per-region CRS; log src.crs vs dst.crs residuals ISO 14064-3 §5.3.1 (Boundary Definition)
Null zonal intersection valid.size == 0 across > 15% of suppliers Verify raster extent vs vector bounds before masking SEC Climate Disclosure Rule §229.1502 (Methodology Disclosure)

The pipeline’s compliance posture rests on three enforced gates. Equal-area weighting keeps areal multiplication within the ±0.5% tolerance auditors apply to tonnage, satisfying the geometric-integrity expectations shared with Verra VM-series methodologies (for example, the project-boundary delineation rules in VM0047 for afforestation/reforestation/revegetation). Double-count resolution before zonal statistics directly answers GHG Protocol Scope 3 §4.3. CRS and factor lineage — written as immutable attributes and propagated to MRV data lineage and provenance tracking — gives verifiers the reproducibility evidence required under CSRD ESRS E1 and SEC climate-disclosure methodology rules.

For multi-temporal Scope 3 tracking, version each run with DVC or Delta Lake and emit a provenance manifest containing input hashes, CRS transformation matrices, cloud-mask thresholds, and emission-factor sources. Emission factors themselves carry uncertainty that should be propagated, not discarded; modeling that spread is the job of emission factor uncertainty mapping, whose confidence bounds attach to each allocated figure before reporting. The GHG Protocol Corporate Value Chain (Scope 3) Standard requires documented methodologies for spatially explicit activity data, and the OGC Well-Known Text CRS Representation standard provides the canonical encoding for the coordinate-system declarations auditors request.

Three apportionment rules applied to one shared parcel, and the different tonnages they produce A single 400 hectare parcel supplies three buyers. Under area apportionment, each buyer receives a share proportional to the hectares nominally allocated to it: 180, 140 and 80 hectares giving 4500, 3500 and 2000 tonnes. Under volume apportionment, shares follow purchased output: 55, 30 and 15 percent giving 5500, 3000 and 1500 tonnes. Under economic apportionment, shares follow purchase value, giving 6200, 2700 and 1100 tonnes. A panel states that all three sum to the same 10000 tonne parcel total, that the methodology chooses the rule, and that the rule must be recorded on every row because the same physical parcel produces three defensible and different answers. One parcel, three defensible answers 400 ha parcel, 10 000 tCO₂e of land-use-change emissions, three buyers. By area By volume By value 4 500 3 500 2 000 5 500 3 000 1 500 6 200 2 700 1 100 buyer A · B · C All three sum to 10 000. The methodology picks the rule — so the rule must travel on every row, or the figure is unreconcilable.

Frequently Asked Questions

Which Scope 3 categories are worth mapping spatially at all?

The ones whose emissions are genuinely located: purchased goods from suppliers you can identify to a site, upstream transport where routes are known, and above all land-use change in agricultural and forestry supply chains, where the emission is inseparable from a place. Categories computed from spend-based or country-average factors gain nothing from a map and lose something — placing them on one implies a spatial precision the underlying data does not carry. Record the data tier per figure so a reader can tell which is which.

How is double counting between suppliers actually prevented?

By making the apportionment explicit and reconcilable. Every parcel-to-buyer allocation must carry the rule applied, the share, and a parcel identifier, so the shares for a parcel can be summed and asserted to equal one. Double counting shows up as a sum above one, and undercounting as a sum below it; neither is visible if the allocation is implicit in a join. The full mechanics are in preventing Scope 3 double-counting in spatial joins.

What happens when supplier locations are only known to a region?

Report at the region and say so. A region-level figure with an honest label is more useful than a point placed at a region’s centroid, which invites downstream consumers to intersect it with something. Where a mixed portfolio has some sites located and others not, keep the two tiers as separate rows with a resolution field rather than blending them into one map layer — blending is how a partially located inventory becomes a fully misleading one.

Should land-use-change emissions be amortised over time?

Most methodologies require it, typically over a fixed window from the conversion event, and the window is a methodology parameter rather than an engineering choice. What is an engineering choice is representing the conversion event as a dated fact and the amortisation as a derived quantity, so a change to the window re-derives cleanly rather than requiring a re-analysis. Storing only the amortised annual figure loses the event and makes any later methodology change a manual exercise.

How do supplier changes mid-period affect the spatial figures?

They split the period. A supplier relationship that starts or ends within a reporting period must be represented as an interval, with the emissions apportioned across the overlap rather than assigned to whichever side the join happened to land on. This is the same interval discipline that crediting periods require, and skipping it produces a portfolio whose supplier-level figures do not reconcile to the corporate total when suppliers churn.

How should a supplier who refuses to share locations be handled?

By reporting at the resolution you actually have and saying so, not by inferring locations from a trade database and presenting them as known. A supplier that provides only a country is a country-level figure with a country-level label; treating an inferred site as observed converts a disclosure limitation into a misstatement. Where coverage gaps are material, disclose the share of spend or volume that is unlocated — that number is often more informative to a reader than the mapped portion.

Does spatial Scope 3 mapping change the total, or only its attribution?

Both, and the total change surprises people. Moving from spend-based factors to spatially explicit land-use-change accounting frequently changes a category’s total by a large multiple in either direction, because the two methods measure different things — one an economic average, the other an observed conversion. Expect the transition to produce a restatement, plan the disclosure around it, and keep both computations available for the periods where they overlap so the change is explainable rather than merely large.

How is spatial Scope 3 work best sequenced for a team starting out?

Locate the largest categories first and accept coarse resolution elsewhere. A programme that spends a year building a perfect map of a category worth three per cent of the footprint has spent a year well only if it learned the method. Start with the category that dominates, get its supplier locations to site level, and treat the rest at the resolution the data supports — then improve outward as supplier engagement allows.

Conclusion

GHG Protocol Scope 3 spatial mapping converts diffuse procurement and logistics data into auditable, location-explicit emission inventories. By enforcing an equal-area canonical CRS, resolving overlapping footprints before zonal statistics, applying cloud-masked weighting, and embedding lineage at every transformation, engineering teams eliminate double-counting, resolve jurisdictional misallocation, and produce verification-ready outputs that hold up under ISO 14064-3, CSRD ESRS E1, and SEC disclosure. The architecture scales across multi-tier supply chains while preserving the determinism auditors demand: identical inputs and factor versions must yield byte-identical tonnage. For per-parcel parameters, tolerance thresholds, and factor-weighting matrices needed in production, continue to the step-by-step GHG Protocol Scope 3 geospatial calculation reference.