To implement web data provenance tracking step by step, do five things at fetch time: capture the source URL and timestamp, compute a content hash, assign a stable identifier, record the agent and method, and persist that metadata atomically alongside the payload. Everything else in this guide builds on those five actions.
Minimum provenance fields to capture at every fetch:
source— canonical URL of the fetched resourcefetch_timestamp— ISO 8601 UTC timestamp of the fetchfetch_method— HTTP method and client version (e.g.,GET/gyrence-fetch-v1)consent_indicator— flag or pointer to the legal basis for collectioncontent_hash— SHA-256 of the raw response body
A minimal four-field provenance schema covering source, fetch_timestamp, fetch_method, and consent_indicator is highly adoptable and unlocks most audit and compliance needs for scraped web data.
Three-step pilot checklist (one sprint):
- Instrument the fetch layer to emit a provenance record for every HTTP response.
- Persist that record atomically with the payload in an append-only store.
- Sign the canonicalized provenance JSON and index it by entity ID and timestamp.
Table of Contents
- What is data provenance vs. data lineage for web data?
- Which standards and serializations should you adopt?
- Practical capture techniques for web provenance
- Step-by-step implementation for web data provenance
- How should you store and query provenance at scale?
- Using provenance as an observability signal
- Tools you can adopt for provenance tracking
- Common pitfalls, governance, and privacy controls
- A hands-on example: instrumenting a Gyrence-style pipeline
- Key Takeaways
- What teams consistently underestimate about provenance adoption
- Gyrence gives you provenance signals from the first API call
- Useful sources
- FAQ
What is data provenance vs. data lineage for web data?
These two terms get conflated constantly, and the confusion leads teams to pick the wrong model and the wrong APIs.
Data provenance answers: where did this record come from, who produced it, and how? The W3C PROV conceptual model formalizes provenance as a graph of three types: Entities (things that exist, like a page snapshot), Activities (things that happen, like a crawl job), and Agents (things responsible for activities, like a scraper version or a worker process). Provenance is record-centric and backward-looking.
Data lineage answers: how does data flow through a system, and what downstream assets does a change affect? Lineage is pipeline-centric and forward-looking. It tells you which downstream tables break when an upstream schema changes.
For web scraping, the distinction is operational. You need provenance when you are auditing a training dataset for consent, reproducing a model input set, or debugging a data quality incident back to a specific URL and crawl run. You need lineage when you are doing impact analysis across a transformation graph. In practice, most scraping teams need both, but they should reach for provenance-first representations (W3C PROV, PROV-JSON) for audit and trust, and lineage-first representations (OpenLineage) for pipeline observability and change propagation. The PROV-PRIMER is the fastest way to internalize the distinction through worked examples.
Which standards and serializations should you adopt?
The W3C PROV family
The PROV-Overview describes four complementary specifications:
- PROV-O — the OWL2 ontology encoding of PROV-DM; use it when your storage layer is an RDF triple store or when you need semantic interoperability with linked-data consumers.
- PROV-AQ — the access and query specification; defines HTTP Link headers and provenance query services so clients can discover and retrieve provenance records programmatically.
OpenLineage
OpenLineage tracks three core entities: Dataset, Job, and Run. These map directly to PROV types:
| OpenLineage Entity | PROV Type | Notes |
|---|---|---|
| Dataset | Entity | A versioned data asset at a point in time |
| Job | Activity | A transformation or processing step |
| Run | Activity (qualified) | A specific execution of a Job with start/end times |
| Facets | Qualified relations / extensions | Domain-specific metadata attached to any entity |
OpenLineage events are JSON objects emitted at run start and run completion. They integrate natively with Airflow, Spark, and dbt via client libraries, and Marquez serves as the reference backend for collecting and visualizing those events.
Serialization selection
- PROV-JSON / PROV-N — use for provenance interchange between systems; PROV-JSON is machine-readable, PROV-N is human-readable. Both are compact and well-supported.
- JSON-LD — use when you need linked-data compatibility or plan to publish provenance as part of a knowledge graph. Pair with PROV-O context.
- OpenLineage JSON events — use for pipeline telemetry; emit at job start/complete and consume with Marquez or any OpenLineage-compatible backend.
Interoperability checklist:
- Assign HTTP URIs or URNs to every entity, activity, and agent — blank nodes break cross-system linking.
- Canonicalize URLs before hashing (strip tracking parameters, normalize scheme to
https, lowercase host). - Use ISO 8601 UTC for all timestamps; never store local time.
- Use OpenLineage facets to carry PROV-specific fields (content_hash, consent_indicator) in pipeline events.
Practical capture techniques for web provenance
The single most important decision in a provenance implementation is where to capture. Get this wrong and you spend months retrofitting.
Capture points, ranked by value
Fetch layer is the highest-value instrumentation point. Every HTTP response carries a URL, status code, response headers, and a body you can hash. Capturing provenance here requires no schema knowledge of the payload and covers 100% of fetched resources automatically.

