# Aerial Imagery API - Coverage, AI Roof and Property Data (`nabeelbaghoor/aerial-imagery-ai-data-api`) Actor

Find every aerial capture over a location with its date and resolution, then read what the provider's AI found in it: roofs with material, pitch and condition, buildings with heights, solar panels, pools, trees and surfaces, each with its area and confidence, plus one-row aggregate rollups.

- **URL**: https://apify.com/nabeelbaghoor/aerial-imagery-ai-data-api.md
- **Developed by:** [Nabeel Hassan](https://apify.com/nabeelbaghoor) (community)
- **Categories:** Real estate, Business, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 aerial capture returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Aerial Imagery API - Coverage, AI Roof and Property Data

Find every aerial capture over a location, with its date and its resolution, then read what the provider's computer vision models found in it: roofs with their material, pitch and condition, buildings with their heights, solar panels, pools, trees, driveways and surfaces - each with its own measured area and model confidence.

### What this actor does

- **Imagery coverage, free to ask about.** Every survey over a point or a polygon with its capture date, the time of the first and last photo in the flight, the ground sample distance in metres per pixel, the timezone, and which resource classes it holds. This is how you find out whether the imagery you need exists before you spend anything on reading it.
- **Post-catastrophe flights, identified.** Captures carry tags, and a disaster tag is what separates imagery of a neighbourhood from imagery of a neighbourhood after the hurricane. Filter on them, or read them off the row.
- **Detected features with real measurements.** One row per roof, building, pool, solar panel, tree, driveway or other surface the models found, with its class, its confidence, and its area in square metres and square feet.
- **Three areas, because one is not enough.** Every feature carries its whole area, its area clipped to the area of interest you asked about, and an explicitly unclipped area. A roof that straddles a parcel boundary has different numbers for each, and which one is correct depends entirely on the question you are asking.
- **The material mix, not just the dominant material.** Turn on attribute rows and a roof's material attribute breaks into every material found on it, each with its area, its share of the roof and its confidence, with one marked dominant. Roof pitch in degrees and building height in metres and feet come through the same route.
- **Aggregated rollups when you want one row per property.** The same underlying analysis, already reduced to one value per measure - total solar panel area, roof condition, tree overhang - keyed by a stable identifier with a readable description.
- **Find out what your account can ask for.** The class and pack catalogues list exactly which feature classes and packs this credential holds. Running that first turns a later refusal into a decision made in advance.
- **Credits recorded on the rows they bought.** AI requests spend export credits. Every AI row carries the credits its request cost, and the run logs the total, so a month's spend is auditable from the data rather than only from an invoice.
- **Pay per result.** You are charged for rows carrying a real record. Locations with no coverage and areas where nothing was detected are free.

### Bring your own key

This actor calls the provider with **your own account key**, created in your account rather than through an API call. Paste it into the API key field, or set it as the `DATA_API_KEY` secret. Nothing runs on anyone else's credentials, and a run without a key ends cleanly with an explanation rather than failing.

One detail worth knowing: the key travels in an `Authorization` header whose scheme word is spelled **`Apikey`** - capital A, everything else lowercase - and the provider states that the case is significant. A key sent as `ApiKey` or `Bearer` is simply not seen, which looks exactly like a wrong key. This actor gets that right, and strips a pasted scheme word if you copy the whole header line.

### Preview is the default, so a check never costs you credits

The transactional endpoint has two modes that differ by one parameter. In **preview** it tells you what content is available for an address and costs nothing. Without preview it does the same thing, charges credits and returns a transaction token that unlocks the content.

Quietly spending somebody else's balance is not a reasonable default, so this actor previews unless you explicitly switch on *Spend credits on transactions*. Every row records which kind it was and what it cost.

### A null rollup is not a zero

The provider is explicit about this: when a feature is not detected, its rollup value comes back **null**, and the confidence beside it comes back null too.

Coercing that to 0 would turn "no solar panel was found here" into "there are zero square metres of solar panel". Those sum and average identically and mean completely different things - one is an observation, the other is a non-observation. So nulls are preserved and flagged with a `rollupNotDetected` column, and the numeric value sits in its own column so an average only ever runs over real measurements.

### Partial resources, and when absent means absent

Some AI survey resources only carry predictions over part of their area. Inside such a resource, a missing roof can mean the roof is not there, or that nothing looked. The actor warns in the log when a response is flagged partial and puts the flag on every row, and there is an input to exclude partial resources entirely when absent has to mean absent.

### Example output

```json
{
  "recordType": "feature",
  "requested": "-33.7251728,151.2955012",
  "found": true,
  "featureId": "a1b2c3d4-0001",
  "classId": "0f4a1b2c-roof",
  "classDescription": "Roof",
  "confidence": 0.97,
  "areaSqm": 170.9,
  "areaSqft": 1840,
  "clippedAreaSqm": 164.2,
  "clippedAreaSqft": 1768,
  "unclippedAreaSqm": 170.9,
  "unclippedAreaSqft": 1840,
  "belongsToParcel": true,
  "roofSpotlightIndex": 78,
  "roofSpotlightConfidence": 0.91,
  "attributeCount": 4,
  "surveyId": "88d9f2a0-2026-0421",
  "surveyDate": "2026-04-21",
  "systemVersion": "gen6-3",
  "creditsUsed": 1,
  "mapBrowserLink": "https://apps.example-provider.com/maps/#/@-33.7251728,151.2955012,20.00z,0d/V/20260421",
  "partialResource": false
}
```

### FAQ

#### What does this aerial imagery API return?

Two things. Coverage: every aerial survey over a location, with its capture date, ground sample distance in metres per pixel, flight times, timezone and tags. And AI content derived from those surveys: individual detected features such as roofs, buildings, solar panels, pools, trees and surfaces with measured areas and model confidences, the attributes and material components beneath them, and aggregated rollups that reduce all of it to one value per measure.

#### How do I check whether imagery exists before paying for it?

Run coverage mode over the point or polygon. It lists every capture with its date and resolution and costs nothing. For transactional content, run transaction mode with the default preview setting, which returns the same availability answer without charging a credit or issuing a token. Only turning on *Spend credits on transactions* actually bills your balance.

#### What roof data can I get?

Roof features with their measured area in square metres and square feet, and through attribute rows the material breakdown - every material found on the roof with its area, its share and its confidence, one of them marked dominant. Where three dimensional coverage exists, roof pitch in degrees and building height in metres and feet. The roof spotlight index is available as supplementary data on feature rows.

#### What is the difference between features and rollups?

Features give you one row per detected object with its own geometry and confidence, which is what you want when you need to know how many, how big, and where. Rollups give you the same analysis already aggregated into one value per measure for the whole area, which is what you want when you need one row per property for a model or a spreadsheet. Rollups cost the same request; they are a different shape of answer, not a cheaper one.

#### Why do features have three different areas?

Because an area of interest cuts through real objects. A roof that straddles a parcel boundary has a true total area and a smaller area inside the parcel you asked about. The clipped area answers "how much of this is on the property", the unclipped area answers "how big is this thing", and blending them silently would make either question unanswerable. Both are returned, in both units.

#### How is a not-detected feature reported?

As null, flagged. The provider returns a null rollup value when the feature was never detected, and this actor preserves that null and sets a `rollupNotDetected` column rather than writing a zero. The numeric value gets its own column so that averaging over it never quietly mixes real zeros with non-observations.

#### Which countries are covered?

Coverage follows the provider's own imagery library, which is strongest across the United States, Australia, New Zealand and Canada. The AI geocoder supports US and Australian addresses specifically; elsewhere, supply a point or a polygon rather than an address. Coverage mode answers the question directly for any location.

#### Do AI requests cost credits?

Yes. AI feature and rollup requests spend export credits from your account. Each response reports how many it used, this actor writes that number onto every row the request produced, and logs the run total at the end. Coverage requests and the class and pack catalogues do not spend export credits.

### Keyword map

aerial imagery API, aerial photo API, property imagery API, AI property data API, roof data API, roof material detection API, roof pitch API, building height API, solar panel detection API, pool detection API, tree overhang data, geospatial AI API, imagery coverage API, ground sample distance, orthoimagery API, post catastrophe imagery, insurance property inspection data, property condition AI, parcel level feature extraction, GIS aerial data, remote sensing API, building footprint API, surface area measurement API, rooftop solar assessment data, catastrophe response imagery

# Actor input Schema

## `mode` (type: `string`):

Coverage lists the aerial captures over a location with their dates and resolution. Transaction checks what content is available for an address, free in preview. AI features returns each detected feature with its area and confidence. AI rollups returns the same information already aggregated into one value per measure. AI coverage says which AI resources exist over a location. Class and pack catalogues say what this account may ask for.

## `points` (type: `array`):

One "latitude,longitude" pair per line, in that order. The provider's own paths take longitude first and a swapped pair returns a real location somewhere else in the world rather than an error, so the order is fixed for you here.

## `polygons` (type: `array`):

One area of interest per line, as a comma separated list of longitude and latitude values where the first and last point are the same. Used by the coverage and AI modes.

## `addresses` (type: `array`):

One full street address per line, written as "street, city, state, zip". The AI endpoints geocode from separate street, city, state and ZIP parameters rather than from one string, so the line is split for you; a line that cannot be split is reported rather than sent as a street that will not match.

## `since` (type: `string`):

Only consider captures on or after this date, as YYYY-MM-DD. The coverage endpoints also accept a relative form such as 5M for five months ago.

## `until` (type: `string`):

Only consider captures on or before this date, as YYYY-MM-DD, or a relative form such as 1Y.

## `order` (type: `string`):

When several surveys match the date range, which one the AI endpoints read from. Latest is usually what you want; earliest is how you look at a property before a known event.

## `resourceTypes` (type: `string`):

Comma separated resource types to consider, written as class or class:type. For example photos,tiles:Vert,tiles:North for coverage, or raster:Vert for a transactional request. Leave empty on coverage for everything the account can see.

## `surveyLimit` (type: `integer`):

How many survey records the provider returns per location. Transactional requests cap this at 1000.

## `sortBy` (type: `string`):

Which field to order surveys by, with a leading minus for descending. For example -captureDate for newest first. Defaults to capture date descending.

## `overlap` (type: `string`):

Whether to include imagery that only partly covers the requested area. Full returns only imagery covering the whole of it, which is what you want when a partial image would be useless.

## `includeTags` (type: `string`):

Comma separated tag queries a capture must match at least one of, written as type:name. For example disaster:flood,disaster:hurricane to find post-catastrophe flights.

## `excludeTags` (type: `string`):

Comma separated tag queries that exclude a capture, written as type:name.

## `dates` (type: `string`):

Whether a transactional request covers every available date or a single one per resource type. Single is the cheaper question.

## `spendCredits` (type: `boolean`):

Off by default, which sends the request in preview: the same coverage comes back free and without a transaction token. Turn this on only when you actually want the token that unlocks the content, because that is the call that charges your balance. Every row records what it cost.

## `resourceFilter` (type: `string`):

Whether a transactional request matches surveys carrying all of the listed resource types or at least one of them. Accepts allTypes or anyTypes.

## `packs` (type: `string`):

Comma separated AI pack names to request, for example building,roof\_char,surfaces. Leave empty for everything the account holds. Run the pack catalogue mode to see what that is.

## `classes` (type: `string`):

Comma separated feature class IDs to keep, filtering out everything else. Run the class catalogue mode to see which IDs this account may request.

## `includeSupplementary` (type: `string`):

Comma separated supplementary datasets to add to the response, for example roofSpotlightIndex. These are add-ons on top of the base features rather than part of them.

## `includeAttributes` (type: `boolean`):

Emit a row for each attribute on each feature, and for each component inside it. A roof's material attribute breaks into the area, ratio and confidence of every material found on it, with one marked dominant. Collapsing that onto the feature row keeps the dominant material and loses the mix.

## `parcelMode` (type: `boolean`):

Treat the requested area as a parcel boundary, which makes the provider mark which features belong to the parcel and return their clipped geometry. Useful when a roof crosses the boundary.

## `bulk` (type: `boolean`):

Tell the provider this request belongs to a large batch, which exempts it from interactive rate limiting. It does not change the answer or the page size, only how the request is throttled.

## `includeAlphaClasses` (type: `boolean`):

Include feature classes the provider marks as alpha. These are experimental and their definitions can change.

## `includeBetaClasses` (type: `boolean`):

Include feature classes the provider marks as beta.

## `use3dCoverage` (type: `boolean`):

Pick the survey resource using the 3D attribute coverage boundary rather than the ordinary one. Relevant when you need roof pitch or building height, which only exist where 3D coverage does.

## `excludePartialResources` (type: `boolean`):

Skip survey resources that only have predictions over part of their area. Worth switching on when an absent feature has to mean absent rather than not analysed.

## `postCatastrophe` (type: `string`):

Whether to use only imagery flown after a catastrophe, only imagery flown before one, or either. Choosing deliberately matters when you are comparing a property to its pre-event state.

## `systemVersion` (type: `string`):

Pin the request to one AI system version, so results stay comparable across runs as the models change.

## `systemVersionPrefix` (type: `string`):

Pin the request to a family of AI system versions by prefix rather than to one exact version.

## `country` (type: `string`):

Two letter country code for geocoded requests. The AI geocoder supports US and AU.

## `reference` (type: `string`):

An opaque string echoed back on every AI response, for example a policy or job number. Useful for tying rows back to whatever prompted the lookup.

## `apiKey` (type: `string`):

Your own account key, created in your account rather than through an API call. Sent in an Authorization header whose scheme is spelled "Apikey" with a capital A and nothing else capitalised, which the provider treats as case significant. Stored encrypted and never written into the dataset. Can also be supplied as the DATA\_API\_KEY environment secret.

## `maxResults` (type: `integer`):

Stop after this many rows. Counts every row: surveys, features, attributes, rollups and catalogue entries alike.

## `requestsPerMinute` (type: `integer`):

How fast to call the provider. Lower this if your plan's rate limit is being hit, or switch on bulk mode for a large batch.

## `baseUrl` (type: `string`):

Overrides the host the API is called on. Leave empty unless the provider has given you a different one.

## Actor input object example

```json
{
  "mode": "coverage",
  "order": "",
  "overlap": "",
  "dates": "single",
  "spendCredits": false,
  "includeAttributes": false,
  "parcelMode": false,
  "bulk": false,
  "includeAlphaClasses": false,
  "includeBetaClasses": false,
  "use3dCoverage": false,
  "excludePartialResources": false,
  "postCatastrophe": "",
  "country": "",
  "maxResults": 100,
  "requestsPerMinute": 60
}
```

# Actor output Schema

## `records` (type: `string`):

One row per record, alongside the point, polygon or address that produced it.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("nabeelbaghoor/aerial-imagery-ai-data-api").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("nabeelbaghoor/aerial-imagery-ai-data-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call nabeelbaghoor/aerial-imagery-ai-data-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nabeelbaghoor/aerial-imagery-ai-data-api"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/c140aZ0v3ZVoWxmyG/builds/Sbs2bSerMHO1sSDsu/openapi.json
