<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: climintell</title>
    <description>The latest articles on DEV Community by climintell (@climintell_1c2dc8f2eec311).</description>
    <link>https://dev.to/climintell_1c2dc8f2eec311</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3692295%2F4f4ed371-185b-4ce8-abf5-017cdfcf5903.png</url>
      <title>DEV Community: climintell</title>
      <link>https://dev.to/climintell_1c2dc8f2eec311</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/climintell_1c2dc8f2eec311"/>
    <language>en</language>
    <item>
      <title>Building Volcano Monitoring Applications with Satellite-Based Degassing Data</title>
      <dc:creator>climintell</dc:creator>
      <pubDate>Sun, 04 Jan 2026 08:32:50 +0000</pubDate>
      <link>https://dev.to/climintell_1c2dc8f2eec311/building-volcano-monitoring-applications-with-satellite-based-degassing-data-1ook</link>
      <guid>https://dev.to/climintell_1c2dc8f2eec311/building-volcano-monitoring-applications-with-satellite-based-degassing-data-1ook</guid>
      <description>&lt;p&gt;When Hayli Gubbi volcano in Ethiopia erupted on November 23, 2025 after 12,000 years of dormancy, satellite SO₂ sensors detected precursor signals 5-6 days before the explosion. For developers building disaster monitoring applications, this raises an important question: how do you integrate real-time volcanic degassing data into your applications?&lt;/p&gt;

&lt;p&gt;This article walks through the architecture, data formats, and integration patterns for building volcano monitoring apps using satellite-based SO₂ data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problem Space&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Traditional volcano monitoring relies on ground-based seismic networks and gas sensors. This works well for well-studied volcanoes like Kilauea or Mount St. Helens, but fails for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Remote volcanoes&lt;/strong&gt; (Hayli Gubbi had zero ground infrastructure)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Understudied volcanoes&lt;/strong&gt; (no historical eruption data)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Developing regions&lt;/strong&gt; (limited resources for monitoring networks)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Global-scale monitoring&lt;/strong&gt; (thousands of active/dormant volcanoes worldwide)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Satellite-based monitoring fills this gap. The Copernicus Sentinel-5P satellite measures atmospheric SO₂ concentrations daily at 7×3.5 km spatial resolution, covering every volcano on Earth.&lt;/p&gt;

&lt;p&gt;The challenge for developers: raw satellite data requires significant processing before it's useful for applications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq1f51hldret6socvdthg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq1f51hldret6socvdthg.png" alt=" " width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why not use raw Sentinel-5P data directly?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data volume:&lt;/strong&gt; Daily global coverage = petabytes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Processing complexity:&lt;/strong&gt; Atmospheric corrections, cloud masking, quality filtering&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain expertise:&lt;/strong&gt; Interpreting mol/m² values requires volcanology knowledge&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure:&lt;/strong&gt; Requires geospatial data processing pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;APIs like VolcanoWatch handle the processing layer, returning actionable volcanic intelligence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API Request Pattern&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Basic Degassing Analysis&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /api/volcano/degassing-analysis
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY

{
  "volcano_name": "Hayli Gubbi (Erta Ale)",
  "country": "Ethiopia",
  "analysis_period_months": 6,
  "buffer_km": 10
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Parameters explained:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;volcano_name&lt;/code&gt;: Target volcano (use standardized names from Global Volcanism Program)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;country&lt;/code&gt;: Geographic filter (handles volcanoes with multiple names)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;analysis_period_months&lt;/code&gt;: Historical lookback window&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;buffer_km&lt;/code&gt;: Spatial radius around volcano coordinates (accounts for plume drift)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Response Structure&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "volcano": {
    "name": "Hayli Gubbi (Erta Ale)",
    "location": {
      "latitude": 13.33,
      "longitude": 40.72
    },
    "elevation_m": 500
  },
  "analysis": {
    "period": {
      "start_date": "2025-07-01",
      "end_date": "2026-01-01",
      "total_days": 184
    },
    "anomalies": {
      "total_count": 12,
      "high_alerts": 1,
      "moderate_alerts": 2,
      "weak_alerts": 9
    },
    "events": [
      {
        "date": "2025-11-23",
        "so2_column_density": 24.035,
        "alert_level": "HIGH",
        "confidence": "high",
        "interpretation": "Active eruption in progress"
      },
      {
        "date": "2025-11-18",
        "so2_column_density": 1.510,
        "alert_level": "WEAK",
        "confidence": "medium",
        "interpretation": "Precursor degassing detected"
      }
      // ... more events
    ]
  },
  "thresholds": {
    "weak": 0.0015,
    "moderate": 0.005,
    "high": 0.01,
    "units": "mol/m²"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Integration Patterns&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Real-Time Alert Systems&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use case:&lt;/strong&gt; Send notifications when volcanic unrest is detected&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import requests
from datetime import datetime, timedelta

def check_volcano_status(volcano_name):
    """
    Check for recent degassing anomalies
    Returns alert level if activity detected in last 48 hours
    """
    response = requests.post(
        'https://api.climintell.com/volcano/degassing-analysis',
        headers={'Authorization': f'Bearer {API_KEY}'},
        json={
            'volcano_name': volcano_name,
            'analysis_period_months': 1,  # Recent activity only
            'buffer_km': 10
        }
    )

    data = response.json()

    # Check for recent anomalies
    cutoff_date = datetime.now() - timedelta(days=2)
    recent_events = [
        event for event in data['analysis']['events']
        if datetime.fromisoformat(event['date']) &amp;gt; cutoff_date
    ]

    if not recent_events:
        return None

    # Return highest alert level detected
    alert_levels = {'HIGH': 3, 'MODERATE': 2, 'WEAK': 1}
    max_alert = max(recent_events, key=lambda x: alert_levels.get(x['alert_level'], 0))

    return {
        'volcano': volcano_name,
        'alert_level': max_alert['alert_level'],
        'so2_value': max_alert['so2_column_density'],
        'date': max_alert['date'],
        'interpretation': max_alert['interpretation']
    }

# Example usage
alert = check_volcano_status('Hayli Gubbi (Erta Ale)')
if alert and alert['alert_level'] in ['HIGH', 'MODERATE']:
    send_notification(alert)  # Your notification function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Precursor Detection Dashboard&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use case:&lt;/strong&gt; Visualize degassing trends to identify precursor signals&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Fetch historical data
async function getVolcanoDegassingTrend(volcanoName, months = 6) {
  const response = await fetch('https://api.climintell.com/volcano/degassing-analysis', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${API_KEY}`
    },
    body: JSON.stringify({
      volcano_name: volcanoName,
      analysis_period_months: months,
      buffer_km: 10
    })
  });

  const data = await response.json();

  // Transform for charting library (e.g., Chart.js, Recharts)
  return data.analysis.events.map(event =&amp;gt; ({
    date: new Date(event.date),
    so2: event.so2_column_density,
    alert: event.alert_level,
    label: event.interpretation
  }));
}

// Render timeline chart
async function renderDegassingChart(volcanoName) {
  const trendData = await getVolcanoDegassingTrend(volcanoName);

  // Color-code by alert level
  const colorMap = {
    'HIGH': '#dc2626',
    'MODERATE': '#ea580c',
    'WEAK': '#facc15',
    'NORMAL': '#22c55e'
  };

  // Chart.js example
  new Chart(ctx, {
    type: 'scatter',
    data: {
      datasets: [{
        label: 'SO₂ Emissions',
        data: trendData.map(d =&amp;gt; ({ x: d.date, y: d.so2 })),
        backgroundColor: trendData.map(d =&amp;gt; colorMap[d.alert])
      }]
    },
    options: {
      scales: {
        y: { 
          title: { text: 'SO₂ Column Density (mol/m²)' },
          type: 'logarithmic'  // Better for wide range of values
        }
      }
    }
  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Multi-Volcano Monitoring&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use case:&lt;/strong&gt; Aviation safety, regional monitoring&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def monitor_volcano_region(volcanoes_list, alert_threshold='MODERATE'):
    """
    Monitor multiple volcanoes in a region
    Returns list of volcanoes with alerts above threshold
    """
    active_volcanoes = []

    for volcano in volcanoes_list:
        status = check_volcano_status(volcano)

        if status and meets_threshold(status['alert_level'], alert_threshold):
            active_volcanoes.append(status)

    return active_volcanoes

# Example: Monitor Ethiopian Rift Valley volcanoes
ethiopian_volcanoes = [
    'Hayli Gubbi (Erta Ale)',
    'Erta Ale',
    'Dabbahu',
    'Manda Hararo',
    'Alu-Dalafilla'
]

alerts = monitor_volcano_region(ethiopian_volcanoes, alert_threshold='WEAK')

# Generate aviation advisory
if alerts:
    generate_vaac_style_report(alerts)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Data Interpretation Best Practices&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding SO₂ Thresholds&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The API returns threshold-classified alerts, but understanding the science helps with application logic:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weak Precursor (&amp;gt;0.0015 mol/m²):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Typical warning window: 5-7 days&lt;/li&gt;
&lt;li&gt;Interpretation: Magma degassing at depth&lt;/li&gt;
&lt;li&gt;Action: Increased monitoring, preparedness&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Moderate (&amp;gt;0.005 mol/m²):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Magma approaching surface or significant pressure buildup&lt;/li&gt;
&lt;li&gt;Action: Enhanced surveillance, evacuation planning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;High (&amp;gt;0.01 mol/m²):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Co-eruptive or actively erupting&lt;/li&gt;
&lt;li&gt;Action: Emergency response, aviation alerts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Critical consideration:&lt;/strong&gt; These thresholds are statistically derived from historical eruptions. They provide guidance, not certainty.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Confidence Levels&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The API returns confidence levels based on multi-parameter analysis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "confidence": "high",
  "factors": {
    "so2_elevation": true,
    "temporal_consistency": true,
    "spatial_pattern": true
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Integration logic:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def should_trigger_alert(event):
    """
    Decision logic for alert triggering
    """
    if event['alert_level'] == 'HIGH':
        return True  # Always alert on high

    if event['alert_level'] == 'MODERATE' and event['confidence'] == 'high':
        return True

    if event['alert_level'] == 'WEAK':
        # Only alert if part of temporal pattern
        return check_temporal_pattern(event)

    return False
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Temporal Pattern Recognition&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Single anomalies can be atmospheric noise. Look for patterns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def check_temporal_pattern(events, window_days=7):
    """
    Check if anomalies cluster temporally (precursor pattern)
    """
    from collections import Counter
    from datetime import datetime, timedelta

    dates = [datetime.fromisoformat(e['date']) for e in events]
    dates.sort()

    # Check for multiple anomalies within window
    clusters = []
    for i, date in enumerate(dates):
        cluster = [date]
        for other_date in dates[i+1:]:
            if (other_date - date).days &amp;lt;= window_days:
                cluster.append(other_date)
        if len(cluster) &amp;gt;= 2:
            clusters.append(cluster)

    return len(clusters) &amp;gt; 0  # Pattern detected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use Cases by Industry&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aviation Safety&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integration point: VAAC (Volcanic Ash Advisory Centers)&lt;/li&gt;
&lt;li&gt;Key feature: SO₂ cloud tracking + ash plume correlation&lt;/li&gt;
&lt;li&gt;Alert threshold: Any detected anomaly (aviation is zero-tolerance)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Disaster Management&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integration point: Civil defense early warning systems&lt;/li&gt;
&lt;li&gt;Key feature: Temporal pattern detection for evacuation timing&lt;/li&gt;
&lt;li&gt;Alert threshold: MODERATE with high confidence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Research &amp;amp; Academia&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integration point: Volcano observatories, research databases&lt;/li&gt;
&lt;li&gt;Key feature: Historical analysis, eruption correlation studies&lt;/li&gt;
&lt;li&gt;Alert threshold: All events logged for analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Insurance &amp;amp; Risk Assessment&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integration point: Catastrophe modeling systems&lt;/li&gt;
&lt;li&gt;Key feature: Long-term degassing trends, eruption probability&lt;/li&gt;
&lt;li&gt;Alert threshold: Sustained elevated activity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Rate Limits &amp;amp; Caching Strategies&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Satellite data updates daily, so aggressive polling isn't necessary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import time
from functools import lru_cache

@lru_cache(maxsize=128)
def get_volcano_status_cached(volcano_name, date_key):
    """
    Cache results by volcano + date
    date_key ensures daily refresh
    """
    return check_volcano_status(volcano_name)

# Usage
date_key = datetime.now().strftime('%Y-%m-%d')
status = get_volcano_status_cached('Erta Ale', date_key)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Recommended polling frequency:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real-time monitoring: Every 6-12 hours&lt;/li&gt;
&lt;li&gt;Dashboard updates: Daily&lt;/li&gt;
&lt;li&gt;Historical analysis: On-demand&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import requests
from requests.exceptions import RequestException

def safe_api_call(volcano_name, max_retries=3):
    """
    Robust API calling with exponential backoff
    """
    for attempt in range(max_retries):
        try:
            response = requests.post(
                API_ENDPOINT,
                headers={'Authorization': f'Bearer {API_KEY}'},
                json={'volcano_name': volcano_name},
                timeout=30
            )

            if response.status_code == 200:
                return response.json()
            elif response.status_code == 404:
                # Volcano not found - check name spelling
                raise ValueError(f"Volcano '{volcano_name}' not found")
            elif response.status_code == 429:
                # Rate limit - backoff
                wait_time = 2 ** attempt
                time.sleep(wait_time)
                continue
            else:
                response.raise_for_status()

        except RequestException as e:
            if attempt == max_retries - 1:
                raise
            time.sleep(2 ** attempt)

    return None
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Going Further&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This article covered core integration patterns. Additional capabilities to explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Spatial analysis:&lt;/strong&gt; Plume drift modeling, downwind impact zones&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-gas correlation:&lt;/strong&gt; SO₂ + CO + CH₄ for higher confidence&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seismic data fusion:&lt;/strong&gt; Combine satellite degassing with ground seismic data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Machine learning:&lt;/strong&gt; Train models on historical precursor patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Satellite data democratizes volcano monitoring -&lt;/strong&gt; works for remote/understudied volcanoes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;APIs abstract complexity -&lt;/strong&gt; no need to process petabytes of raw satellite data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thresholds are guidance -&lt;/strong&gt; use temporal patterns and confidence levels in logic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache aggressively -&lt;/strong&gt; daily satellite updates don't require real-time polling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context matters -&lt;/strong&gt; interpretation differs by volcano type and tectonic setting&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Hayli Gubbi case proved satellite degassing data can detect precursors 5-6 days before explosive eruptions. The challenge for developers is building systems that act on these signals.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;VolcanoWatch API provides processed Sentinel-5P SO₂ data for global volcano monitoring. For API access and documentation: &lt;a href="https://www.climintell.com/" rel="noopener noreferrer"&gt;www.climintell.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technologies mentioned:&lt;/strong&gt; Sentinel-5P TROPOMI, Python, JavaScript, Chart.js&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Carn et al. (2017) - "Multi-decadal satellite measurements of global volcanic degassing" - Scientific Reports&lt;/li&gt;
&lt;li&gt;NASA Earth Observatory - Volcano monitoring from space&lt;/li&gt;
&lt;li&gt;Copernicus Sentinel-5P documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;What volcano monitoring use cases are you building? Drop your questions in the comments!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>python</category>
      <category>javascript</category>
      <category>geospatial</category>
    </item>
  </channel>
</rss>