Pre-commit hooks for repository-based packaging work well when datasets are assembled from files checked into Git or stored in object storage. DataLad uses this pattern: every datalad get or datalad run command records what was downloaded and what command produced it, giving you dataset-level provenance without manual annotation.
Transform step instrumentation captures how records change between pipeline stages. Instrument each transform to emit an OpenLineage RunEvent at start and complete, carrying input/output dataset identifiers and record counts as facets.
Model training manifests are the terminal provenance artifact. Before a training run starts, generate a manifest listing every dataset entity ID, its content hash, and its provenance record pointer. Store the manifest hash in the model card.
Automated instrumentation vs. manual logging
| Dimension | Automated instrumentation | Manual logging |
|---|---|---|
| Coverage | High — every call captured | Low — only what developers remember |
| Overhead | Low per-call, fixed setup cost | Zero setup, high maintenance cost |
| Fidelity | Structural fields only | Can capture semantic context |
| Failure modes | Silent if middleware is bypassed | Inconsistent schema across teams |
For column-level provenance in structured extraction, capture which source field mapped to which output field and which transform rule applied. For record-level provenance, a single content hash and source pointer per record is sufficient for most audit needs. Column-level is worth the overhead only when you need field-level lineage for regulatory compliance or model feature attribution.
Step-by-step implementation for web data provenance
This is the full playbook, from design to production.
Step 1: Define your provenance schema
Start with the minimal schema: source, fetch_timestamp, fetch_method, consent_indicator, content_hash. Add fetch_agent (tool name + semver) and entity_id (stable URN). Version the schema from day one using a schema_version field.
Step 2: Assign stable identifiers
Every entity needs a stable, collision-resistant ID. Use a URN namespace your team controls:
urn:gyrence:page:{sha256_of_canonical_url}
urn:gyrence:run:{job_name}:{iso_date}:{uuid4}
urn:gyrence:agent:{tool_name}:{semver}
Canonical URL normalization is the most common source of duplicate entities. Strip UTM parameters, normalize scheme to https, lowercase the host, and remove trailing slashes before computing the URL hash.
Pro Tip: Build a canonicalize_url(url: str) -> str function in a shared library and import it everywhere. A single inconsistency in URL normalization will produce duplicate entity IDs that silently corrupt your provenance graph.
Step 3: Instrument the fetch layer
Wrap your HTTP client to emit a provenance record on every response. Pseudocode:
def fetch_with_provenance(url: str, agent: str) -> FetchResult:
canonical = canonicalize_url(url)
entity_id = f"urn:page:{sha256(canonical)}"
response = http_client.get(canonical)
content_hash = sha256(response.body)
prov_record = {
"schema_version": "1.0",
"entity_id": entity_id,
"source": canonical,
"fetch_timestamp": utcnow_iso8601(),
"fetch_method": f"GET/{agent}",
"consent_indicator": lookup_consent(canonical),
"content_hash": content_hash,
"fetch_agent": agent,
"http_status": response.status_code,
}
persist_provenance(prov_record)
return FetchResult(body=response.body, provenance=prov_record)
Step 4: Instrument transform steps
At each transform, emit an OpenLineage RunEvent and append a PROV derivation record:
def transform_with_provenance(input_entity_id, output_entity_id, run_id, step_name):
ol_event = {
"eventType": "COMPLETE",
"eventTime": utcnow_iso8601(),
"run": {"runId": run_id},
"job": {"namespace": "scrape-pipeline", "name": step_name},
"inputs": [{"namespace": "pages", "name": input_entity_id}],
"outputs": [{"namespace": "records", "name": output_entity_id}],
}
emit_openlineage_event(ol_event)
prov_derivation = {
"type": "wasDerivedFrom",
"derived_entity": output_entity_id,
"source_entity": input_entity_id,
"activity": run_id,
"timestamp": utcnow_iso8601(),
}
persist_provenance(prov_derivation)
Step 5: Persist provenance atomically
Write the provenance record in the same transaction (or the same atomic write) as the payload. If the payload write succeeds and the provenance write fails, you have an orphaned record with no audit trail. Use a write-ahead log or a two-phase commit pattern if your storage layer supports it. For simpler setups, write provenance first and treat a missing provenance record as a signal to reject the payload.
Step 6: Sign and anchor
Sign the canonicalized provenance JSON with a private key your team controls. For tamper-evident audit trails, compute a Merkle root over a batch of provenance records and anchor it to an immutable store (S3 Object Lock, a ledger service, or a blockchain anchor). This approach is described in detail in the developer guide for provenance APIs and immutable audit trails.
Step 7: Expose provenance via PROV-AQ and HTTP Link headers
Per PROV-AQ, add a Link header to HTTP responses from your data API:
Link: <https://prov.example.com/records/urn:page:abc123>; rel="http://www.w3.org/ns/prov#has_provenance"
Implement a provenance query endpoint at /prov/{entity_id} that returns PROV-JSON. This lets downstream consumers discover provenance programmatically without out-of-band documentation.
Step 9: Operational sizing
A minimal provenance record (eight fields, no blobs) runs a few hundred bytes as JSON. At high fetch volumes, this represents manageable storage requirements for provenance metadata before compression. Store blobs (raw HTML) in object storage (S3 or equivalent); store provenance metadata in a queryable document store or graph database. Index on entity_id, fetch_timestamp, consent_indicator, and fetch_agent.
A pilot covering a single scraping job and one downstream transform can be instrumented quickly. Production rollout across a multi-stage pipeline typically takes multiple weeks, depending on the number of transform steps and the maturity of the existing logging infrastructure.
A sample PROV-JSON record for a fetched page:
{
"entity": {
"urn:page:a3f1c9": {
"prov:type": "prov:Entity",
"schema_version": "1.0",
"source": "https://example.com/products/widget-a",
"fetch_timestamp": "2026-03-15T14:22:00Z",
"fetch_method": "GET/gyrence-fetch-v1",
"consent_indicator": "robots_allowed:true;tos_reviewed:2026-01-10",
"content_hash": "sha256:a3f1c9...",
"fetch_agent": "gyrence-fetch-v1.4.2"
}
},
"activity": {
"urn:run:crawl-job:2026-03-15:uuid4": {
"prov:type": "prov:Activity",
"prov:startTime": "2026-03-15T14:20:00Z",
"prov:endTime": "2026-03-15T14:25:00Z"
}
},
"wasGeneratedBy": {
"_:wgb1": {
"prov:entity": "urn:page:a3f1c9",
"prov:activity": "urn:run:crawl-job:2026-03-15:uuid4"
}
}
}
How should you store and query provenance at scale?
Storage choice depends on your query patterns, not your team's preferred database.
| Backend | Best for | Tradeoffs |
|---|---|---|
| Append-only ledger (S3 Object Lock / QLDB) | Immutable audit trail, tamper evidence | No ad-hoc queries; need a separate index |
| Graph DB (Neo4j / JanusGraph) | Traversal queries (find all ancestors of a record) | Higher operational cost; overkill for simple lookups |
| RDF triple store (Apache Jena / Oxigraph) | PROV-O / linked-data interoperability | SPARQL learning curve; slower for high-throughput writes |
| Document store + search index (PostgreSQL + Elasticsearch) | Operational queries, dashboards, consent audits | No native graph traversal; join-heavy for deep lineage |
For most scraping teams, a document store with a search index covers 90% of operational queries. Add a graph database only when you need multi-hop traversal (e.g., "find all training records that derive from URLs on domain X").
HTTP exposure via PROV-AQ
PROV-AQ defines two mechanisms: an HTTP Link header on the resource itself pointing to its provenance record, and a provenance query service that accepts entity URIs and returns PROV documents. Implement both. The Link header costs one header per response; the query service is a standard REST endpoint.
For LLM context pipelines that ingest web data, exposing provenance via PROV-AQ means the consuming agent can verify the source and freshness of every context chunk without out-of-band coordination.
Index these fields for operational performance: entity_id (primary key), fetch_timestamp (range queries), consent_indicator (compliance scans), fetch_agent (incident triage), content_hash (deduplication).
Using provenance as an observability signal
Treating provenance as an observability requirement changes how you debug data quality incidents. Instead of grepping logs, you query a structured provenance graph.
The pattern: attach run_id and entity_id to every data quality alert. When an alert fires, the triage query is:
SELECT source, fetch_timestamp, fetch_agent, content_hash
FROM provenance
WHERE entity_id IN (
SELECT entity_id FROM quality_alerts WHERE alert_id = ?
)
ORDER BY fetch_timestamp ASC
LIMIT 1;
That query finds the earliest fetch that produced the bad record, the URL it came from, and the scraper version that ran. From there, you check whether the content hash changed between runs (the source changed) or whether the hash is stable but the quality metric degraded (a transform introduced the defect).
Operational recipe for provenance-backed alerts:
- Tag every quality metric with
entity_idandrun_idat write time. - Build a dashboard that shows quality score by
fetch_agentversion and by source domain. - Set alert rules that fire when quality drops below threshold AND
consent_indicatoris missing — those records are both low-quality and legally risky. - For incident reconstruction, store the full provenance graph snapshot at the time of the incident, not just the alert metadata.
- For training run reproducibility, validate that the content hashes in the training manifest match the hashes in the provenance store before the run starts.
Linking data quality standards to provenance metadata is what turns a quality monitoring system from a dashboard into an audit trail.
Tools you can adopt for provenance tracking
OpenLineage and Marquez
OpenLineage provides client libraries for Python, Java, and Scala, plus native integrations for Airflow, Spark, dbt, and Flink. Instrument your scraping jobs by emitting RunEvent objects at job start and completion. Marquez is the reference backend: it collects OpenLineage events, stores them in PostgreSQL, and exposes a REST API and a web UI for lineage visualization. A Marquez-backed pilot is the fastest path to a working lineage graph for a new pipeline.
For CI/CD pipeline instrumentation, OpenLineage run events map cleanly to pipeline job executions, giving you lineage across both data and deployment boundaries.
DataLad
DataLad captures dataset-level provenance for downloaded and generated files using Git and git-annex under the hood. Every datalad run command records the exact command, inputs, outputs, and environment, producing a reproducible provenance record at the dataset granularity. Use DataLad when your pipeline assembles datasets from multiple sources and you need snapshot-level reproducibility.
Apache Atlas
Apache Atlas provides metadata governance for Hadoop-ecosystem pipelines. It supports entity types, classifications, and lineage graphs. Use it when your organization already runs an Atlas-compatible data catalog and you need to register scraped datasets as governed entities with lineage to downstream consumers.
RDF/PROV toolchains
For linked-data use cases, the PROV-O ontology combined with an RDF store (Apache Jena, Oxigraph) gives you SPARQL-queryable provenance graphs. This is the right choice when provenance records need to interoperate with external knowledge graphs or when you are publishing provenance as part of a public data catalog.
OpenTelemetry
OpenTelemetry traces can carry provenance metadata as span attributes. Attach entity_id, run_id, and content_hash to fetch spans. This does not replace a dedicated provenance store, but it gives you provenance signals in your existing observability stack at near-zero additional cost.
Common pitfalls, governance, and privacy controls
Governance checklist
- Version your provenance schema and maintain backward compatibility.
- Apply access controls to the provenance layer separately from the payload layer. Provenance records may contain sensitive metadata (consent evidence, operator identity) that not all consumers should read.
- Define retention periods for provenance records. Legal holds may require keeping provenance longer than the payload itself.
- Implement consent enforcement logic: reject or quarantine records where
consent_indicatoris missing or denied before they enter a training pipeline. - Enforce provenance schema compliance at the pipeline policy layer using policy-as-code tools like OPA or Conftest.
Privacy controls
- Flag provenance records that reference PII-containing pages with a
pii_flag: truefield. - When a record is redacted, do not delete its provenance entry. Instead, write a redaction provenance record:
redactedRecord wasDerivedFrom originalRecord; redactionActivity wasAssociatedWith redactionAgent. - Store consent evidence pointers (URLs to terms of service snapshots, robots.txt hashes) in the provenance record, not just a boolean flag.
- For SEC disclosures and regulated data, provenance records serve as the legal basis documentation for each fetch.
Cost and timeline guidance: A minimal provenance implementation (fetch layer only, document store backend) adds roughly 5–10% overhead to pipeline latency and under 2% to storage costs at typical scraping volumes. A full implementation with graph storage, signing, and PROV-AQ endpoints typically takes 6–12 weeks for a team of two engineers, depending on pipeline complexity.
A hands-on example: instrumenting a Gyrence-style pipeline
This section maps a concrete scraping pipeline to PROV and OpenLineage entities, using Gyrence primitives as the instrumentation points.
Architecture
Search → Traverse (Gyre) → Fetch → Extract → Transform → Dataset Manifest → Training Manifest
Each primitive emits a provenance record. The Fetch primitive produces the richest provenance: it has the canonical URL, HTTP status, content hash, and agent version. Extract produces a derivation record linking the structured JSON output to the raw page entity. Transform produces an OpenLineage RunEvent linking input records to output records.
Gyrence primitives mapped to PROV and OpenLineage
| Gyrence Primitive | PROV Type | OpenLineage Entity | Provenance Fields |
|---|---|---|---|
| Search | Activity | Job | query, result_count, timestamp |
| Traverse (Gyre) | Activity | Job + Run | start_url, depth, url_count, run_id |
| Fetch | Activity + Entity | Run + Dataset | source, content_hash, fetch_timestamp, fetch_agent, consent_indicator |
| Extract | Activity | Job + Run | input_entity_id, schema_version, output_entity_id, field_count |
| Map | Activity | Job | domain, url_count, sitemap_hash, run_id |
Sample PROV-JSON for a Fetch + Extract sequence
{
"entity": {
"urn:page:a3f1c9": {
"prov:type": "prov:Entity",
"source": "https://example.com/products/widget-a",
"content_hash": "sha256:a3f1c9...",
"fetch_timestamp": "2026-03-15T14:22:00Z",
"consent_indicator": "robots_allowed:true"
},
"urn:record:extract-job:row-001": {
"prov:type": "prov:Entity",
"schema_version": "product-v2",
"field_count": 12
}
},
"activity": {
"urn:run:fetch:2026-03-15:uuid-fetch": {
"prov:type": "prov:Activity",
"prov:startTime": "2026-03-15T14:22:00Z"
},
"urn:run:extract:2026-03-15:uuid-extract": {
"prov:type": "prov:Activity",
"prov:startTime": "2026-03-15T14:22:05Z"
}
},
"wasGeneratedBy": {
"_:wgb1": {
"prov:entity": "urn:page:a3f1c9",
"prov:activity": "urn:run:fetch:2026-03-15:uuid-fetch"
},
"_:wgb2": {
"prov:entity": "urn:record:extract-job:row-001",
"prov:activity": "urn:run:extract:2026-03-15:uuid-extract"
}
},
"wasDerivedFrom": {
"_:wdf1": {
"prov:generatedEntity": "urn:record:extract-job:row-001",
"prov:usedEntity": "urn:page:a3f1c9"
}
}
}
Corresponding OpenLineage event for the Extract run
{
"eventType": "COMPLETE",
"eventTime": "2026-03-15T14:22:10Z",
"run": {
"runId": "uuid-extract",
"facets": {
"sourceCodeLocation": {"_producer": "gyrence-extract-v1.4.2"}
}
},
"job": {"namespace": "gyrence-pipeline", "name": "extract-product"},
"inputs": [{"namespace": "pages", "name": "urn:page:a3f1c9"}],
"outputs": [{"namespace": "records", "name": "urn:record:extract-job:row-001"}]
}
Replay and validation steps
- Load the training manifest and extract all
entity_idvalues. - For each entity, fetch the provenance record from the provenance store and verify the
content_hashagainst the stored blob. - Verify the digital signature on each provenance record.
- Assert that
consent_indicatoris not null or denied for every entity. - If any check fails, halt the training run and log the failing entity IDs.
For structured extraction pipelines, schema validation at step 2 catches schema drift between the provenance record version and the current extraction schema before it reaches the model.
Glen's prior implementation notes and architecture writeups are available at gyrence.com/docs for teams looking to adapt these patterns to their own pipelines.
Key Takeaways
Effective web data provenance tracking requires capturing structured metadata at the fetch layer, assigning stable identifiers, signing records for tamper evidence, and exposing them via PROV-AQ-compatible endpoints so every downstream consumer can verify the origin and integrity of the data it processes.
| Point | Details |
|---|---|
| Capture at fetch | Record source, fetch_timestamp, fetch_method, consent_indicator, and content_hash on every HTTP response. |
| Assign stable IDs | Use a shared URN namespace and canonicalize URLs before hashing to prevent duplicate entity records. |
| Sign and anchor | Sign provenance JSON at write time and anchor Merkle roots to an immutable store for tamper-evident audit trails. |
| Choose storage by query pattern | Use a document store for operational queries; add a graph DB only when multi-hop traversal is required. |
| Gyrence primitives as capture points | Gyrence's Fetch, Extract, and Traverse primitives each produce provenance signals that map directly to PROV entities and OpenLineage runs. |
What teams consistently underestimate about provenance adoption
The technical implementation is the easy part. The hard part is organizational.
Most teams underestimate the cost of URL canonicalization. It sounds trivial — strip a few query parameters, normalize the scheme — but in practice, every team that has not built a shared canonicalization library ends up with three slightly different implementations that produce different entity IDs for the same page. The provenance graph becomes unqueryable within weeks.
The second underestimation is retention. Teams instrument the fetch layer, persist provenance records, and then apply the same 30-day log retention policy to provenance that they apply to application logs. Provenance records are not logs. They are the legal and technical basis for every downstream use of the data. A training dataset assembled from records whose provenance was deleted is an unauditable asset. Set retention for provenance records to match the retention of the data they describe, plus the statute of limitations for any applicable regulation.
The third is the gap between "we have provenance" and "we can query provenance." Storing records is not enough. You need indexed, queryable access to answer the questions that actually matter: which records lack consent, which runs produced anomalous output, which source domains contributed to a given model version. Build the query layer before you need it, not after an incident.
The practical advice: scope your pilot to a single scraping job and one downstream transform. Get the fetch layer instrumented, the provenance records persisted and signed, and one query working end-to-end. That is a sprint. Everything else is iteration.

