Home / Notebooks / Geospatial & Remote Sensing
Geospatial & Remote Sensing
intermediate

Sentinel Hub Essentials

Complete guide to accessing and processing satellite imagery with Sentinel Hub

April 20, 2026
Updated regularly

Sentinel Hub Essentials

Complete guide to accessing and processing satellite imagery using Sentinel Hub APIs.

What is Sentinel Hub?

Sentinel Hub is a cloud-based platform that provides access to satellite imagery from various Earth observation missions, primarily Copernicus Sentinel satellites.

Key Features:

  • Access to Sentinel-1, Sentinel-2, Sentinel-3, Landsat, and more
  • On-the-fly image processing and analysis
  • RESTful APIs for easy integration
  • Pre-built processing scripts
  • Cloud-optimized data access (no downloads required)
  • Custom band combinations and indices (NDVI, NDWI, etc.)
  • Common Use Cases:

  • Agriculture monitoring
  • Environmental analysis
  • Urban planning
  • Disaster response
  • Change detection
  • Land cover classification
  • Prerequisites

    Requirements

  • Python 3.8 or higher
  • Sentinel Hub account (free trial available)
  • Basic understanding of satellite imagery concepts
  • Get API Credentials

    Step 1: Create Account

  • Go to https://www.sentinel-hub.com/
  • Sign up for a free trial account
  • Verify your email
  • Step 2: Get Credentials

  • Log in to Sentinel Hub Dashboard
  • Go to "User Settings" → "OAuth clients"
  • Create new OAuth client
  • Copy your CLIENT_ID and CLIENT_SECRET
  • Installation

    Install Sentinel Hub Python Package

    # Step 1: Create virtual environment (recommended)
    python -m venv venv
    source venv/bin/activate  # On Windows: venv\Scripts\activate
    
    # Step 2: Install sentinelhub package
    pip install sentinelhub
    
    # Step 3: Install additional dependencies
    pip install numpy matplotlib rasterio
    
    Verify Installation:
    python -c "import sentinelhub; print(sentinelhub.__version__)"
    

    Configuration

    Setup Authentication

    Create .env file:

    # Sentinel Hub credentials
    SH_CLIENT_ID=your_client_id_here
    SH_CLIENT_SECRET=your_client_secret_here
    SH_INSTANCE_ID=your_instance_id_here
    

    Configure in Python:

    # ========== Option 1: Using Config ==========
    from sentinelhub import SHConfig
    
    # Create configuration
    config = SHConfig()
    config.sh_client_id = 'your_client_id'
    config.sh_client_secret = 'your_client_secret'
    
    # Save configuration (persists for future use)
    config.save()
    
    # ========== Option 2: From Environment Variables ==========
    import os
    from dotenv import load_dotenv
    
    load_dotenv()
    
    config = SHConfig()
    config.sh_client_id = os.getenv('SH_CLIENT_ID')
    config.sh_client_secret = os.getenv('SH_CLIENT_SECRET')
    
    # ========== Verify Configuration ==========
    print(f"Client ID: {config.sh_client_id[:8]}...")
    print(f"Base URL: {config.sh_base_url}")
    

    Basic Concepts

    Understanding Sentinel Satellites

    Sentinel-2:

  • Optical imagery (visible and near-infrared)
  • 13 spectral bands
  • 10m to 60m resolution
  • 5-day revisit time
  • Best for: vegetation, land use, agriculture
  • Sentinel-1:

  • Synthetic Aperture Radar (SAR)
  • All-weather, day/night imaging
  • 10m resolution
  • 6-day revisit time
  • Best for: flood mapping, ship detection, ice monitoring
  • Common Spectral Bands

    # Sentinel-2 bands
    BANDS = {
        'B01': 'Coastal aerosol (443 nm)',
        'B02': 'Blue (490 nm) - 10m',
        'B03': 'Green (560 nm) - 10m',
        'B04': 'Red (665 nm) - 10m',
        'B05': 'Red Edge 1 (705 nm)',
        'B06': 'Red Edge 2 (740 nm)',
        'B07': 'Red Edge 3 (783 nm)',
        'B08': 'NIR (842 nm) - 10m',
        'B8A': 'Narrow NIR (865 nm)',
        'B09': 'Water vapour (945 nm)',
        'B10': 'SWIR Cirrus (1375 nm)',
        'B11': 'SWIR 1 (1610 nm)',
        'B12': 'SWIR 2 (2190 nm)'
    }
    

    Searching for Data

    Find Available Images

    from sentinelhub import SHConfig, DataCollection, SentinelHubCatalog
    from datetime import datetime, timedelta
    
    # ========== Setup ==========
    config = SHConfig()
    catalog = SentinelHubCatalog(config=config)
    
    # ========== Define Search Parameters ==========
    # Area of interest (bounding box)
    bbox = [13.822, 45.85, 13.835, 45.86]  # Venice, Italy [lon_min, lat_min, lon_max, lat_max]
    
    # Time range
    time_interval = (
        datetime(2024, 6, 1),
        datetime(2024, 8, 31)
    )
    
    # ========== Search for Sentinel-2 Images ==========
    search_iterator = catalog.search(
        DataCollection.SENTINEL2_L2A,  # Sentinel-2 Level-2A (atmospherically corrected)
        bbox=bbox,
        time=time_interval,
        filter="eo:cloud_cover < 20",  # Max 20% cloud cover
        fields={
            "include": ["id", "properties.datetime", "properties.eo:cloud_cover"],
            "exclude": []
        }
    )
    
    # ========== Display Results ==========
    results = list(search_iterator)
    print(f"Found {len(results)} images")
    
    for item in results[:5]:  # Show first 5
        print(f"ID: {item['id']}")
        print(f"Date: {item['properties']['datetime']}")
        print(f"Cloud Cover: {item['properties']['eo:cloud_cover']}%")
        print("-" * 50)
    
    Expected Output:
    Found 12 images
    ID: S2A_MSIL2A_20240815T100031_N0510_R122_T33TVG_20240815T171645
    Date: 2024-08-15T10:15:42Z
    Cloud Cover: 5.2%
    --------------------------------------------------
    

    Requesting Imagery

    True Color Image

    from sentinelhub import (
        SHConfig, SentinelHubRequest, DataCollection,
        BBox, CRS, MimeType, bbox_to_dimensions
    )
    
    # ========== Configuration ==========
    config = SHConfig()
    
    # ========== Define Area of Interest ==========
    bbox = BBox(bbox=[13.822, 45.85, 13.835, 45.86], crs=CRS.WGS84)
    resolution = 10  # 10 meters per pixel
    size = bbox_to_dimensions(bbox, resolution=resolution)
    
    print(f"Image size: {size} pixels")
    
    # ========== Evalscript for True Color ==========
    evalscript_true_color = """
    //VERSION=3
    
    function setup() {
        return {
            input: [{
                bands: ["B04", "B03", "B02"]  // Red, Green, Blue
            }],
            output: {
                bands: 3,
                sampleType: "AUTO"
            }
        };
    }
    
    function evaluatePixel(sample) {
        // Apply gain for brightness
        return [2.5 * sample.B04, 2.5 * sample.B03, 2.5 * sample.B02];
    }
    """
    
    # ========== Create Request ==========
    request = SentinelHubRequest(
        evalscript=evalscript_true_color,
        input_data=[
            SentinelHubRequest.input_data(
                data_collection=DataCollection.SENTINEL2_L2A,
                time_interval=('2024-08-01', '2024-08-31'),
                maxcc=0.2  # Maximum 20% cloud coverage
            )
        ],
        responses=[
            SentinelHubRequest.output_response('default', MimeType.PNG)
        ],
        bbox=bbox,
        size=size,
        config=config
    )
    
    # ========== Get Image ==========
    true_color_image = request.get_data()[0]
    
    print(f"Image shape: {true_color_image.shape}")
    print(f"Data type: {true_color_image.dtype}")
    

    Visualize with Matplotlib

    import matplotlib.pyplot as plt
    
    # ========== Display Image ==========
    plt.figure(figsize=(12, 8))
    plt.imshow(true_color_image)
    plt.title('Sentinel-2 True Color Image')
    plt.axis('off')
    plt.tight_layout()
    plt.savefig('true_color.png', dpi=300, bbox_inches='tight')
    plt.show()
    
    print("Image saved as 'true_color.png'")
    

    Vegetation Indices

    NDVI (Normalized Difference Vegetation Index)

    # ========== NDVI Evalscript ==========
    evalscript_ndvi = """
    //VERSION=3
    
    function setup() {
        return {
            input: [{
                bands: ["B04", "B08"]  // Red and NIR
            }],
            output: {
                bands: 1,
                sampleType: "FLOAT32"
            }
        };
    }
    
    function evaluatePixel(sample) {
        // NDVI = (NIR - Red) / (NIR + Red)
        let ndvi = (sample.B08 - sample.B04) / (sample.B08 + sample.B04);
        return [ndvi];
    }
    """
    
    # ========== Request NDVI ==========
    request_ndvi = SentinelHubRequest(
        evalscript=evalscript_ndvi,
        input_data=[
            SentinelHubRequest.input_data(
                data_collection=DataCollection.SENTINEL2_L2A,
                time_interval=('2024-08-01', '2024-08-31'),
                maxcc=0.2
            )
        ],
        responses=[
            SentinelHubRequest.output_response('default', MimeType.TIFF)
        ],
        bbox=bbox,
        size=size,
        config=config
    )
    
    # ========== Get NDVI Data ==========
    ndvi_data = request_ndvi.get_data()[0]
    
    # ========== Visualize NDVI ==========
    plt.figure(figsize=(12, 8))
    plt.imshow(ndvi_data, cmap='RdYlGn', vmin=-1, vmax=1)
    plt.colorbar(label='NDVI Value')
    plt.title('NDVI - Vegetation Health')
    plt.axis('off')
    plt.tight_layout()
    plt.savefig('ndvi.png', dpi=300, bbox_inches='tight')
    plt.show()
    
    # ========== Interpret NDVI Values ==========
    print("NDVI Interpretation:")
    print("  -1.0 to 0.0: Water, snow, clouds")
    print("   0.0 to 0.2: Barren rock, sand, urban areas")
    print("   0.2 to 0.4: Shrubs and grassland")
    print("   0.4 to 0.6: Moderate vegetation")
    print("   0.6 to 1.0: Dense, healthy vegetation")
    

    NDWI (Normalized Difference Water Index)

    # ========== NDWI Evalscript ==========
    evalscript_ndwi = """
    //VERSION=3
    
    function setup() {
        return {
            input: [{
                bands: ["B03", "B08"]  // Green and NIR
            }],
            output: {
                bands: 1,
                sampleType: "FLOAT32"
            }
        };
    }
    
    function evaluatePixel(sample) {
        // NDWI = (Green - NIR) / (Green + NIR)
        let ndwi = (sample.B03 - sample.B08) / (sample.B03 + sample.B08);
        return [ndwi];
    }
    """
    
    # ========== Request NDWI ==========
    request_ndwi = SentinelHubRequest(
        evalscript=evalscript_ndwi,
        input_data=[
            SentinelHubRequest.input_data(
                data_collection=DataCollection.SENTINEL2_L2A,
                time_interval=('2024-08-01', '2024-08-31'),
                maxcc=0.2
            )
        ],
        responses=[
            SentinelHubRequest.output_response('default', MimeType.TIFF)
        ],
        bbox=bbox,
        size=size,
        config=config
    )
    
    # ========== Get and Visualize ==========
    ndwi_data = request_ndwi.get_data()[0]
    
    plt.figure(figsize=(12, 8))
    plt.imshow(ndwi_data, cmap='Blues', vmin=-1, vmax=1)
    plt.colorbar(label='NDWI Value')
    plt.title('NDWI - Water Content')
    plt.axis('off')
    plt.tight_layout()
    plt.savefig('ndwi.png', dpi=300, bbox_inches='tight')
    plt.show()
    

    Time Series Analysis

    Multi-Temporal Comparison

    from sentinelhub import SentinelHubRequest, DataCollection, MimeType
    import numpy as np
    
    # ========== Define Time Periods ==========
    time_periods = [
        ('2024-01-01', '2024-01-31', 'January'),
        ('2024-04-01', '2024-04-30', 'April'),
        ('2024-07-01', '2024-07-31', 'July'),
        ('2024-10-01', '2024-10-31', 'October')
    ]
    
    # ========== Collect Images for Each Period ==========
    ndvi_series = []
    
    for start, end, label in time_periods:
        request = SentinelHubRequest(
            evalscript=evalscript_ndvi,
            input_data=[
                SentinelHubRequest.input_data(
                    data_collection=DataCollection.SENTINEL2_L2A,
                    time_interval=(start, end),
                    maxcc=0.3
                )
            ],
            responses=[
                SentinelHubRequest.output_response('default', MimeType.TIFF)
            ],
            bbox=bbox,
            size=size,
            config=config
        )
        
        ndvi = request.get_data()[0]
        ndvi_series.append((ndvi, label))
        print(f"{label}: Mean NDVI = {np.nanmean(ndvi):.3f}")
    
    # ========== Visualize Time Series ==========
    fig, axes = plt.subplots(2, 2, figsize=(16, 12))
    
    for idx, (ndvi, label) in enumerate(ndvi_series):
        ax = axes[idx // 2, idx % 2]
        im = ax.imshow(ndvi, cmap='RdYlGn', vmin=-1, vmax=1)
        ax.set_title(f'NDVI - {label}')
        ax.axis('off')
    
    plt.colorbar(im, ax=axes.ravel().tolist(), label='NDVI')
    plt.tight_layout()
    plt.savefig('ndvi_time_series.png', dpi=300, bbox_inches='tight')
    plt.show()
    

    Advanced Processing

    Cloud Masking

    # ========== Evalscript with Cloud Mask ==========
    evalscript_cloud_mask = """
    //VERSION=3
    
    function setup() {
        return {
            input: [{
                bands: ["B04", "B03", "B02", "CLM"]  // RGB + Cloud Mask
            }],
            output: {
                bands: 3,
                sampleType: "AUTO"
            }
        };
    }
    
    function evaluatePixel(sample) {
        // If cloud detected (CLM = 1), return gray
        if (sample.CLM == 1) {
            return [0.5, 0.5, 0.5];
        }
        
        // Otherwise return true color
        return [2.5 * sample.B04, 2.5 * sample.B03, 2.5 * sample.B02];
    }
    """
    
    # ========== Request with Cloud Masking ==========
    request_masked = SentinelHubRequest(
        evalscript=evalscript_cloud_mask,
        input_data=[
            SentinelHubRequest.input_data(
                data_collection=DataCollection.SENTINEL2_L2A,
                time_interval=('2024-08-01', '2024-08-31')
            )
        ],
        responses=[
            SentinelHubRequest.output_response('default', MimeType.PNG)
        ],
        bbox=bbox,
        size=size,
        config=config
    )
    
    masked_image = request_masked.get_data()[0]
    

    False Color Composite

    # ========== False Color (NIR, Red, Green) ==========
    evalscript_false_color = """
    //VERSION=3
    
    function setup() {
        return {
            input: [{
                bands: ["B08", "B04", "B03"]  // NIR, Red, Green
            }],
            output: {
                bands: 3,
                sampleType: "AUTO"
            }
        };
    }
    
    function evaluatePixel(sample) {
        // Vegetation appears red in false color
        return [2.5 * sample.B08, 2.5 * sample.B04, 2.5 * sample.B03];
    }
    """
    
    # ========== Request False Color ==========
    request_false = SentinelHubRequest(
        evalscript=evalscript_false_color,
        input_data=[
            SentinelHubRequest.input_data(
                data_collection=DataCollection.SENTINEL2_L2A,
                time_interval=('2024-08-01', '2024-08-31'),
                maxcc=0.2
            )
        ],
        responses=[
            SentinelHubRequest.output_response('default', MimeType.PNG)
        ],
        bbox=bbox,
        size=size,
        config=config
    )
    
    false_color = request_false.get_data()[0]
    
    # ========== Display ==========
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 8))
    
    ax1.imshow(true_color_image)
    ax1.set_title('True Color')
    ax1.axis('off')
    
    ax2.imshow(false_color)
    ax2.set_title('False Color (Vegetation in Red)')
    ax2.axis('off')
    
    plt.tight_layout()
    plt.savefig('color_comparison.png', dpi=300, bbox_inches='tight')
    plt.show()
    

    Batch Processing

    Process Multiple Locations

    from sentinelhub import BBox, CRS
    
    # ========== Define Multiple Areas ==========
    locations = {
        'Venice': BBox([13.822, 45.85, 13.835, 45.86], crs=CRS.WGS84),
        'Rome': BBox([12.48, 41.88, 12.50, 41.90], crs=CRS.WGS84),
        'Milan': BBox([9.18, 45.46, 9.20, 45.48], crs=CRS.WGS84)
    }
    
    # ========== Process Each Location ==========
    results = {}
    
    for name, bbox in locations.items():
        print(f"Processing {name}...")
        
        size = bbox_to_dimensions(bbox, resolution=10)
        
        request = SentinelHubRequest(
            evalscript=evalscript_ndvi,
            input_data=[
                SentinelHubRequest.input_data(
                    data_collection=DataCollection.SENTINEL2_L2A,
                    time_interval=('2024-08-01', '2024-08-31'),
                    maxcc=0.2
                )
            ],
            responses=[
                SentinelHubRequest.output_response('default', MimeType.TIFF)
            ],
            bbox=bbox,
            size=size,
            config=config
        )
        
        ndvi = request.get_data()[0]
        results[name] = {
            'ndvi': ndvi,
            'mean': np.nanmean(ndvi),
            'std': np.nanstd(ndvi)
        }
        
        print(f"  Mean NDVI: {results[name]['mean']:.3f}")
        print(f"  Std Dev: {results[name]['std']:.3f}")
    
    # ========== Compare Results ==========
    fig, axes = plt.subplots(1, 3, figsize=(18, 6))
    
    for idx, (name, data) in enumerate(results.items()):
        axes[idx].imshow(data['ndvi'], cmap='RdYlGn', vmin=-1, vmax=1)
        axes[idx].set_title(f"{name}\nMean NDVI: {data['mean']:.3f}")
        axes[idx].axis('off')
    
    plt.colorbar(plt.cm.ScalarMappable(cmap='RdYlGn', norm=plt.Normalize(-1, 1)),
                 ax=axes, label='NDVI')
    plt.tight_layout()
    plt.savefig('batch_comparison.png', dpi=300, bbox_inches='tight')
    plt.show()
    

    Export to GeoTIFF

    Save with Geospatial Metadata

    import rasterio
    from rasterio.transform import from_bounds
    
    # ========== Get Image Data ==========
    ndvi_data = request_ndvi.get_data()[0]
    
    # ========== Define Spatial Reference ==========
    bounds = bbox.geometry.bounds  # (min_lon, min_lat, max_lon, max_lat)
    height, width = ndvi_data.shape
    
    transform = from_bounds(
        bounds[0], bounds[1], bounds[2], bounds[3],
        width, height
    )
    
    # ========== Write GeoTIFF ==========
    with rasterio.open(
        'ndvi_output.tif',
        'w',
        driver='GTiff',
        height=height,
        width=width,
        count=1,  # Number of bands
        dtype=ndvi_data.dtype,
        crs='EPSG:4326',  # WGS84
        transform=transform,
        compress='lzw'  # Compression
    ) as dst:
        dst.write(ndvi_data, 1)
        
        # Add metadata
        dst.update_tags(
            DESCRIPTION='NDVI from Sentinel-2',
            DATE='2024-08-15',
            SOURCE='Sentinel Hub'
        )
    
    print("GeoTIFF saved successfully")
    print(f"File: ndvi_output.tif")
    print(f"CRS: EPSG:4326")
    print(f"Bounds: {bounds}")
    

    Common Use Cases

    Agriculture Monitoring

    # ========== Monitor Crop Health ==========
    def analyze_crop_health(bbox, time_interval, threshold=0.6):
        """
        Analyze crop health using NDVI
        
        Args:
            bbox: Area of interest
            time_interval: Date range
            threshold: NDVI threshold for healthy vegetation
        """
        request = SentinelHubRequest(
            evalscript=evalscript_ndvi,
            input_data=[
                SentinelHubRequest.input_data(
                    data_collection=DataCollection.SENTINEL2_L2A,
                    time_interval=time_interval,
                    maxcc=0.2
                )
            ],
            responses=[
                SentinelHubRequest.output_response('default', MimeType.TIFF)
            ],
            bbox=bbox,
            size=bbox_to_dimensions(bbox, resolution=10),
            config=config
        )
        
        ndvi = request.get_data()[0]
        
        # Calculate statistics
        healthy = np.sum(ndvi > threshold)
        stressed = np.sum((ndvi > 0.2) & (ndvi <= threshold))
        total_vegetation = healthy + stressed
        
        print(f"Crop Health Analysis:")
        print(f"  Healthy vegetation: {healthy / total_vegetation * 100:.1f}%")
        print(f"  Stressed vegetation: {stressed / total_vegetation * 100:.1f}%")
        
        return ndvi
    
    # Usage
    farm_bbox = BBox([13.822, 45.85, 13.835, 45.86], crs=CRS.WGS84)
    crop_ndvi = analyze_crop_health(farm_bbox, ('2024-07-01', '2024-07-31'))
    

    Water Body Detection

    # ========== Detect Water Bodies ==========
    def detect_water(bbox, time_interval):
        """Detect water bodies using NDWI"""
        request = SentinelHubRequest(
            evalscript=evalscript_ndwi,
            input_data=[
                SentinelHubRequest.input_data(
                    data_collection=DataCollection.SENTINEL2_L2A,
                    time_interval=time_interval,
                    maxcc=0.2
                )
            ],
            responses=[
                SentinelHubRequest.output_response('default', MimeType.TIFF)
            ],
            bbox=bbox,
            size=bbox_to_dimensions(bbox, resolution=10),
            config=config
        )
        
        ndwi = request.get_data()[0]
        
        # Water typically has NDWI > 0.3
        water_mask = ndwi > 0.3
        water_pixels = np.sum(water_mask)
        total_pixels = ndwi.size
        
        print(f"Water Detection:")
        print(f"  Water coverage: {water_pixels / total_pixels * 100:.2f}%")
        print(f"  Water pixels: {water_pixels:,}")
        
        return water_mask
    
    # Usage
    water_mask = detect_water(bbox, ('2024-08-01', '2024-08-31'))
    

    Best Practices

    Optimize API Usage

    1. Use Appropriate Resolution
    # High resolution (10m) - small areas only
    size_10m = bbox_to_dimensions(bbox, resolution=10)
    
    # Medium resolution (20m) - balanced
    size_20m = bbox_to_dimensions(bbox, resolution=20)
    
    # Low resolution (60m) - large areas
    size_60m = bbox_to_dimensions(bbox, resolution=60)
    
    2. Filter by Cloud Coverage
    # Only get images with <10% clouds
    input_data = SentinelHubRequest.input_data(
        data_collection=DataCollection.SENTINEL2_L2A,
        time_interval=('2024-08-01', '2024-08-31'),
        maxcc=0.1  # 10% maximum cloud coverage
    )
    
    3. Cache Results
    import pickle
    
    # Save processed data
    with open('ndvi_cache.pkl', 'wb') as f:
        pickle.dump(ndvi_data, f)
    
    # Load cached data
    with open('ndvi_cache.pkl', 'rb') as f:
        ndvi_data = pickle.load(f)
    
    4. Batch Requests
    # Request multiple time periods in one call
    from sentinelhub import DownloadRequest
    
    requests = [
        request1.download_list[0],
        request2.download_list[0],
        request3.download_list[0]
    ]
    
    # Download all at once
    data = SentinelHubDownloadClient(config=config).download(requests)
    

    Troubleshooting

    Common Issues

    Authentication Error:
    # Verify credentials
    config = SHConfig()
    print(f"Client ID set: {bool(config.sh_client_id)}")
    print(f"Client Secret set: {bool(config.sh_client_secret)}")
    
    # Test authentication
    from sentinelhub import SentinelHubRequest
    try:
        # Simple test request
        test_request = SentinelHubRequest(...)
        print("Authentication successful!")
    except Exception as e:
        print(f"Authentication failed: {e}")
    
    No Data Found:
    # Check if images exist for your parameters
    results = list(catalog.search(
        DataCollection.SENTINEL2_L2A,
        bbox=bbox,
        time=time_interval
    ))
    
    if len(results) == 0:
        print("No images found. Try:")
        print("  - Expanding time range")
        print("  - Increasing cloud coverage threshold")
        print("  - Verifying bbox coordinates")
    
    Rate Limiting:
    import time
    
    # Add delay between requests
    for location in locations:
        process_location(location)
        time.sleep(1)  # Wait 1 second between requests
    

    Resources

  • Official Docs: https://docs.sentinel-hub.com/
  • Sentinel Hub: https://www.sentinel-hub.com/
  • Python Package: https://sentinelhub-py.readthedocs.io/
  • Custom Scripts: https://custom-scripts.sentinel-hub.com/
  • EO Browser: https://apps.sentinel-hub.com/eo-browser/
  • Copernicus Open Access Hub: https://scihub.copernicus.eu/
  • Quick Reference Card

    # ========== Setup ==========
    from sentinelhub import SHConfig, SentinelHubRequest, DataCollection
    config = SHConfig()
    config.sh_client_id = 'your_id'
    config.sh_client_secret = 'your_secret'
    
    # ========== Define Area ==========
    bbox = BBox([lon_min, lat_min, lon_max, lat_max], crs=CRS.WGS84)
    size = bbox_to_dimensions(bbox, resolution=10)
    
    # ========== Request Data ==========
    request = SentinelHubRequest(
        evalscript=your_script,
        input_data=[...],
        responses=[...],
        bbox=bbox,
        size=size,
        config=config
    )
    data = request.get_data()[0]
    
    # ========== Common Indices ==========
    # NDVI = (NIR - Red) / (NIR + Red)
    # NDWI = (Green - NIR) / (Green + NIR)
    # EVI = 2.5 * (NIR - Red) / (NIR + 6*Red - 7.5*Blue + 1)
    

    Next Steps

  • Explore custom evalscripts at https://custom-scripts.sentinel-hub.com/
  • Try different satellite data sources (Landsat, Sentinel-1)
  • Integrate with machine learning for classification
  • Build time-series analysis pipelines
  • Create automated monitoring systems
  • ---

    Last Updated: 2026-04-20 Sentinel Hub API: v3 Difficulty: Intermediate

    Topics

    Sentinel HubSatellite ImageryRemote SensingPythonGIS

    Found This Helpful?

    If you have questions or suggestions for improving these notes, I'd love to hear from you.