INSPIRE Metadata Mandate

Part of: Regulatory Compliance & Standards Mapping

The EU INSPIRE Directive (2007/2 EC) requires public authorities in member states to document their spatial data sets and services with harmonized metadata so that data across national borders can be discovered, evaluated, and used. For a data steward the obligation is concrete: every data set covering one of the INSPIRE spatial data themes — from administrative units to hydrography to protected sites — must carry metadata that conforms to the INSPIRE Implementing Rules for metadata, and a central element of that metadata is a lineage statement describing the history and processing that produced the data. This guide, part of the Regulatory Compliance & Standards Mapping section, explains which INSPIRE metadata elements are mandatory, what the lineage obligation actually demands, and how to generate conformant lineage statements from a Python pipeline.

INSPIRE does not invent a metadata format from scratch. Its Implementing Rules are built on the ISO 19115 content model and encoded with ISO 19139 XML, so an INSPIRE-conformant record is an ISO metadata record with additional constraints and multiplicity rules layered on top. That layering has a practical consequence: if your provenance capture already targets ISO lineage, you are most of the way to INSPIRE conformance, and the same processing events can populate both. The remainder of this page maps the INSPIRE requirements onto lineage fields your pipeline can emit, and the companion how-to on generating conformant metadata with pygeometa shows the XML generation end to end.

INSPIRE metadata and lineage conformity flow Spatial Data theme + pipeline Lineage Statement source + process Metadata Elements id / extent / CRS ISO 19139 XML encoding Conformity impl. rules

Foundational concepts

INSPIRE metadata answers three questions about a data set: what it is (identification), whether you may use it (constraints and quality), and how it came to be (lineage). The identification block carries a resource title, a unique resource identifier, the spatial data theme keyword drawn from the GEMET INSPIRE themes vocabulary, a geographic bounding box, and the coordinate reference system. The quality-and-lineage block is where provenance lives: INSPIRE requires a lineage statement — free-text describing the source data and the processing steps — as a mandatory element for data sets.

The lineage statement is not merely a courtesy note. Under the Implementing Rules it is the element that lets a downstream user judge fitness for purpose: a hydrography layer reprojected from a national grid to EPSG:3035 (the INSPIRE-recommended ETRS89-LAEA) and generalized to a target scale must say so, because those transformations change what the data can legitimately support. A steward who already captures transformation events for security or catalogue purposes has the raw material for this statement; the task is to render it in the ISO structure INSPIRE expects. Where your organization also draws formal system boundaries, aligning the lineage scope with the ingress and egress points defined when establishing trust boundaries in GIS keeps the statement honest about what processing occurred inside your authority.

Conformity is its own element. An INSPIRE record must declare whether it conforms to the Commission Regulation on interoperability of spatial data sets and services, citing the specification and a pass/fail/not-evaluated degree. Asserting conformity you cannot evidence is a finding waiting to happen, which is why the lineage statement and the conformity declaration should be produced from the same pipeline metadata.

Standards & compliance alignment

Because INSPIRE reuses ISO 19115 for content and ISO 19139 for encoding, the mapping from your provenance model to the record is direct: a source data set becomes an ISO LI_Source, a processing step becomes an LI_ProcessStep, and the human-readable summary becomes the LI_Lineage.statement. Building your provenance capture against the ISO model therefore satisfies INSPIRE and the ISO mandate at once — the detail of that model lives in the ISO 19115 lineage implementation topic. For a wider view of how INSPIRE sits beside FISMA, GDPR, and the ISO family, the compliance framework mapping overview shows where the obligations overlap and where they diverge.

The architectural implication is that lineage should be captured as structured, per-step records — source identifier, processing description, processor, and date — rather than as an after-the-fact prose paragraph. Structured steps can be rendered into the ISO XML automatically and can also be summarized into the free-text statement; prose written by hand can be neither validated nor reused.

Step-by-step

1. Capture lineage as structured process steps

Model each transformation as a step with the fields ISO 19139 will need. Purpose: hold provenance in a form that renders to both the per-step XML and the summary statement.

from __future__ import annotations
from dataclasses import dataclass, field
from datetime import date

@dataclass(slots=True)
class ProcessStep:
    description: str          # -> LI_ProcessStep.description
    processor: str           # -> responsible party
    step_date: date          # -> LI_ProcessStep.dateTime
    source_id: str           # -> LI_Source.sourceCitation identifier
    source_crs: str          # e.g. "EPSG:4258" (ETRS89)
    result_crs: str          # e.g. "EPSG:3035" (ETRS89-LAEA)

@dataclass(slots=True)
class DatasetLineage:
    theme: str               # GEMET INSPIRE theme keyword, e.g. "Hydrography"
    resource_id: str         # unique resource identifier (a stable URN or code)
    steps: list[ProcessStep] = field(default_factory=list)

Recording both source_crs and result_crs per step means the statement can report projection changes explicitly, the transformation that most often surprises INSPIRE data users.

2. Render a conformant free-text lineage statement

