Solar Resource & PVWatts Yield Scorer — Batch Site Screening avatar

Solar Resource & PVWatts Yield Scorer — Batch Site Screening

Pricing

from $4.40 / 1,000 results

Go to Apify Store
Solar Resource & PVWatts Yield Scorer — Batch Site Screening

Solar Resource & PVWatts Yield Scorer — Batch Site Screening

Batch solar resource assessment via NREL PVWatts v8. Lat/lon list in; annual/monthly kWh yield, capacity factor, irradiance, and a solar-worthiness class out. The resource-quality layer for solar, storage, and data-center siting.

Pricing

from $4.40 / 1,000 results

Rating

0.0

(0)

Developer

Kyle Maloney

Kyle Maloney

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

8 days ago

Last modified

Share

Score a list of coordinates for solar potential in one call, using NREL PVWatts v8. Each site returns modelled annual AC production, specific yield, capacity factor, a full monthly production profile, the solar resource, the identity and distance of the weather station behind the number, and every assumption echoed back so the result is reproducible.

This is a modelled screening estimate, not a bankable energy yield assessment. PVWatts runs a typical-meteorological-year simulation on an assumed-unshaded array with a single generic loss percentage, using weather from the nearest NSRDB grid cell rather than the site itself. Use it to rank and shortlist. Commission a measured, shade-analysed P50/P90 assessment before financing, PPA pricing or construction.


What v1.1 fixed (2026-08-01)

The station distance was wrong by a factor of 1,609 on every successful row

NREL documents station_info.distance in metres. v1.0's code comment asserted miles and multiplied by 1609.34.

Verified live: Phoenix (33.45, −112.07) returns distance: 923, with the station at (33.45000076, −112.05999756). One hundredth of a degree of longitude at 33.45°N is ~929 m — so 923 is metres, and the station is essentially the site's own grid cell. v1.0 published station_distance_m: 1485421 — a station 1,485 km away. Seattle: distance: 756, published as 1,216,660.

station_distance_m now reports metres. This changes an existing field's value, and it is the one case where that is correct: the old number was wrong. A live drift assertion re-derives the true distance from the station coordinates every run and fails if the units ever flip.

The host list led with a dead host

developer.nrel.gov has no A recordnslookup returns the name with no address and curl fails in 8 ms. developer.nlr.gov (the api.data.gov alias, developer-nlr-gov.domains.api.data.gov) resolves and serves v8 in ~0.5 s. v1.0 listed the dead name first and burned three attempts with exponential backoff on it before every single site. The live host now leads; the other is retained as a fallback because DNS is not the same everywhere.

A 422 threw away the message that explains it

PVWatts answers an unusable location with HTTP 422 and a populated errors array: "No climate data found with dataset=nsrdb for location specified", plus a warnings array saying "try re-submitting with dataset=intl". v1.0 short-circuited on !res.ok, never read either array, retried the other host pointlessly, and surfaced a bare "HTTP 422". Both arrays are now read and emitted. v1.0 never read warnings at all.

Failures could not be told apart from bad sites

Every failure path now sets pvwatts_statusok, rate_limited, error, malformed, unavailable, invalid_input — and every metric on a non-ok row is null. A rate-limited or errored site is never a low yield. A fabricated "poor" silently disqualifies a good site, and the buyer has no way to know. A 200 with no ac_annual used to emit errors: null and all-null metrics, asserting nothing had gone wrong; it is now explicitly malformed.

An invalid key, and a total outage, still billed

A bad key returns HTTP 403 API_KEY_INVALID — v1.0 turned that into a billable blank row per site and reported SUCCESS. It is now a terminal, actionable failure. Rows are buffered and a billing gate runs before pushData: if not one site was scored, the run fails and emits nothing.

Data fetched and thrown away

v1.0 requested a response with 7 output arrays/values, 11 station fields, 8 echoed inputs and 3 envelope fields, and emitted 8 of them. Now emitted: dc_monthly, poa_monthly, station latitude/longitude/elevation/timezone/id/ country/resource-file, the weather data source and vintage, the PVWatts and SSC versions, and all eight echoed assumptions.

