Tracking Air Cargo Rates and Capacity with Proxy Networks

Tracking Air Cargo Rates and Capacity with Proxy Networks

Air cargo is the fastest-growing segment of freight transport in Southeast Asia. With high-value manufacturing (electronics, semiconductors, pharmaceuticals) expanding across the region and e-commerce driving demand for fast cross-border delivery, air freight rates and capacity have become critical data points for logistics planners. Unlike ocean freight, where rates are published more transparently, air cargo pricing remains opaque, fragmented, and difficult to track systematically.

This guide explains how to use proxy networks to build an air cargo rate and capacity monitoring system that provides the market intelligence needed for effective freight procurement and planning.

The Air Cargo Market in Southeast Asia

Key Air Cargo Hubs

Southeast Asia’s air cargo market is anchored by several major hubs:

Singapore Changi Airport (SIN): The region’s largest air cargo hub, handling over 2 million tonnes annually. Major cargo airlines and integrators operate significant capacity through Changi.

Bangkok Suvarnabhumi (BKK): Thailand’s primary air cargo gateway, serving manufacturing exports and e-commerce logistics. Growing connections to China and India.

Kuala Lumpur International (KUL): Malaysia’s main cargo hub with competitive handling costs. Strong connectivity to Middle East and European markets.

Ho Chi Minh City Tan Son Nhat (SGN): Vietnam’s busiest cargo airport, serving the country’s booming electronics manufacturing sector.

Manila NAIA (MNL): The Philippines’ gateway for electronics exports and BPO-related logistics.

Jakarta Soekarno-Hatta (CGK): Indonesia’s primary cargo airport, growing rapidly with domestic e-commerce demand.

Air Cargo Pricing Structure

Air cargo pricing is more complex than ocean freight:

  • Base rate: Per kilogram rate varying by route, weight break, and commodity
  • Fuel surcharge (FSC): Fluctuates with jet fuel prices
  • Security surcharge: Post-9/11 security compliance costs
  • Terminal handling charges: Airport and warehouse handling fees
  • Weight breaks: Rates decrease at higher weight thresholds (45kg, 100kg, 300kg, 500kg, 1000kg)
  • Commodity rates: Special rates for specific commodity types
  • ULD rates: Discounted rates for full unit load device bookings
  • Peak season surcharges: Additional charges during high-demand periods

Data Sources for Air Cargo Intelligence

Air Cargo Rate Platforms

TAC Index: Publishes air cargo rate indices based on actual transaction data. Provides weekly rate updates for major trade lanes.

Freightos Air Index: Extends the Freightos marketplace into air cargo with rate data and booking capabilities.

WebCargo by Freightos: Digital air cargo booking platform where airlines publish rates for freight forwarders.

CargoAi: Digital platform connecting shippers and airlines with rate and capacity data.

Airline cargo portals: Each major cargo airline (Singapore Airlines Cargo, Thai Airways Cargo, Cathay Cargo, Korean Air Cargo, etc.) publishes rates and capacity on their portals.

Capacity Data Sources

IATA CargoIS: Industry database with shipment-level air cargo statistics.

Airport authority statistics: Monthly cargo throughput data published by airport authorities.

Airline schedules: Freighter and belly cargo capacity from airline schedule databases like OAG and Cirium.

AIS-equivalent for aviation: FlightRadar24 and FlightAware provide real-time flight tracking that can indicate cargo capacity utilization.

Building an Air Cargo Monitoring System

Why Proxies Are Essential

Air cargo platforms present unique collection challenges:

Airline portal restrictions: Cargo airline portals are designed for registered freight forwarders. They detect and block automated access patterns aggressively because rate information is commercially sensitive.

Geographic rate serving: Air cargo rates are directional and geographic. Rates from Singapore to Bangkok differ from Bangkok to Singapore. Platforms may serve different rate information based on the requester’s location.

Anti-bot sophistication: Digital cargo platforms like WebCargo and CargoAi use advanced bot detection because their business value depends on controlled data access.

DataResearchTools mobile proxies provide the trust level needed to access these platforms. Air cargo professionals increasingly use mobile devices to check rates and capacity, so mobile proxy traffic blends naturally with legitimate usage patterns.

System Architecture

