Skip to main content
GET
https://avert.ldeo.columbia.edu
/
api
/
imagery
/
q
Query Imagery
curl --request GET \
  --url https://avert.ldeo.columbia.edu/api/imagery/q
{
  "results": [
    {
      "image_id": "311240.CLNE.2025.329_120000-0000",
      "image_url": "https://avert-legacy.ldeo.columbia.edu/archive/imagery/infrared/311240/2025/CLNE/still/329/311240.CLNE.2025.329_120000-0000.jpg",
      "vnum": 311240,
      "site": "CLNE",
      "frame": 0,
      "file_format": "jpg",
      "timestamp": "2025-11-25T12:00:00Z",
      "image_type": "infrared",
      "created_at": "2025-11-25T12:05:00Z",
      "updated_at": "2025-11-25T12:05:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 100,
    "total_count": 1500,
    "total_pages": 15,
    "has_prev": false,
    "has_next": true,
    "prev_page": null,
    "next_page": 2,
    "count": 100
  },
  "query": {
    "imageType": "infrared",
    "site": "CLNE",
    "vnum": 311240,
    "datefrom": null,
    "dateto": null,
    "has_fog": null,
    "is_night": null,
    "has_clouds": null,
    "freq": "all",
    "order": "desc"
  }
}

Overview

The unified imagery query endpoint provides access to both infrared and visible images from AVERT volcano monitoring cameras. Query and download images with flexible filtering options including site, date range, atmospheric conditions, and temporal sampling.
All parameters are optional. Without parameters, the API returns the 100 most recent infrared images.

Parameters

Image Type

imageType
string
default:"infrared"
Type of imagery to queryOptions:
  • infrared - Thermal/infrared imagery (default)
  • visible - Standard visible light imagery
# Infrared images (default)
?imageType=infrared

# Visible images
?imageType=visible

Pagination

limit
integer
default:"100"
Number of results per pageRange: 1-200
Default: 100
# Get 20 results
?limit=20

# Get maximum 200 results
?limit=200
page
integer
default:"1"
Page number for paginationMinimum: 1
Default: 1
# First page
?page=1

# Second page
?page=2

Location Filters

You can find available site names and vnum codes here.
site
string
Camera site codeCommon sites:
  • CLNE - Cleveland volcano
  • VPMI - Poás volcano
# Images from Cleveland
?site=CLNE

# Images from Poás
?site=VPMI
vnum
integer
Volcano ID numberCommon volcano IDs:
  • 311240 - Cleveland
  • 345040 - Poás
  • 383010 - Cumbre Vieja
  • 311290 - Okmok
# Cleveland volcano
?vnum=311240

# Poás volcano
?vnum=345040

Date Range Filters

datefrom
string
Start date/time for query rangeFormat: yyyymmddhhmmss
Timezone: Coordinated Universal Time (UTC) Example: 20250321110000 = March 21, 2025 at 11:00:00 AM UTC
# Images after January 1, 2025
?datefrom=20250101000000

# Specific date and time
?datefrom=20250321110000
dateto
string
End date/time for query rangeFormat: yyyymmddhhmmss
Timezone: Coordinated Universal Time (UTC)
Time Handling:
  • freq=all with single site: Time portion ignored, dates interpreted as local dates
  • freq=daily: Time portion ignored, dates interpreted as local dates
  • freq=hourly/minutely: Time portion creates daily recurring UTC time window
  • freq=all without site: Time portion used, dates interpreted as exact UTC range
# Images before December 31, 2025
?dateto=20251231235959

# Complete date range (November 2025)
?datefrom=20251101000000&dateto=20251130235959

# Hourly window: 12PM-2PM UTC each day (Dec 1-5)
?site=VPMI&freq=hourly&datefrom=20251201120000&dateto=20251205140000

Condition Filters

has_fog
boolean
Filter by fog presenceOptions:
  • true - Images with fog
  • false - Clear images (no fog)
# Clear images only
?has_fog=false
is_night
boolean
Filter by time of dayOptions:
  • true - Nighttime images
  • false - Daytime images
# Daytime only
?is_night=false

# Nighttime only
?is_night=true
has_clouds
boolean
Filter by cloud presenceOptions:
  • true - Images with clouds
  • false - Clear images (no clouds)
# No clouds
?has_clouds=false

# Clear conditions (no fog or clouds)
?has_fog=false&has_clouds=false

Temporal Sampling

freq
string
default:"all"
Frequency/sampling filter for time-lapse and data reductionOptions:
  • all - Return all captured images (default, ~1-2 min intervals)
    • Single site: Returns all images for full local days, timestamps in local time (no Z)
    • No site/multi-site: Returns images in exact UTC time range, timestamps in UTC (with Z)
  • minutely - Middle image from each minute within daily UTC time window (requires site)
  • hourly - Middle image from each hour within daily UTC time window (requires site)
  • daily - Image closest to 10:00 AM local time for each day (requires site)
How it works:AVERT cameras capture images approximately every 1-2 minutes (irregular intervals). The freq parameter groups images by time period and returns a representative image from each period.
freq valueData ReductionTimestamp FormatRequires Site?
all (single site)None (100% of images)Local time (no Z)No
all (no site)NoneUTC (with Z)No
minutely~0-5%UTC (with Z)Yes
hourly~98% (60x smaller)UTC (with Z)Yes
daily~99.9% (1440x smaller)UTC (with Z)Yes
Time Handling:
  • freq=all with single site: Time portion ignored, returns full local days
  • freq=daily: Time portion ignored, returns one image per local day at 10 AM
  • freq=hourly/minutely: Time portion creates daily recurring UTC time window
# All images (default)
?freq=all

# One image per hour (requires site)
?site=VPMI&freq=hourly

# Daily summaries (requires site)
?site=CLNE&freq=daily&datefrom=20250101000000&dateto=20251231235959

# Hourly window: 12PM-2PM UTC each day
?site=VPMI&freq=hourly&datefrom=20251201120000&dateto=20251205140000
Use freq=hourly or freq=daily when downloading large date ranges to dramatically reduce dataset size while maintaining temporal coverage. Note that freq=daily, hourly, and minutely require a site parameter.
order
string
default:"desc"
Sort order of results by timestampOptions:
  • desc - Newest images first (default)
  • asc - Oldest images first
Timezone-aware ordering:
  • freq=all with single site: Sorts by local site time
  • All other queries: Sorts by UTC time
# Default: newest first
?order=desc

# Oldest first (useful for time-lapse)
?order=asc

# Combined with other parameters
?site=VPMI&freq=hourly&order=asc
For freq=hourly and freq=minutely, the same images are returned regardless of order - only the display order changes.

Download Options

download
string
Download mode for retrieving imagesOptions:
  • estimate - Get download estimate (size, time, warnings) WITHOUT downloading
  • true - Download all matching images as ZIP file
  • selected - Download specific images by ID (requires image_ids)
Frontend workflow (recommended):
1

Get estimate

?site=VPMI&datefrom=20251201000000&dateto=20251201235959&download=estimate
Returns JSON with:
{
  "total_images": 24,
  "estimated_size_mb": 4.1,
  "estimated_time_seconds": 5,
  "warning": null,
  "suggestion": null
}
2

Show confirmation

Display estimate to user and get confirmation before downloading
3

Trigger download

?site=VPMI&datefrom=20251201000000&dateto=20251201235959&download=true
Returns ZIP file with all 24 images
API testing:
# Test with small batch
?limit=10&download=true
image_ids
string
Comma-separated image IDs for selective downloadRequired when: download=selected
Format: Comma-separated list of image IDs
# Download specific images
?download=selected&image_ids=311240.CLNE.2025.329_120000-0000,311240.CLNE.2025.329_130000-0000

Response Format

JSON Response (default)

{
  "results": [
    {
      "image_id": "311240.CLNE.2025.329_120000-0000",
      "image_url": "https://avert-legacy.ldeo.columbia.edu/archive/imagery/infrared/311240/2025/CLNE/still/329/311240.CLNE.2025.329_120000-0000.jpg",
      "vnum": 311240,
      "site": "CLNE",
      "frame": 0,
      "file_format": "jpg",
      "timestamp": "2025-11-25T12:00:00Z",
      "image_type": "infrared",
      "created_at": "2025-11-25T12:05:00Z",
      "updated_at": "2025-11-25T12:05:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 100,
    "total_count": 1500,
    "total_pages": 15,
    "has_prev": false,
    "has_next": true,
    "prev_page": null,
    "next_page": 2,
    "count": 100
  },
  "query": {
    "imageType": "infrared",
    "site": "CLNE",
    "vnum": 311240,
    "datefrom": null,
    "dateto": null,
    "has_fog": null,
    "is_night": null,
    "has_clouds": null,
    "freq": "all",
    "order": "desc"
  }
}

Response Fields

results
array
required
Array of image objects matching your query
pagination
object
required
Pagination metadata for navigating results
query
object
required
Echo of your query parameters for debugging

Download Estimate Response

When using download=estimate:
{
  "total_images": 24,
  "estimated_size_mb": 4.1,
  "estimated_time_seconds": 5,
  "warning": null,
  "suggestion": null
}

ZIP Download Response

When using download=true or download=selected, returns a ZIP file containing JPG images. ZIP Structure:
avert_infrared_CLNE_20251126_120000.zip
└── avert_imagery/
    └── infrared/
        └── 311240/
            └── CLNE/
                ├── 311240.CLNE.2025.329_120000-0000.jpg
                ├── 311240.CLNE.2025.329_130000-0000.jpg
                └── 311240.CLNE.2025.329_140000-0000.jpg

Example Requests

Basic Queries

# 100 most recent infrared images
curl "https://avert.ldeo.columbia.edu/api/imagery/q"

Filter by Location

# Images from Cleveland site
curl "https://avert.ldeo.columbia.edu/api/imagery/q?site=CLNE&limit=50"

Filter by Date

# November 2025
curl "https://avert.ldeo.columbia.edu/api/imagery/q?\
datefrom=20251101000000&\
dateto=20251130235959&\
limit=100"

Filter by Conditions

# Clear daytime infrared images
curl "https://avert.ldeo.columbia.edu/api/imagery/q?\
imageType=infrared&\
is_night=false&\
has_fog=false&\
has_clouds=false&\
limit=50"

Temporal Sampling

# One image per hour from November
curl "https://avert.ldeo.columbia.edu/api/imagery/q?\
site=VPMI&\
freq=hourly&\
datefrom=20251101000000&\
dateto=20251130235959&\
limit=200"

Downloads

# Step 1: Get download estimate
curl "https://avert.ldeo.columbia.edu/api/imagery/q?\
site=VPMI&\
datefrom=20251201000000&\
dateto=20251201235959&\
download=estimate"

# Response shows: 1440 images, 239 MB, 24 seconds

Code Examples

JavaScript/TypeScript

// Query recent infrared images
const response = await fetch(
  'https://avert.ldeo.columbia.edu/api/imagery/q?imageType=infrared&limit=20'
);
const data = await response.json();

console.log(`Total results: ${data.results.length}`);
console.log(`Page ${data.pagination.page} of ${data.pagination.total_pages}`);

// Display images
data.results.forEach(img => {
  const imgElement = document.createElement('img');
  imgElement.src = img.image_url;
  imgElement.alt = img.image_id;
  document.body.appendChild(imgElement);
});

Python

import requests

# Query recent infrared images
response = requests.get(
    'https://avert.ldeo.columbia.edu/api/imagery/q',
    params={
        'imageType': 'infrared',
        'site': 'CLNE',
        'limit': 50
    }
)
data = response.json()

print(f"Total results: {len(data['results'])}")
print(f"Page {data['pagination']['page']} of {data['pagination']['total_pages']}")

for img in data['results']:
    print(f"{img['image_id']}: {img['image_url']}")

Handling Rate Limits

The API limits requests to 100 per minute per IP address. Implement retry logic to handle rate limit errors:
import requests
import time

def query_with_retry(url, params, max_retries=3):
    """Query with exponential backoff on rate limits"""
    for attempt in range(max_retries):
        response = requests.get(url, params=params)
        
        if response.status_code == 200:
            return response.json()
        elif response.status_code == 429:
            # Rate limited - wait and retry
            wait_time = 2 ** attempt  # Exponential backoff
            print(f"Rate limited. Waiting {wait_time} seconds...")
            time.sleep(wait_time)
        else:
            response.raise_for_status()
    
    raise Exception("Max retries exceeded")

# Usage
data = query_with_retry(
    'https://avert.ldeo.columbia.edu/api/imagery/q',
    params={'limit': 50, 'site': 'CLNE'}
)

Error Responses

{
  "error": "Invalid imageType. Must be 'infrared' or 'visible'"
}

Best Practices

Always call download=estimate before triggering large downloads to inform users about size and time requirements.
# Good: Get estimate first
estimate = get_download_estimate(filters)
if estimate['total_images'] > 1000:
    print(f"Warning: Large download ({estimate['estimated_size_mb']} MB)")
    
# Then download if confirmed
download_images(filters)
When querying long time periods, use freq=hourly or freq=daily to reduce dataset size while maintaining temporal coverage.
# Bad: Download 60,000+ images from November
?datefrom=20251101000000&dateto=20251130235959&download=true

# Good: Download ~720 hourly snapshots instead
?datefrom=20251101000000&dateto=20251130235959&freq=hourly&download=true
Don’t try to fetch all results at once. Use pagination to load results incrementally.
# Good: Paginated loading
def load_results(params):
    page = 1
    while True:
        data = fetch_page(params, page)
        yield data['results']
        
        if not data['pagination']['has_next']:
            break
        page += 1
Store frequently accessed data locally to reduce API calls and improve performance.
// Good: Cache results
const cache = new Map();

async function getCachedResults(cacheKey, params) {
  if (cache.has(cacheKey)) {
    return cache.get(cacheKey);
  }
  
  const data = await fetchResults(params);
  cache.set(cacheKey, data);
  return data;
}
Implement proper error handling and retry logic for rate limits and network errors.
# Good: Comprehensive error handling
try:
    data = query_with_retry(url, params)
except requests.HTTPError as e:
    if e.response.status_code == 429:
        log.warning("Rate limited - try again later")
    else:
        log.error(f"API error: {e}")
except requests.RequestException as e:
    log.error(f"Network error: {e}")

Need Help?