No field was removed or renamed, and the price is unchanged.

The live drift gate

Two real coordinates with known-magnitude answers, checked before any billable row exists. Any failure aborts with nothing emitted and nothing billed.

AssertionLive value 2026-08-01What it catches
Response envelope has inputs/errors/warnings/version/station_info/outputsall presentAn API contract change
Major version is 88.5.0A silent v9 swap (v9 currently 404s)
Phoenix yield inside 6,000–8,200 kWh/yr7,020.48A model or weather-set shift
Seattle yield inside 3,600–5,100 kWh/yr4,351.56The same, at the other end
Phoenix ÷ Seattle ≥ 1.351.613A model degraded to a constant or a clamp — passes both magnitude bands, fails here
station_info.distance matches the geometry to the station coordinates923 m vs 929 m computedThe metres/miles flip that v1.0 shipped

The gate costs two API calls. Against the shared, rate-limited DEMO_KEY that is a meaningful share of what an auto-QA run has, so the verdict is cached in a named key-value store for 3 hours and only the first run in each window pays for it. Rows from a cached verdict say so: drift_gate_status: "passed_cached". The drift this gate catches -- a host dying, a version bump, a units flip, a model shift -- moves on the order of days, not minutes.

If the shared DEMO_KEY is rate-limited when the canaries run, the gate is skipped rather than failed — rate limiting is a documented property of a shared key, not upstream drift — and every row says so via drift_gate_status: "skipped_rate_limited".


Who uses this

  • Solar developers and EPC site selectors — rank a candidate list before spending money on any of them; specific_yield_kwh_per_kwdc is the cross-site metric, and station_quality tells you which numbers to trust.
  • C&I energy managers and rooftop assessors — compare portfolio sites on a consistent tilt/azimuth/loss basis, all echoed on the row.
  • Storage and microgrid designersseasonality_ratio and winter_share_pct size the winter gap that drives storage and generator hours.
  • Real-estate and data-centre teams — a quick, cheap on-site-generation read.
  • AI agents — one call per site batch; see the MCP note below.

Example input

{
"assets": [
{ "lat": 33.45, "lon": -112.07, "label": "Phoenix AZ" },
{ "lat": 35.08, "lon": -106.65, "label": "Albuquerque NM" },
{ "lat": 39.74, "lon": -104.99, "label": "Denver CO" },
{ "lat": 47.61, "lon": -122.33, "label": "Seattle WA (control)" }
],
"apiKey": "DEMO_KEY",
"systemCapacityKw": 4,
"moduleType": 0,
"arrayType": 1,
"tilt": 20,
"azimuth": 180,
"losses": 14
}

Live result from that exact input (2026-08-01):

SiteAC kWh/yrCapacity factorClassSeasonalityWinter shareStation
Albuquerque NM7,116.1620.31%excellent1.6127.2%1,438 m
Phoenix AZ7,020.4820.04%excellent1.5427.3%923 m
Denver CO6,380.0318.21%good1.6626.1%1,405 m
Seattle WA4,351.5612.42%poor4.3415.3%756 m

Albuquerque narrowly beats Phoenix on annual yield — and Seattle's best month produces 4.34x its worst against Phoenix's 1.54x, with only 15.3% of the year's output falling in the four winter months. None of that seasonality was visible in v1.0.

Input fields

FieldTypeDefaultMeaning
assetsarray (required)[{ lat, lon, label }]. One PVWatts call per site, plus two drift canaries per run. Omitting it fails the run before anything is billed.
apiKeystring (secret)prefill DEMO_KEYYour free key from developer.nrel.gov/signup. DEMO_KEY is shared and rate-limited — fine for a handful of sites. An invalid key fails the run loudly and bills nothing.
systemCapacityKwinteger4Nameplate DC size. specific_yield_kwh_per_kwdc normalises across sizes.
moduleTypeinteger00 Standard, 1 Premium, 2 Thin film.
arrayTypeinteger10 Fixed Open Rack, 1 Fixed Roof, 2 1-Axis, 3 1-Axis Backtracking, 4 2-Axis.
tiltinteger20Degrees from horizontal.
azimuthinteger180Degrees from north (180 = due south).
lossesinteger14System-loss percentage; NREL's default is 14.