class AirCargoMonitor:
    """Monitor air cargo rates and capacity across SEA routes."""

    def __init__(self, proxy_config):
        self.proxy_config = proxy_config
        self.rate_collectors = {}
        self.capacity_collectors = {}

    def add_rate_collector(self, name, collector):
        self.rate_collectors[name] = collector

    def add_capacity_collector(self, name, collector):
        self.capacity_collectors[name] = collector

    def collect_all(self, routes):
        """Collect rates and capacity for specified routes."""
        results = {
            "rates": [],
            "capacity": [],
            "collection_time": datetime.utcnow().isoformat(),
        }

        for name, collector in self.rate_collectors.items():
            print(f"Collecting rates from {name}...")
            for route in routes:
                rates = collector.collect(
                    route["origin"], route["destination"],
                    route.get("weight_kg", 100)
                )
                if rates:
                    results["rates"].extend(rates)
                time.sleep(random.uniform(3, 7))

        for name, collector in self.capacity_collectors.items():
            print(f"Collecting capacity from {name}...")
            for route in routes:
                capacity = collector.collect(
                    route["origin"], route["destination"]
                )
                if capacity:
                    results["capacity"].extend(capacity)
                time.sleep(random.uniform(3, 7))

        return results

Rate Collection

@dataclass
class AirCargoRate:
    origin_airport: str
    destination_airport: str
    airline: str
    rate_per_kg: float
    currency: str
    weight_break: str  # "M" (min), "N" (normal), "+45", "+100", "+300", "+500", "+1000"
    fuel_surcharge_per_kg: float
    security_surcharge_per_kg: float
    total_per_kg: float
    commodity_code: str
    transit_hours: int
    frequency: str  # "daily", "3x_weekly", etc.
    valid_from: str
    valid_to: str
    source: str
    collected_at: str

class AirlineCargoRateCollector:
    """Collect rates from airline cargo portals."""

    def __init__(self, proxy_config, airline_config):
        self.proxy_config = proxy_config
        self.airline = airline_config

    def collect(self, origin, destination, weight_kg):
        """Collect air cargo rates for a specific route."""
        # Determine proxy country based on origin airport
        country = self._airport_to_country(origin)
        proxy = self.proxy_config.get_proxy(country, sticky=True)

        session = requests.Session()
        session.proxies = proxy
        session.headers.update({
            "User-Agent": (
                "Mozilla/5.0 (Linux; Android 14; Samsung SM-S928B) "
                "AppleWebKit/537.36 Chrome/121.0.0.0 Mobile Safari/537.36"
            ),
            "Accept": "application/json",
        })

        rates = []
        try:
            # Query airline rate API
            response = session.post(
                self.airline["rate_api"],
                json={
                    "origin": origin,
                    "destination": destination,
                    "weight": weight_kg,
                    "pieces": 1,
                    "commodity": "GEN",  # General cargo
                },
                timeout=30,
            )

            if response.status_code == 200:
                data = response.json()
                for quote in data.get("rates", []):
                    rate = AirCargoRate(
                        origin_airport=origin,
                        destination_airport=destination,
                        airline=self.airline["name"],
                        rate_per_kg=quote["rate"],
                        currency=quote.get("currency", "USD"),
                        weight_break=quote.get("weight_break", "N"),
                        fuel_surcharge_per_kg=quote.get("fsc", 0),
                        security_surcharge_per_kg=quote.get("ssc", 0),
                        total_per_kg=(
                            quote["rate"]
                            + quote.get("fsc", 0)
                            + quote.get("ssc", 0)
                        ),
                        commodity_code=quote.get("commodity", "GEN"),
                        transit_hours=quote.get("transit_hours", 0),
                        frequency=quote.get("frequency", ""),
                        valid_from=quote.get("valid_from", ""),
                        valid_to=quote.get("valid_to", ""),
                        source=self.airline["name"],
                        collected_at=datetime.utcnow().isoformat(),
                    )
                    rates.append(rate)

        except Exception as e:
            print(f"Error collecting {self.airline['name']} rates: {e}")

        return rates

    def _airport_to_country(self, airport_code):
        airport_countries = {
            "SIN": "sg", "BKK": "th", "DMK": "th",
            "CGK": "id", "SUB": "id", "SGN": "vn",
            "HAN": "vn", "MNL": "ph", "CEB": "ph",
            "KUL": "my", "PEN": "my",
        }
        return airport_countries.get(airport_code, "sg")