INSPIRE requires the statement even when per-step metadata is present. Purpose: derive a deterministic, human-readable summary from the structured steps so the two never disagree.

def build_lineage_statement(lineage: DatasetLineage) -> str:
    if not lineage.steps:
        raise ValueError("INSPIRE lineage statement is mandatory: at least one step required")
    parts: list[str] = [
        f"Data set for INSPIRE theme '{lineage.theme}' (resource {lineage.resource_id})."
    ]
    for i, step in enumerate(lineage.steps, start=1):
        crs_note = (
            f" reprojected {step.source_crs} to {step.result_crs}"
            if step.source_crs != step.result_crs else ""
        )
        parts.append(
            f"Step {i} ({step.step_date.isoformat()}, {step.processor}): "
            f"{step.description}{crs_note}; source {step.source_id}."
        )
    return " ".join(parts)

Guarding against an empty step list enforces the mandatory-element rule at generation time rather than at validation time. Feeding these fields into an ISO 19139 document is the subject of the pygeometa how-to, which turns the DatasetLineage object into schema-valid XML.

3. Assert conformity from evidenced steps

Purpose: declare conformity to the Implementing Rules only when the record actually carries the mandatory elements.

def conformity_degree(lineage: DatasetLineage, has_extent: bool, has_crs: bool) -> str:
    mandatory_present = (
        bool(lineage.steps)          # lineage statement derivable
        and bool(lineage.theme)      # spatial data theme classified
        and bool(lineage.resource_id)
        and has_extent               # geographic bounding box present
        and has_crs                  # reference system present
    )
    return "conformant" if mandatory_present else "not evaluated"

Deriving the conformity degree from present elements prevents the common failure of a record that claims conformance while missing a mandatory field.

Configuration reference

Parameter Type Valid values Default
theme string a GEMET INSPIRE theme keyword required
resource_id string stable URN or agency code, globally unique required
default_crs string EPSG:3035, EPSG:4258, EPSG:4326 EPSG:3035
metadata_language string ISO 639-2 three-letter code (e.g. eng, deu) eng
conformity_spec string citation of the interoperability Implementing Rule required
lineage_max_chars int 1 – 4000 (keep statement within catalogue limits) 4000
charset string utf8 utf8

Conformity Is a Claim You Must Evidence

Three ways to state conformity, only two defensible Conformant with recorded evidence and honestly not-conformant are both acceptable; an unevidenced conformance claim is the one that produces a finding. DEGREE = true, with evidence A validator run, dated, whose output you retained Reproducible by the reviewer against the same record the goal DEGREE = false, with the gap named Honest, and entirely acceptable while work is in progress Tells a harvester exactly what not to rely on acceptable DEGREE = true, asserted by hand Nothing behind it; nobody ran anything Discovered the first time a harvester validates independently the finding

The middle row is the one teams resist and should not. A conformity statement of false, accompanied by the specific requirement not yet met, is a legitimate published position while remediation is under way — and it protects downstream users who would otherwise build on a claim that does not hold. Publishing true because the deadline arrived is a different kind of statement, and independent harvesters validate records routinely enough that it does not survive long.

Generate the statement from the validator rather than writing it. The record should carry the specification identifier, the date the validation ran, the validator version, and the outcome, all populated by the same job that produced the metadata. That makes the claim reproducible: a reviewer can run the same validator against the same record and get the same answer, which is the property that distinguishes evidence from assertion.

Common failure modes & mitigations

Failure Symptom Mitigation
Missing lineage element Validator flags mandatory LI_Lineage absent; record rejected by the national geoportal Enforce a non-empty step list at generation time, as build_lineage_statement does
Silent CRS drift Statement claims EPSG:3035 but the delivered file is still in the source grid Read the CRS back from the output file and compare to result_crs before writing metadata
Wrong theme keyword Free-text theme that is not from the GEMET INSPIRE vocabulary; discovery filters miss the record Constrain theme to the controlled vocabulary; reject values outside it
Unstable resource identifier Republished data set gets a new id each run, breaking downstream links Derive resource_id from a stable code, never from a timestamp or run id
Overstated conformity Record declares conformant but lacks extent or CRS Compute the conformity degree from present elements rather than hardcoding it

Harvesting Is the Real Deadline

Conformance is assessed on what a harvester retrieves, not on what sits in your repository, and that distinction sets the operational requirements more tightly than the specification does. Three properties of the served record matter as much as its content.

Stability of the resource identifier. A record whose identifier changes between harvests appears as a deletion and a creation rather than an update, which breaks the harvester’s history and any downstream reference to it. Derive the identifier from something permanent — a registered namespace plus a dataset UUID — never from a file path or a title that a curator might reasonably improve.

Availability during the harvest window. Harvesters retry, but not indefinitely, and a discovery service that is down during a scheduled crawl simply drops out of the federated catalogue until the next one. Where the crawl schedule is published, treat it as a maintenance constraint; where it is not, ask for it, because scheduling a deployment into an unknown crawl window is a coin flip.

