---
name: imf-portwatch-ingestion
description: "How to get IMF PortWatch data into a pandas DataFrame and Parquet: access, the request, the format, limits, quirks and terms."
---

# Load IMF PortWatch daily port-activity data into pandas and Parquet

Source entry: https://signal-lab-jet.vercel.app/datasets/imf-portwatch
Provider: https://portwatch.imf.org/pages/data-and-methodology
Checked against the provider's documentation: 2026-11-04

## Access
- No account or key. The ArcGIS feature layer returns JSON over HTTPS.

## Request
```bash
curl 'https://services9.arcgis.com/weJ1QsnbMYJlCHdG/arcgis/rest/services/Daily_Ports_Data/FeatureServer/0/query?where=1%3D1&outFields=*&returnGeometry=false&resultRecordCount=5&f=json'
```

## Format
ArcGIS FeatureServer JSON: a fields array (name, type, alias) and a features array of {attributes: {...}} records; date is esriFieldTypeDateOnly.

## Load into pandas and Parquet
Needs Python 3 with requests, pandas and pyarrow.
```python
"""IMF PortWatch Daily_Ports_Data sample -> pandas -> Parquet. No key.

Uses the public ArcGIS FeatureServer. Prefer a simple where=1=1 + outFields=*
query; some ArcGIS statistics/orderBy query shapes return a JSON error object
with HTTP 200 on these PortWatch tables.
"""
import requests
import pandas as pd

URL = (
    "https://services9.arcgis.com/weJ1QsnbMYJlCHdG/arcgis/rest/services/"
    "Daily_Ports_Data/FeatureServer/0/query"
)
params = {
    "where": "1=1",
    "outFields": "*",
    "returnGeometry": "false",
    "resultRecordCount": 5,
    "f": "json",
}
r = requests.get(URL, params=params, timeout=60)
r.raise_for_status()
payload = r.json()
if "error" in payload:
    raise RuntimeError(f"ArcGIS error: {payload['error']}")
features = payload.get("features") or []
df = pd.json_normalize([f.get("attributes", {}) for f in features])
df.to_parquet("imf_portwatch_ports_sample.parquet", index=False)
print(len(df), "port-day rows; sample:", df.iloc[0]["portname"], "on", df.iloc[0]["date"])

```
Run by us on 2026-11-04 (python 3.13.5 | pandas 3.0.6 | pyarrow 26.0.1 | requests 2.34.2). Result: 5 port-day rows; sample: Tsuruga on 2019-01-01

## Limits
- Rate limits: Not stated.
- Prefer simple where=1=1 and outFields=* queries; some ArcGIS statistics or orderBy query shapes return a JSON error object with HTTP 200 on these PortWatch tables.

## Quirks
- Daily_Ports_Data and Daily_Chokepoints_Data are hosted as ArcGIS tables (no geometry) on services9.arcgis.com under the IMF org weJ1QsnbMYJlCHdG.
- Always check the JSON body for an ArcGIS error object even when HTTP status is 200 before reading features.

## Terms and attribution
- IMF's Copyright and Usage terms require permission to copy or download IMF Content "in any systematic way" and a citation when reusing it.
- Email copyright@imf.org before any commercial reuse of IMF Data.
- Terms page: https://www.imf.org/en/about/copyright-and-terms

## Sources
- https://portwatch.imf.org/pages/data-and-methodology: "Our database includes 2065 ports and 28 major chokepoints globally."
- https://www.imf.org/en/about/copyright-and-terms: "IMF written permission must be obtained for other uses, including: Copying or downloading IMF Content in any systematic way."
- https://www.imf.org/en/about/copyright-and-terms: "For any potential commercial reuse of IMF Data, email copyright@imf.org to request permission."

## Help improve this skill
Missing a source, or see something to improve? Call the MCP tool suggest_source or feedback (or POST /api/suggest or /api/feedback). Reviewed ideas: https://signal-lab-jet.vercel.app/agent-suggestions

Information for educational purposes only. Free tiers, limits and licenses belong to the providers and may change; check the provider's own terms before using the data.