Output fields

Every field below is declared in the dataset schema and present on every row. null always means not obtained — never a low or zero yield.

Site and headline result

FieldTypeDescription
labelstringYour site label.
latnumberSite latitude.
lonnumberSite longitude.
ac_annual_kwhnumberModelled annual AC production.
dc_annual_kwhnumberModelled annual DC production.
kwh_per_kw_yearnumberAnnual AC output per kW DC installed.
specific_yield_kwh_per_kwdcnumberThe same figure under the industry's name — the standard cross-site comparison metric.
capacity_factor_pctnumberAnnual capacity factor.
solar_classstringexcellent ≥20%, good ≥17%, fair ≥14%, poor <14%, or unknown when no yield was modelled. unknown is never a low score.
solrad_annual_kwh_m2_daynumberAnnual average daily solar radiation.
poa_annual_kwh_m2numberAnnual irradiance on the tilted array surface.

Monthly profile and seasonality

FieldTypeDescription
monthly_ac_kwharrayTwelve monthly AC output values.
monthly_dc_kwharrayTwelve monthly DC output values.
monthly_solradarrayTwelve monthly solar-radiation values.
monthly_poa_kwh_m2arrayTwelve monthly plane-of-array irradiance values — what tilt and azimuth actually move.
best_monthobject{ name, ac_kwh } for the highest-production month.
worst_monthobject{ name, ac_kwh } for the lowest.
best_month_namestringBest month, flattened for CSV.
best_month_ac_kwhnumberBest-month AC output.
worst_month_namestringWorst month, flattened for CSV.
worst_month_ac_kwhnumberWorst-month AC output.
seasonality_rationumberBest month ÷ worst month. High means thin winter production.
winter_share_pctnumberShare of annual output across Nov–Feb.
dc_to_ac_efficiency_pctnumberAnnual AC as a percentage of annual DC.

Weather station — how much to trust the number

FieldTypeDescription
station_distance_mnumberDistance to the NSRDB grid cell / station, in metres. Corrected in v1.1 (see above).
station_distance_kmnumberThe same distance in kilometres.
station_qualitystringsite_grid_cell (≤5 km), near (≤25 km), regional (≤100 km), distant (>100 km).
station_latnumberStation latitude.
station_lonnumberStation longitude.
station_elevation_mnumberStation elevation — a large site/station elevation gap weakens the estimate in terrain.
station_timezone_utc_offsetnumberStation UTC offset, for aligning output with a local load profile or tariff.
station_idstringNSRDB station / grid-cell id. Two sites sharing an id share weather data.
station_resource_filestringFilename of the NSRDB record used — the most precise citation available.
station_statestringStation state as NREL reports it.
station_countrystringStation country.
station_citystringStructurally empty in PVWatts v8. NREL returns "" for NSRDB grid-cell stations at every location tested (Phoenix, Seattle, NYC, Honolulu, Anchorage, San Juan), so this is always null. Retained because removing a published field would break existing pipelines; use station_id, station_lat/station_lon and station_state instead.
weather_data_sourcestringThe NSRDB dataset and vintage, e.g. NSRDB PSM V3 GOES tmy-2020 3.2.0. This is the data-vintage field — if NREL moves to a newer TMY it changes here.

Assumptions echoed back (reproducibility)

FieldTypeDescription
system_capacity_kwnumberNameplate DC capacity simulated.
module_typeintegerPVWatts module_type code.
module_type_labelstringStandard / Premium / Thin film.
array_typeintegerPVWatts array_type code.
array_type_labelstringe.g. Fixed - Roof Mounted, 1-Axis Tracking.
tilt_degnumberTilt used.
azimuth_degnumberAzimuth used.
losses_pctnumberSystem-loss percentage used.