Consistency between the record and the service it describes. A record advertising a download endpoint that returns a different CRS, or a dataset whose extent no longer matches the record’s, fails interoperability checks even when the metadata itself validates perfectly. This is the failure mode that survives every internal check, because internal validation inspects the document while the harvester inspects the relationship between the document and reality.

The practical response to all three is a post-publication verification job that behaves like a harvester: fetch the record through the public discovery endpoint, follow the links it advertises, and assert that what comes back matches what the record claims. Running it against your own service catches these before an external crawler does, and its output doubles as evidence that the published claims were tested rather than assumed.

Compliance & governance alignment

INSPIRE requirement Obligation in brief Lineage field / practice that satisfies it
Lineage (mandatory) Statement of source and processing history DatasetLineage.steps rendered by build_lineage_statement
Spatial data theme Classify against INSPIRE themes theme from the GEMET controlled vocabulary
Unique resource identifier Persistent, unique id for the resource Stable resource_id URN
Geographic bounding box Spatial extent of the data set Computed extent passed to conformity_degree
Coordinate reference system Declared reference system result_crs, defaulting to ETRS89-LAEA EPSG:3035
Conformity Degree of conformity to Implementing Rules conformity_degree derived from present elements
Encoding ISO 19139 XML Rendered per the pygeometa how-to

Free Text and Structure Serve Different Readers

One source, two renderings Structured process steps drive both the machine-readable lineage elements and the generated free-text statement, keeping the two from diverging. Structured process steps the single source LI_ProcessStep elements read by harvesters and validators queryable, ordered, typed Free-text statement read by people browsing a portal GENERATED, never hand-written Hand-authoring the statement guarantees it will contradict the steps within a release or two.

The requirement to supply a readable lineage statement is often satisfied by someone writing a paragraph, which is exactly how the statement and the structured steps come to disagree. The paragraph is written once and never revised; the steps change with every pipeline release. Six months later a portal visitor reads a description of a process that no longer runs, while a harvester reads accurate structured elements — and the two are both published under your name.

Generating the prose is not difficult and removes the divergence permanently: a template that walks the ordered steps and emits a sentence per transformation produces something readable, always current, and traceable to the same source the machine-readable elements come from. Where a curator genuinely needs to add context the steps cannot express, put it in a separate supplemental field rather than editing the generated statement, so regeneration never overwrites human input.

Phased rollout

A pragmatic path to INSPIRE conformance starts with classification and identity: pin every data set to a GEMET theme and a stable resource identifier, since a record cannot be discovered without them. Next, wire the structured ProcessStep capture into the pipelines that produce your themed data sets, so lineage accrues automatically rather than being reconstructed. Then generate the ISO 19139 XML and validate its structure, and finally derive the conformity declaration from the evidenced elements and publish to your national geoportal. Each stage has a clear success test: a record is INSPIRE-ready only when it carries a theme, a unique identifier, an extent, a CRS, and a lineage statement that truthfully names every reprojection and generalization applied — and when re-running the pipeline over unchanged inputs regenerates a byte-identical statement.

Approached this way, the INSPIRE metadata mandate becomes an output of the pipeline rather than a documentation chore bolted on before a deadline, and the same structured lineage feeds your ISO catalogue and your national reporting obligations without duplicate effort.

Frequently Asked Questions

Which conformance class should we target first?

Metadata conformance, because it gates discovery — a dataset that cannot be found through the discovery service is invisible regardless of how well the data itself conforms. Network service and interoperability conformance follow, and both are considerably larger pieces of work. Sequencing them the other way produces excellent data nobody can locate.

Do we need to publish a record for internal datasets?

Only for those within the directive’s thematic scope and made available to others, which is narrower than most agencies assume. The practical risk runs the other way, though: datasets that quietly become externally available without a record. Tie record generation to the publication step so scope is determined by what actually leaves rather than by an inventory decision made once.

How do we handle a dataset with no meaningful lineage?

State that, in the structured elements as well as the statement. A source marked as unknown, dated to acquisition, is a factual record; an empty lineage block is ambiguous between “no history” and “not yet documented”. Validators accept both, but only the first tells a downstream user what they are getting.

Can one ISO record serve both INSPIRE and a national profile?

Usually yes, since national profiles are typically ISO 19115 with additional mandatory elements. Generate from your internal model and apply the profile as an additive template rather than maintaining separate documents — divergent records for the same dataset will eventually disagree, and a harvester that reads both has no rule for choosing.

What triggers regeneration of a published record?

Any change to the dataset or its lineage, driven by the same event that produced the change. Time-based regeneration produces records that describe a state nobody published, and manual regeneration produces records that lag. Bind it to publication and the record and the artefact move together.

Is a validator failure a blocker for release?

For metadata conformance, yes — publishing a record you know to be invalid helps nobody and will be rejected by harvesters anyway. For interoperability conformance during a transition, no: publish with the conformity degree set honestly to false and the specific gap named. The distinction is between an invalid record and a valid record reporting non-conformance.