Zillow Listing Scraper
Pricing
from $1.00 / 1,000 results
Zillow Listing Scraper
Scrape Zillow property listings by location, search URL, property URL, or ZPID. Track prices, status changes, lifecycle history, coverage quality, conflicts, and source provenance with false-removal protection.
Pricing
from $1.00 / 1,000 results
Rating
0.0
(0)
Developer
SearchShark Tools
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
0
Monthly active users
3 days ago
Last modified
Categories
Share
๐ Zillow Scraper - Listing Change Ledger & Coverage Monitor
Zillow Scraper - Listing Change Ledger & Coverage Monitor extracts structured Zillow property data and helps you track what changed, where it was observed, and whether the scan was complete enough to trust.
Use it for property research, listing monitoring, CRM automation, PropTech workflows, ETL pipelines, and change detection without manually revisiting Zillow pages.
- ๐ Scrape Zillow listings: collect ZPIDs, addresses, prices, beds, baths, square footage, property type, coordinates, and more
- ๐ Search by location or Zillow URL: use cities, ZIP codes, neighborhoods, direct Zillow search URLs, property URLs, or ZPIDs
- ๐งฌ Deduplicate by ZPID: reconcile overlapping observations into one canonical property record
- ๐งญ Preserve provenance: keep the searches and search URLs that observed each property
- ๐ Track listing changes: detect new listings, price cuts, price increases, status changes, reactivations, and absence signals
- ๐ก Avoid false removals: blocked, capped, or incomplete scans are not silently treated as confirmed removals
- ๐ Measure scan quality: receive coverage diagnostics showing caps, failures, blocks, unique ZPIDs, duplicates, and detail success
- โก Automate workflows: export structured results through Apify Dataset, API, integrations, or downstream applications
๐ฆ What data does Zillow Scraper extract?
| ๐ ZPID | ๐ Canonical Zillow URL |
| ๐ Address | ๐ท Listing status |
| ๐ต Price | ๐ Beds |
| ๐ Baths | ๐ Square feet |
| ๐ Property type | ๐ Zestimate when available |
| ๐ Latitude & longitude | ๐ Scrape timestamp |
| ๐ Source query | ๐ Source URL |
| ๐งญ Matched queries | ๐ Matched search URLs |
| ๐ฅ First discovery query | ๐งน Duplicate observation count |
| โ Data consistency status | โ ๏ธ Conflict evidence |
| ๐ฌ Detail enrichment status | ๐ Coverage diagnostics |
| ๐ Change events | ๐งฌ Lifecycle summaries |
Missing fields may be returned as
null. The Actor does not invent property data that Zillow does not expose.
๐ Features
Zillow Scraper is designed for auditable property extraction and change monitoring.
- Multiple discovery modes: locations, Zillow search URLs, property URLs, and ZPIDs
- Canonical ZPID reconciliation: use stable Zillow property IDs as the primary identity
- Overlapping-query provenance: preserve every query and search URL that observed a property
- Conflict detection: retain material disagreements instead of silently hiding conflicting values
- Coverage diagnostics: report whether each discovery scope was complete, partial, blocked, capped, or unknown
- False-removal protection: incomplete scans do not create fake confirmed-removal events
- Listing lifecycle tracking: retain first seen, last seen, observation counts, price-cut totals, pending transitions, and reactivations
- Change-event output: emit explicit machine-readable events with previous/current values and evidence
- Selective detail enrichment: fetch property details for all listings or only when they are new, changed, or insufficient
- Per-search and global limits: control maximum accepted listing observations
- Retry handling: retry temporary request failures according to your configuration
- Concurrent discovery: process independent search targets in parallel
- API-friendly output: every Dataset row uses a predictable
recordType - Browser-backed Zillow transport: designed for live Zillow pages and current Zillow response structures
โฌ๏ธ Input
You can configure Zillow Scraper directly from the Apify Console or send input programmatically through the Apify API.
You can combine multiple input types in one run.
๐ Locations
Use locations for Zillow location searches.
Examples:
Austin, TXMiami, FL90210Downtown Los Angeles, CA
Example:
{"locations": ["Austin, TX","Miami, FL"]}
Each location becomes its own discovery scope with its own coverage evidence.
๐ Zillow search URLs
Use searchUrls when you already have a Zillow search page.
Example:
{"searchUrls": ["https://www.zillow.com/austin-tx/"]}
The Actor keeps the search URL as provenance and applies supported Actor filters when configured.
๐ Direct property URLs
Use propertyUrls to scrape specific public Zillow property pages.
Example:
{"propertyUrls": ["https://www.zillow.com/homedetails/example-property/123456789_zpid/"]}
Direct property inputs are validated against the embedded ZPID when available.
๐ ZPIDs
Use zpids when you already know the Zillow property IDs.
Example:
{"zpids": ["123456789","987654321"]}
ZPIDs are treated as stable property identities for reconciliation and monitoring.
๐ข Maximum items per search
maxItemsPerLocation controls the maximum accepted listing observations from each location or Zillow search URL.
Minimum: 1Default: 1000Maximum: 5000
If the limit is reached before completeness can be proven, the search is reported as:
coverageStatus: CAPPED
with a transparent reason such as:
USER_TOTAL_LIMIT_REACHED
๐ Maximum total items
maxTotalItems limits accepted observations across all direct targets and searches in the run.
Minimum: 1Default: 5000Maximum: 50000
This is a maximum, not a guarantee.
If Zillow exposes fewer usable listings, the Actor returns the listings it can verify instead of fabricating rows.
๐ Listing filters
๐ท Listing status
Supported listingStatus values:
for_salefor_rentsoldpendingany
any preserves the URL/default status state instead of forcing a specific supported status filter.
Default:
for_sale
๐ Property types
Supported propertyTypes values:
SINGLE_FAMILYCONDOTOWNHOUSEMULTI_FAMILYAPARTMENTMANUFACTUREDLOT
Example:
{"propertyTypes": ["SINGLE_FAMILY","CONDO"]}
๐ต Price filters
Optional inputs:
minPricemaxPrice
Example:
{"minPrice": 300000,"maxPrice": 900000}
๐ Bed and bath filters
Optional inputs:
minBedsmaxBedsminBaths
Example:
{"minBeds": 3,"maxBeds": 5,"minBaths": 2}
๐ฌ Detail enrichment
Set:
includeDetails: true
to allow Zillow property-detail requests.
Supported detailStrategy values:
noneallnew_or_changed_only
Default:
new_or_changed_only
none
Skip detail enrichment.
all
Attempt detail enrichment for every canonical property, subject to maxDetailFetches.
new_or_changed_only
Use detail requests selectively for records that are new, changed, conflicting, or missing useful information.
This can reduce unnecessary requests during recurring monitor runs.
๐ข Maximum detail fetches
maxDetailFetches limits the number of property-detail requests in one run.
Minimum: 0Default: 250Maximum: 5000
Coverage output reports:
detailRequesteddetailSucceededdetailSuccessRate
so downstream systems can see how much enrichment actually succeeded.
๐งน ZPID deduplication
By default:
deduplicateByZpid: true
The Actor reconciles multiple observations of the same ZPID into one canonical CURRENT record.
This is useful when the same property appears in:
Austin, TX+78747+a Zillow search URL
Instead of blindly returning duplicate properties, the Actor can preserve the overlap as provenance.
๐งญ Matched-query provenance
When:
preserveMatchedQueries: true
the canonical property can include:
{"matchedQueries": ["Austin, TX","78747"],"matchedSearchUrls": ["https://www.zillow.com/austin-tx/","https://www.zillow.com/..."]}
This answers an important question:
Which discovery scopes actually observed this ZPID?
That provenance is especially useful for ETL, CRM routing, data QA, and monitoring systems.
โ ๏ธ Cross-source conflicts
If material observations disagree, the Actor can preserve the disagreement instead of silently choosing a value.
Example:
{"dataStatus": "CONFLICT","conflicts": [{"field": "price","values": [500000,525000]}]}
Possible dataStatus values:
CONSISTENTCONFLICTPARTIAL
This makes conflicting source evidence visible to downstream automation.
๐ Coverage diagnostics
Enable:
includeCoverageReport: true
to receive COVERAGE records for discovery scopes.
Coverage can include:
rawRowsuniqueZpidsduplicatesRemovedreportedMatchespagesScannedpartitionsScannedrequestsSucceededrequestsFaileddetailRequesteddetailSucceededdetailSuccessRatecapHitblockedRequestscoverageStatuscoverageReasonscheckedAt
Supported coverageStatus values:
COMPLETEPARTIALBLOCKEDCAPPEDUNKNOWN
๐ก Why coverage matters
A scraper should not treat:
0 results
as automatically meaning:
0 properties exist
A scan may instead be:
blockedpartially parsedcapped by a user limitaffected by a request failuremissing detail enrichment
Zillow Scraper exposes these conditions so automated systems can decide whether the output is safe to trust.
๐ Monitoring changes across runs
Set:
monitorMode: true
and provide a stable:
monitorId
to compare the current run with persistent monitor state.
Example:
{"monitorMode": true,"monitorId": "austin-investment-watch"}
Use the same monitorId on future runs to continue the same history.
๐ First monitor run
When a property is seen for the first time, the Actor can emit:
changeType: NEW
The lifecycle state begins with:
firstSeenAtlastSeenAtobservationsCountlifecycleStage
๐ Later monitor runs
If a property is observed again with no material change:
No new CHANGE_EVENT is required
but its lifecycle state can still update:
lastSeenAtobservationsCount
If something materially changes, the Actor can emit an evidence-backed change event.
๐ Change-event types
Supported changeType values include:
NEWPRICE_CUTPRICE_INCREASESTATUS_CHANGEDACTIVE_AGAINNOT_SEEN_CONFIRMEDNOT_SEEN_PARTIAL_SCANDATA_CONFLICT
Each CHANGE_EVENT can contain:
changedFieldspreviousValuescurrentValuesdetectedAtpreviousObservedAtcurrentObservedAtpriceChangepriceChangePercentobservationConfidenceevidencereasonCodes
๐ Price changes
Example:
{"recordType": "CHANGE_EVENT","zpid": "123456789","changeType": "PRICE_CUT","changedFields": ["price"],"previousValues": {"price": 650000},"currentValues": {"price": 625000},"priceChange": -25000}
Lifecycle output can retain:
numberOfPriceCutscumulativePriceCutcumulativePriceCutPercent
๐ท Status changes
The Actor can track status transitions such as:
FOR_SALE โ PENDINGPENDING โ FOR_SALE
Lifecycle output can retain:
wentPendingCountbackOnMarketCountstatusTransitions
when event-history retention is enabled.
๐ก False-removal protection
One of the most important monitoring rules is:
An incomplete Zillow scan must not be treated as proof that a property disappeared.
If a previously observed property is missing from a run, the Actor evaluates the scan evidence first.
โ Confirmed absence
When the required discovery coverage is reliable enough, the Actor can emit:
NOT_SEEN_CONFIRMED
โ ๏ธ Incomplete scan
When the search was blocked, capped, failed, or otherwise incomplete, the Actor can emit:
NOT_SEEN_PARTIAL_SCAN
instead of silently declaring the property removed.
The retained monitor state is protected from fake disappearance signals caused by bad scans.
๐งฌ Lifecycle records
In monitor mode, the Actor can emit LIFECYCLE records such as:
{"recordType": "LIFECYCLE","zpid": "123456789","firstSeenAt": "2026-09-01T00:00:00.000Z","lastSeenAt": "2026-09-11T00:00:00.000Z","observationsCount": 6,"numberOfPriceCuts": 2,"cumulativePriceCut": -35000,"wentPendingCount": 1,"backOnMarketCount": 1,"lifecycleStage": "FOR_SALE","statusTransitions": []}
This provides a compact history summary without requiring you to reconstruct every state transition manually.
๐ Retain lifecycle history
Set:
retainEventHistory: true
to retain supported lifecycle status-transition history in persistent monitor state.
The current version does not create a separate historical-event Dataset for every previous observation.
๐ฏ Emit only changes
Set:
emitOnlyChanges: true
when you primarily want change events during monitoring.
In this mode, normal CURRENT and LIFECYCLE rows can be omitted from public output while requested coverage diagnostics remain available.
This is useful for:
webhooksCRM triggersalertsscheduled monitorschange-only ETL jobs
๐ Proxy configuration
Zillow can return temporary blocks or interactive challenges.
You can provide an Apify proxyConfiguration when needed.
Example:
{"proxyConfiguration": {"groups": ["UNBLOCKER"]}}
The Actor does not pretend that a blocked page is a successful empty result.
Blocked requests are reported through coverage and error diagnostics such as:
blockedRequestscoverageStatus: BLOCKEDerrorCode: BLOCKED
The Actor is designed to work with public Zillow pages. It does not bypass interactive CAPTCHA or human-verification challenges.
โ๏ธ Reliability controls
๐ Maximum concurrency
maxConcurrency controls how many independent search targets can be collected concurrently.
Minimum: 1Default: 8Maximum: 50
๐ Maximum retries
maxRetries controls retry attempts for retryable Zillow failures.
Minimum: 0Default: 3Maximum: 10
โฑ Request delay
requestDelayMs controls the base delay used around throttled/retry requests.
Minimum: 0 msDefault: 250 msMaximum: 30000 ms
๐งช Example input
{"locations": ["Austin, TX"],"searchUrls": [],"propertyUrls": [],"zpids": [],"maxItemsPerLocation": 100,"maxTotalItems": 500,"listingStatus": "for_sale","propertyTypes": ["SINGLE_FAMILY","CONDO"],"minPrice": 300000,"maxPrice": 900000,"minBeds": 3,"minBaths": 2,"includeDetails": true,"detailStrategy": "new_or_changed_only","maxDetailFetches": 100,"deduplicateByZpid": true,"preserveMatchedQueries": true,"includeCoverageReport": true,"monitorMode": true,"monitorId": "austin-homes-watch","emitOnlyChanges": false,"retainEventHistory": true,"proxyConfiguration": {"groups": ["UNBLOCKER"]},"maxConcurrency": 4,"maxRetries": 3,"requestDelayMs": 250}
โฌ๏ธ Output
Results are stored in the Actor's default Apify Dataset.
You can access them through:
OutputStorageApify APIIntegrations
The Dataset can contain five record types:
CURRENTCHANGE_EVENTLIFECYCLECOVERAGEERROR
Use the recordType field to route each row in downstream workflows.
๐ Example CURRENT record
{"recordType": "CURRENT","zpid": "123456789","canonicalUrl": "https://www.zillow.com/homedetails/123456789_zpid/","address": "123 Example St, Austin, TX 78701","status": "FOR_SALE","price": 625000,"beds": 3,"baths": 2,"sqft": 1800,"propertyType": "SINGLE_FAMILY","zestimate": null,"latitude": 30.2672,"longitude": -97.7431,"scrapedAt": "2026-09-11T00:00:00.000Z","sourceQuery": "Austin, TX","sourceUrl": "https://www.zillow.com/austin-tx/","matchedQueries": ["Austin, TX"],"matchedSearchUrls": ["https://www.zillow.com/austin-tx/"],"firstDiscoveredByQuery": "Austin, TX","duplicateObservationCount": 0,"dataStatus": "CONSISTENT","conflicts": [],"detailFetched": true,"detailStatus": "SUCCESS"}
๐ Example COVERAGE record
{"recordType": "COVERAGE","queryKey": "location:austin-tx","query": "Austin, TX","searchUrl": "https://www.zillow.com/austin-tx/","rawRows": 41,"uniqueZpids": 41,"duplicatesRemoved": 0,"reportedMatches": null,"pagesScanned": 1,"partitionsScanned": 1,"requestsSucceeded": 2,"requestsFailed": 0,"detailRequested": 0,"detailSucceeded": 0,"detailSuccessRate": null,"capHit": true,"blockedRequests": 0,"coverageStatus": "CAPPED","coverageReasons": ["USER_TOTAL_LIMIT_REACHED"],"checkedAt": "2026-09-11T00:00:00.000Z"}
A CAPPED scan is not treated as secretly complete.
๐ Example CHANGE_EVENT record
{"recordType": "CHANGE_EVENT","zpid": "123456789","changeType": "STATUS_CHANGED","changedFields": ["status"],"previousValues": {"status": "FOR_SALE"},"currentValues": {"status": "PENDING"},"detectedAt": "2026-09-11T00:00:00.000Z","previousObservedAt": "2026-09-10T00:00:00.000Z","currentObservedAt": "2026-09-11T00:00:00.000Z","priceChange": null,"priceChangePercent": null,"observationConfidence": "HIGH","evidence": {"searchSucceeded": true,"detailSucceeded": true,"coverageStatus": "COMPLETE"},"reasonCodes": []}
โ Example ERROR record
Errors are explicit Dataset records rather than silent empty results.
Example:
{"recordType": "ERROR","errorCode": "PARTIAL_COVERAGE","message": "Discovery scope could not be proven complete.","queryKey": "location:austin-tx","sourceUrl": "https://www.zillow.com/austin-tx/","retryable": true,"createdAt": "2026-09-11T00:00:00.000Z"}
Supported diagnostic codes include:
INVALID_INPUTREQUEST_FAILEDBLOCKEDPARSE_FAILEDDETAIL_FAILEDSEARCH_CAPPEDPARTIAL_COVERAGEDATA_CONFLICT
๐ Dataset views
The Dataset schema includes dedicated views for different workflows.
๐ Listing ledger overview
Focuses on:
record typeZPIDaddressstatuspricechange typedata statuscoverage statusconfidencesourcetimestamps
๐ Monitoring evidence
Focuses on:
change eventsprevious/current valuesprice deltasfirst/last seenprice-cut totalspending/reactivation countslifecycle stage
๐ก Coverage & quality
Focuses on:
coverage statuscoverage reasonsraw rowsunique ZPIDsduplicatesrequest success/failureblocksdetail successconflictserrors
โก Performance
The Actor uses browser-backed Zillow requests designed for current public Zillow page structures.
Performance depends on:
Number of search targetsResult limitsDetail strategyMaximum detail fetchesProxy configurationZillow response timeConcurrencyRetry settings
For lower cost and faster recurring monitors, consider:
detailStrategy: new_or_changed_only
instead of fetching full details for every unchanged property on every run.
๐ก Reliability
Zillow Scraper is designed to make failure states visible.
If one discovery scope fails while others succeed, successful data can still remain available with explicit coverage diagnostics for the affected scope.
The Actor distinguishes conditions such as:
COMPLETEPARTIALBLOCKEDCAPPEDUNKNOWN
instead of collapsing every condition into a successful empty Dataset.
This is especially important when the output is consumed automatically.
๐ API & integrations
Zillow Scraper can be used programmatically through the Apify API.
You can connect Dataset results to workflows such as:
- Google Sheets
- Make
- Zapier
- CRMs
- Internal APIs
- Data warehouses
- Property-analysis pipelines
- Lead and acquisition systems
- AI agents
- MCP workflows
Every run stores structured output in the default Dataset, making the results easy to consume from another application.
๐ก Example use cases
๐ Property listing research
Search one or more markets and collect:
ZPIDAddressStatusPriceBedsBathsSquare feetProperty typeCoordinatesSource query
Use the results for property analysis, market research, or internal data pipelines.
๐ Price-change monitoring
Schedule the Actor with:
monitorMode: truemonitorId: your-stable-monitor-id
to identify:
New listingsPrice cutsPrice increasesStatus changesBack-on-market events
without manually comparing Zillow pages.
๐ Data-quality monitoring
Use COVERAGE records to determine:
Was the search complete?Was the run capped?Were requests blocked?How many unique ZPIDs were found?How many detail requests succeeded?
This is useful before feeding Zillow data into automated decisions.
๐งญ Multi-query reconciliation
Run overlapping searches such as:
Austin, TX78747South Austin, TX
and use ZPID reconciliation plus matched-query provenance to see which properties overlap across scopes.
โ๏ธ CRM and automation triggers
With:
emitOnlyChanges: true
monitor runs can focus on machine-readable change events suitable for downstream alerts and workflows.
โ ๏ธ Current limitations
The current version focuses on public Zillow listing discovery, reconciliation, coverage diagnostics, and monitoring.
Important limitations:
Zillow may expose fewer results than requestedSome public fields may be nullSearch completeness depends on Zillow response behavior and configured limitsInteractive challenges can still block a requestA blocked or partial scan is not automatically treated as a confirmed removalV1 normally uses one partition per input searchLifecycle state does not create a separate historical Dataset for every prior observation
The Actor does not:
Log into private Zillow accountsScrape private/account-only property dataBypass interactive CAPTCHA or human-verification challengesInvent missing fieldsPretend incomplete scans are complete
โ FAQ
How does Zillow Scraper work?
The Actor accepts locations, search URLs, property URLs, or ZPIDs.
It then:
Builds discovery targetsFetches public Zillow pagesParses Zillow search/property dataNormalizes property observationsReconciles by ZPIDPreserves matched-query provenanceOptionally enriches property detailsCalculates coverage diagnosticsCompares persistent monitor state when enabledEmits Dataset records
Can I scrape multiple locations in one run?
Yes.
Add multiple values to:
locations
Each location is treated as its own discovery scope.
Can I provide Zillow search URLs directly?
Yes.
Use:
searchUrls
This is useful when you already have a specific Zillow search page you want to process.
Can I scrape one property directly?
Yes.
Use either:
propertyUrls
or:
zpids
Direct targets receive their own coverage evidence.
Why is the canonical URL sometimes shorter than the original Zillow URL?
The Actor reconciles property identity around the ZPID.
A normalized canonical URL can therefore look like:
https://www.zillow.com/homedetails/123456789_zpid/
while sourceUrl preserves the actual page used as evidence.
Why are some fields null?
Zillow does not expose every field consistently for every property or response type.
The Actor deliberately uses:
null
when a value is unavailable instead of fabricating data.
What does CAPPED mean?
CAPPED means the configured item limit was reached before the Actor could prove that the discovery scope was fully exhausted.
Example:
Zillow exposed 41 unique ZPIDsmaxTotalItems was 25
The Actor can return 25 records while clearly reporting:
coverageStatus: CAPPED
This is intentional.
What does PARTIAL mean?
PARTIAL means the Actor obtained some evidence but could not prove complete coverage.
Possible causes can include:
Request failureParse failureIncomplete detail enrichmentOther incomplete discovery evidence
Check:
coverageReasons
for the exact reason.
What happens if Zillow blocks a request?
The Actor records the block explicitly.
Depending on the affected scope, you may see:
blockedRequests > 0coverageStatus: BLOCKEDerrorCode: BLOCKED
The Actor does not silently convert a blocked page into zero listings.
How does monitoring avoid false removals?
The Actor checks coverage evidence before treating a missing property as confirmed absent.
Reliable coverage can produce:
NOT_SEEN_CONFIRMED
Incomplete coverage can produce:
NOT_SEEN_PARTIAL_SCAN
This prevents a blocked, capped, or failed scan from automatically becoming a fake removal event.
What should I use as monitorId?
Use a stable name that identifies the monitoring job.
Examples:
austin-homes-watchphoenix-rentals-monitorclient-42-acquisition-list
Reuse the same ID on future runs to continue the same monitor history.
Can I output only changes?
Yes.
Use:
emitOnlyChanges: true
This is useful for recurring automations where unchanged CURRENT rows are not needed.
Can I export the results?
Yes.
Apify Dataset results can be exported in supported formats such as:
JSONCSVExcelXMLHTML
Can I use the Actor through an API?
Yes.
Every Actor run can be started through the Apify API, and Dataset results can be retrieved programmatically.
This makes Zillow Scraper suitable for ETL, CRM, monitoring, and automation pipelines.
๐งญ Recommended workflow
For normal one-time property discovery:
1. Add locations or Zillow search URLs2. Set your item limits3. Choose listing filters4. Enable coverage diagnostics5. Use selective detail enrichment when needed6. Run the Actor7. Review CURRENT and COVERAGE records
For recurring monitoring:
1. Create a stable monitorId2. Keep the same discovery inputs across runs3. Enable monitorMode4. Keep coverage diagnostics enabled5. Use new_or_changed_only detail strategy6. Schedule recurring Actor runs7. Route CHANGE_EVENT records to alerts or automation
For stronger trust:
Do not rely only on listing rows+Check COVERAGE records+Review DATA_CONFLICT events+Treat CAPPED/PARTIAL/BLOCKED scopes differently from COMPLETE scopes
๐ฌ Feedback & support
Found a bug or have a feature request?
Use the Actor's Issues tab on Apify.
Useful future additions may include:
More advanced partitioning for very large marketsAdditional lifecycle analyticsMore selective enrichment strategiesDedicated historical event storageAdditional Zillow public fieldsMore market-level monitoring summaries
๐ Zillow listing data you can audit
Enter locations, Zillow URLs, or ZPIDs, run the Actor, and receive structured Zillow property data with ZPID reconciliation, listing-change events, lifecycle tracking, provenance, and coverage evidence ready for research, APIs, CRM workflows, ETL, and automation.