Gyrence gives you provenance signals from the first API call
Web data provenance tracking is only as good as the data you capture at the source. Gyrence is built so that every primitive produces the structured, typed output that provenance systems need: canonical URLs, typed failure modes, and structured JSON payloads that carry the metadata your pipeline needs to build a complete audit trail.
Each Gyrence primitive maps directly to a provenance capture point. Fetch returns the canonical URL, HTTP status, and raw body you need to compute a content hash. Extract returns structured JSON with schema version metadata. Traverse (Gyre) returns a typed list of discovered URLs with depth and run metadata. Map returns a domain URL graph you can snapshot and version. Every call returns a discriminated-union response, including failure cases, so your provenance records reflect reality rather than hiding errors.
Teams building provenance-tracked pipelines can start with the Gyrence API and connect to their existing OpenLineage or PROV-compatible backend in a single sprint. Integration docs are at gyrence.com/docs. Sign up for a workspace at gyrence.com/app and run your first instrumented fetch in under an hour.
Useful sources
- The OpenLineage standard, widely adopted for data pipeline observability
- PROV-Overview
- PROV-AQ: Provenance Access and Query
- PROV primer: an introduction to PROV data model
- The PROV Ontology (PROV-O)
- Basic provenance tracking
- Minimal Provenance Metadata for Enterprise AI
FAQ
How do you track data provenance for web scraping?
Capture a provenance record at every HTTP fetch containing the canonical source URL, fetch timestamp, HTTP method, agent version, consent indicator, and a SHA-256 hash of the response body. Persist that record atomically with the payload, sign it, and expose it via a PROV-AQ-compatible query endpoint.
What is the difference between data provenance and data lineage?
Provenance is record-centric and backward-looking: it answers where a specific record came from and who produced it, using the W3C PROV model of Entities, Activities, and Agents. Lineage is pipeline-centric and forward-looking: it answers how data flows through a system and what downstream assets a change affects, as modeled by OpenLineage's Dataset/Job/Run structure.
Which standards should you use for web data provenance tracking?
Use W3C PROV-DM as the conceptual schema, PROV-JSON or PROV-N for serialization, and OpenLineage JSON events for pipeline telemetry. Add PROV-O and an RDF store only if you need semantic interoperability with linked-data systems. Expose provenance records via HTTP Link headers per PROV-AQ.
What are the minimum fields to capture for provenance at fetch time?
The minimum viable set is four fields: source (canonical URL), fetch_timestamp (ISO 8601 UTC), fetch_method (HTTP method and client version), and consent_indicator (legal basis flag or pointer). This minimal schema is highly adoptable and covers most operational and compliance requirements for web data pipelines.
How does Gyrence support provenance tracking in web data pipelines?
Each Gyrence primitive (Fetch, Extract, Traverse, Search, Map) returns typed, structured output that maps directly to PROV entities and OpenLineage run events. Fetch provides the canonical URL, HTTP status, and raw body needed to compute a content hash; Extract provides schema-versioned JSON output; Traverse provides run metadata for the crawl. Teams can instrument a provenance-tracked pipeline starting from the first API call.