Status and provenance

FieldTypeDescription
pvwatts_statusstringok, rate_limited, error, malformed, unavailable, invalid_input. Anything but ok means every metric is null.
pvwatts_http_statusintegerHTTP status for this site.
errorsstringFailure text; null when the site scored cleanly.
pvwatts_warningsstringThe API's own warnings, e.g. "try re-submitting with dataset=intl".
drift_gate_statusstringpassed (canaries ran this run), passed_cached (a verdict from the last 3 hours was reused), or skipped_rate_limited (the canaries could not run, so the model is unverified for this run).
pvwatts_versionstringModel version, e.g. 8.5.0.
ssc_versionstringNREL SAM Simulation Core version.
host_usedstringWhich NREL host served the response.
source_urlstringPVWatts v8 API documentation.
disclaimerstringThe modelled-estimate disclaimer.
checked_atstringUTC timestamp of the run.

Legitimately empty on a healthy run: errors and pvwatts_warnings are null when nothing went wrong — good news, not dead columns. Both are pinned by offline fixtures. To see them populated live, score a location with no NSRDB coverage, e.g. {"assets":[{"lat":25,"lon":-160,"label":"Mid-Pacific"}]}errors: "No climate data found with dataset=nsrdb...",

pvwatts_warnings: "This location appears to be outside the US, try re-submitting with dataset=intl..."
, pvwatts_status: "error", every metric null.


Use as an MCP tool

Available to AI agents via mcp.apify.com. Hand it a list of coordinates and it returns one structured, comparable yield row per site. pvwatts_status, station_quality and drift_gate_status exist so an agent can distinguish "this site is poor" from "this site was not scored" and from "the model itself was not verified this run" — the distinctions that matter when an agent chains a siting decision.

Pricing

Pay per result — $8 per 1,000 rows. One row per scored site. Graduated paid-plan discounts apply automatically. A run that fails the drift gate, the key check or the billing gate emits zero rows and costs zero.

FAQ

Do I need my own key? No. DEMO_KEY is prefilled and works for small runs. It is shared across all anonymous users, so it rate-limits quickly under load; when that happens the affected sites are reported as pvwatts_status: "rate_limited" with every metric null, and if no site could be scored the run fails and bills nothing rather than emitting empty billable rows. A free key takes 30 seconds at developer.nrel.gov/signup and removes the limit.

Operator note: the Actor also reads a key from the NREL_API_KEY (or DATA_GOV_API_KEY) environment variable. An explicitly supplied apiKey always wins, but a blank key or the literal DEMO_KEY falls back to it -- so setting that one secret env var lifts the prefill and every saved task off the shared key without editing a single stored input. Env vars are read at BUILD time, so it needs a rebuild to take effect.

Why is Albuquerque above Phoenix? Elevation and lower average temperature. PV modules lose efficiency as they heat up, so a cooler high-desert site can out-produce a hotter one at similar irradiance. That is exactly the kind of result a coordinate-level model exists to surface.

Can I model tracking? Yes — arrayType 2, 3 or 4. The choice is echoed on every row as array_type_label.

Is this good enough to finance a project? No, and it does not claim to be. It is a screening model on typical-year data with an assumed-unshaded array. It is good enough to rank a hundred sites and pick the five worth surveying.

What if the site is outside the US? PVWatts defaults to the NSRDB dataset, which is US-focused. Outside coverage you get pvwatts_status: "error" with the API's own warning suggesting the international dataset — an honest failure rather than a fabricated zero.

  • HIFLD Grid Proximity Screener — distance to transmission, substations and the serving utility, balancing authority and ISO/RTO. The natural next question after "does this site have sun".
  • Interconnection Queue Tracker — what is already queued nearby, across 7 ISOs.
  • Sage-Grouse Siting Screener, Energy Corridor §368 Screener, EPA Nonattainment Air Permit Screener — the siting constraints on the same coordinate.
  • Site Due Diligence Bundle — 20 layers for one coordinate in one call.