Capacity Monitoring

@dataclass
class AirCargoCapacity:
    origin_airport: str
    destination_airport: str
    airline: str
    flight_number: str
    aircraft_type: str
    cargo_capacity_kg: float
    available_capacity_kg: float
    utilization_pct: float
    flight_date: str
    departure_time: str
    service_type: str  # "freighter", "belly", "combi"
    collected_at: str

class CapacityMonitor:
    """Monitor air cargo capacity on key routes."""

    def __init__(self, proxy_config):
        self.proxy_config = proxy_config

    def collect(self, origin, destination, date_range_days=7):
        """Collect capacity data for upcoming flights on a route."""
        country = self._airport_to_country(origin)
        proxy = self.proxy_config.get_proxy(country)

        session = requests.Session()
        session.proxies = proxy
        session.headers.update({
            "User-Agent": (
                "Mozilla/5.0 (iPhone; CPU iPhone OS 17_3 like Mac OS X) "
                "AppleWebKit/605.1.15 Mobile/15E148 Safari/604.1"
            ),
        })

        capacity_data = []
        # Collect schedule and capacity information
        # Implementation varies by data source

        return capacity_data

    def calculate_route_utilization(self, capacity_data):
        """Calculate overall route utilization from capacity data."""
        if not capacity_data:
            return None

        total_capacity = sum(c.cargo_capacity_kg for c in capacity_data)
        total_available = sum(c.available_capacity_kg for c in capacity_data)
        total_utilized = total_capacity - total_available

        return {
            "total_capacity_kg": total_capacity,
            "total_available_kg": total_available,
            "total_utilized_kg": total_utilized,
            "utilization_pct": round(
                (total_utilized / total_capacity * 100)
                if total_capacity > 0 else 0, 1
            ),
            "flights_counted": len(capacity_data),
        }

    def _airport_to_country(self, code):
        mapping = {
            "SIN": "sg", "BKK": "th", "CGK": "id",
            "SGN": "vn", "MNL": "ph", "KUL": "my",
        }
        return mapping.get(code, "sg")

Analysis and Applications

Rate Trend Analysis

def analyze_air_cargo_trends(rate_db, origin, destination, weeks=12):
    """Analyze air cargo rate trends over specified period."""
    query = """
        SELECT
            DATE_TRUNC('week', collected_at) as week,
            airline,
            AVG(total_per_kg) as avg_rate,
            MIN(total_per_kg) as min_rate,
            MAX(total_per_kg) as max_rate,
            COUNT(*) as data_points
        FROM air_cargo_rates
        WHERE origin_airport = %s
        AND destination_airport = %s
        AND collected_at >= NOW() - INTERVAL '%s weeks'
        GROUP BY week, airline
        ORDER BY week, airline
    """
    df = pd.read_sql(
        query, rate_db, params=[origin, destination, weeks]
    )

    # Calculate market average (across airlines)
    market_avg = df.groupby("week").agg({
        "avg_rate": "mean",
        "min_rate": "min",
        "max_rate": "max",
    }).rename(columns={
        "avg_rate": "market_avg",
        "min_rate": "market_min",
        "max_rate": "market_max",
    })

    return {"by_airline": df, "market_summary": market_avg}

Mode Selection (Air vs. Ocean)

Use collected data to make informed air vs. ocean decisions:

def compare_air_vs_ocean(air_rates, ocean_rates, shipment):
    """Compare air and ocean shipping for a specific shipment."""
    weight_kg = shipment["weight_kg"]
    value_usd = shipment["cargo_value_usd"]
    urgency_days = shipment.get("max_transit_days", 30)

    # Air cost calculation
    air_options = [
        r for r in air_rates
        if r.transit_hours / 24 <= urgency_days
    ]
    if air_options:
        best_air = min(air_options, key=lambda r: r.total_per_kg)
        air_cost = best_air.total_per_kg * weight_kg
        air_transit_days = best_air.transit_hours / 24
    else:
        air_cost = float("inf")
        air_transit_days = None

    # Ocean cost calculation
    ocean_options = [
        r for r in ocean_rates
        if r.transit_days <= urgency_days
    ]
    if ocean_options:
        best_ocean = min(ocean_options, key=lambda r: r.total_usd)
        ocean_cost = best_ocean.total_usd
        ocean_transit_days = best_ocean.transit_days
    else:
        ocean_cost = float("inf")
        ocean_transit_days = None

    # Calculate inventory holding cost difference
    if air_transit_days and ocean_transit_days:
        days_saved = ocean_transit_days - air_transit_days
        daily_holding_cost = value_usd * 0.0002  # ~7% annual cost of capital
        holding_savings = days_saved * daily_holding_cost
    else:
        holding_savings = 0

    return {
        "air": {
            "cost": round(air_cost, 2),
            "transit_days": air_transit_days,
            "airline": best_air.airline if air_options else None,
        },
        "ocean": {
            "cost": round(ocean_cost, 2),
            "transit_days": ocean_transit_days,
            "carrier": best_ocean.carrier if ocean_options else None,
        },
        "cost_difference": round(air_cost - ocean_cost, 2),
        "holding_cost_savings": round(holding_savings, 2),
        "adjusted_air_premium": round(
            air_cost - ocean_cost - holding_savings, 2
        ),
        "recommendation": (
            "AIR" if (air_cost - holding_savings) <= ocean_cost * 1.5
            else "OCEAN"
        ),
    }

Capacity-Based Rate Forecasting

def forecast_rate_direction(capacity_data, rate_data):
    """Forecast rate direction based on capacity utilization trends."""
    # High utilization + increasing trend = rates likely to rise
    # Low utilization + decreasing trend = rates likely to fall

    recent_utilization = capacity_data.tail(4)["utilization_pct"].mean()
    utilization_trend = (
        capacity_data.tail(4)["utilization_pct"].mean()
        - capacity_data.tail(8).head(4)["utilization_pct"].mean()
    )

    recent_rate = rate_data.tail(4)["avg_rate"].mean()
    rate_trend = (
        rate_data.tail(4)["avg_rate"].mean()
        - rate_data.tail(8).head(4)["avg_rate"].mean()
    )

    forecast = {
        "current_utilization_pct": round(recent_utilization, 1),
        "utilization_trend": round(utilization_trend, 1),
        "current_avg_rate": round(recent_rate, 2),
        "rate_trend": round(rate_trend, 2),
    }

    if recent_utilization > 80 and utilization_trend > 0:
        forecast["direction"] = "UP"
        forecast["confidence"] = "HIGH"
    elif recent_utilization < 60 and utilization_trend < 0:
        forecast["direction"] = "DOWN"
        forecast["confidence"] = "HIGH"
    elif recent_utilization > 70:
        forecast["direction"] = "UP"
        forecast["confidence"] = "MODERATE"
    else:
        forecast["direction"] = "STABLE"
        forecast["confidence"] = "LOW"

    return forecast

DataResearchTools for Air Cargo Monitoring

DataResearchTools mobile proxies are well-suited for air cargo data collection because:

  • SEA hub coverage: Mobile proxies available at all major SEA air cargo hub countries
  • Airline portal access: Mobile IP traffic matches freight forwarder usage patterns on airline cargo portals
  • Platform compatibility: Reliable access to digital cargo platforms that detect and block datacenter IPs
  • Session management: Sticky sessions for multi-step rate queries and booking platform interactions
  • Scalable collection: Handle the volume of queries needed to monitor rates across dozens of airlines and routes

Conclusion

Air cargo rate and capacity monitoring is a high-value application of proxy-based data collection. The opacity of air freight pricing, combined with significant rate volatility, means that companies with better market intelligence negotiate better rates, make smarter mode selection decisions, and respond faster to capacity changes.

DataResearchTools mobile proxies provide the reliable access needed to collect air cargo data from airline portals, digital freight platforms, and capacity databases across Southeast Asia. Build your monitoring system around the routes most critical to your business, and expand coverage as you demonstrate the value of data-driven air freight procurement.


Related Reading

last updated: April 3, 2026

Scroll to Top

Resources

Proxy Signals Podcast
Operator-level insights on mobile proxies and access infrastructure.

Multi-Account Proxies: Setup, Types, Tools & Mistakes (2026)