Ocean Container Tracking
Overview
This skill queries sea freight shipment status through the local cargo-tracking
Python package. That package handles input recognition (ISO 6346 container check
digit, BL prefix routing), bounded multi-source orchestration (carrier sites +
aggregators), and a strict standardized result model. This skill is the
onboarding guide for driving it correctly and interpreting its output.
Core idea to internalize: the result model strictly separates two layers and
they must never be mixed:
result_status— did the query succeed? (success,partial_success,
no_result,source_failed,parse_failed,ambiguous,invalid_input,
unsupported_query_type)tracking_status— where is the shipment in its transport journey? Present
only whenresult_statusissuccessorpartial_success.
Never report a shipment as "delivered / not found / cleared" based on a failed
query. A failed query means "we could not get the data", not a business fact.
Prerequisites
The cargo-tracking package is bundled inside this skill under
bundled/cargo-tracking/ — no PyPI install and no local checkout is required.
The bundled scripts/track.py wrapper injects it onto the import path on first
run and installs only the lightweight runtime dependencies it needs
(httpx, pydantic). So a fresh user who installs this skill from the
marketplace gets a working setup with zero manual steps.
Verify the bundle is present and importable:
python -m cargo_tracking.cli info --json
# or, via the wrapper (auto-installs deps, keeps the credential-free scope):
python scripts/track.py info
Optional extras (only for broader coverage):
- --scope full (or python -m pip install -e "bundled/cargo-tracking[full]")
installs mcp + playwright for the JCTrans / aggregator carriers and the
Playwright-based official browser lookup.
- [ocr] extra (Pillow / numpy / easyocr) enables the T.S. Lines
OCR/CAPTCHA source.
- Some sources still need credentials via environment variables (see the carrier
/ aggregator directory), e.g. JC_USERNAME / JC_PASSWORD, SINAY_API_KEY,
TRACK123_API_SECRET, TERMINAL49_API_KEY. Without them those sources report
readiness != ready and are skipped — that is expected, not an error.
> Note: advanced users may set CARGO_TRACKING_SRC to point at their own
> cargo-tracking checkout instead of the bundled one; this is never required.
Coverage Scope (default: credential-free)
The most reliable out-of-the-box experience covers only carriers that need
no credentials. These work against public carrier APIs with zero setup:
| Carrier | Aliases | Interface |
|---|---|---|
| SITC | 海丰 | public JSON API |
| COSCO | COSU/COAU, 中远海运 | public JSON API |
| SNL / Sinotrans | SNL, 中外运 | public JSON API |
| Evergreen | EMC/EGLV, 长荣 | public HTML/AJAX |
(T.S. Lines 德翔 is also key-free but requires the [ocr] extra to solve its
CAPTCHA; include it only when that extra is installed.)
Everything else — Maersk, MSC, Hapag-Lloyd, CMA CGM, ONE, OOCL, ZIM, Yang Ming,
Wan Hai, and the 15 aggregator platforms — requires JC_USERNAME/JC_PASSWORD
or an aggregator API key. Without those, queries to them return source_failed
or are skipped, which is noisy and uninformative.
The bundled scripts/track.py wrapper enforces this with a scope flag:
--scope credential-free(default) — runs the real query only for references
whose routed source reports an emptyrequirementslist; otherwise it skips
the reference and prints guidance (which carrier, what credential, official
URL). This keeps the default path quiet and useful.--scope full— forwards every reference to the raw CLI unchanged; configure
the relevant credentials first or expectsource_failedfor gated carriers.
Detection is requirement-based (via route <REF> --json), not a hardcoded
allowlist, so any future key-free source is included automatically.
Standard Workflow
For a normal tracking request:
- Extract the reference number(s) from the user's message (container / BL /
booking). Do not guess or fabricate a number the user did not provide. - Run a single query through the bundled wrapper (default scope keeps the
path credential-free and quiet):
bash python scripts/track.py query <REFERENCE> --query-type auto
- The wrapper adds--jsonautomatically and honors--scope(see
"Coverage Scope" above). Use--scope fullonly when the user has
configured carrier/aggregator credentials and wants broader coverage.
- Leave--query-type autounless the user explicitly states the type.
- Default--query-mode fastis fine; usebalancedonly if fast yields
no_resultand the user wants a deeper attempt. (thoroughis accepted but
downgraded tobalanced.) - Interpret
result_statusfirst, then readtracking_statusonly if the
query succeeded. See "Interpreting Results" below. - Summarize for the user in their language (Chinese by default): the
shipment status, latest event + time + location, current vessel/voyage,
origin/destination ports, and ETA/ETD when present. Surfacewarningsand
needs_manual_reviewhonestly.
For batch requests (multiple numbers), use the wrapper so credential-gated
carriers are skipped with guidance instead of failing inline:
# Inline (credential-free by default; Hapag/Maersk/etc. are skipped + reported)
python scripts/track.py batch NUM1 NUM2 NUM3 --query-type auto
# Broaden to all sources once credentials are configured
python scripts/track.py batch NUM1 NUM2 NUM3 --query-type auto --scope full
# From a file (lines / json / csv auto-detected by extension)
python -m cargo_tracking.cli batch --input queries.csv --output result.json
python -m cargo_tracking.cli batch --input queries.txt --output result.jsonl --output-format jsonl
Note: when --input is used, the wrapper cannot pre-filter a file, so it
forwards everything to the CLI unchanged — configure credentials for any
non-free carriers present in the file.
Keep --max-concurrency modest (default 3, max 10) to stay bounded and avoid
hammering carrier sites.
When a Query Fails or Returns No Data
Do not stop at a bare failure. Use the diagnostic commands to give the user a
useful next step:
python -m cargo_tracking.cli route <REFERENCE> --json— shows which carrier /
source the number should route to, the official tracking URL, and the
recommended automation strategy.python -m cargo_tracking.cli carriers --json— carrier coverage, connected
source ids, credential requirements, and official-site query entry URLs.python -m cargo_tracking.cli aggregators --json— free / trial / commercial
aggregator sources and their constraints.python -m cargo_tracking.cli query-info --json— current source readiness and
V1 limitations (useful to explain why a source was skipped).python -m cargo_tracking.cli official-lookup <REFERENCE> --json— best-effort
Playwright browser lookup of the official carrier site when no stable API
exists. Returns page-visible evidence text that still needs human review before
becoming a business conclusion. Requires Playwright browsers installed.
Typical guidance to relay: "自动来源暂时查不到,可以到 <官网 URL> 用这个提单号人工再查一次"
plus the requirement note (e.g. needs SCAC / needs login).
Interpreting Results
Read references/result_schema.md for the full field-by-field schema, the enum
value meanings (all 11 tracking_status values and 16 EventCode values), and
how to phrase each result_status for the user. Load it whenever unsure how to
map a raw result to a human summary.
Key rules (do not violate):
- If
result_statusis a failure value,tracking_statusis absent — never
invent one, and never tell the user the cargo's business state. - If
needs_manual_reviewistrue, explicitly tell the user human/manual
verification is recommended and includemanual_review_reasons. short_summaryis always a non-empty plain string; it is a safe fallback line
to show, but prefer building a richer localized summary from the structured
fields.- Treat tracking output as reference visibility data, NOT as proof of
delivery / release / customs clearance. Do not use it as the sole basis for
releasing cargo or assigning liability.
MCP Alternative
If an MCP client is preferred over the CLI, the same package exposes an MCP
server via the cargo-tracking-mcp entry point, with tools: tracking_query,
tracking_query_batch, tracking_query_info, tracking_carrier_directory,
tracking_aggregator_directory, tracking_route_reference,
tracking_official_browser_lookup. Tool arguments mirror the CLI options above.
Reference Number Cheatsheet
- Container — 4 letters (owner + category U/J/Z) + 6 digits + 1 check digit,
e.g.TCKU3953453. Validated by ISO 6346 check digit; an invalid check digit
returnsinvalid_input. - BL (bill of lading) — carrier-specific prefixes, e.g.
HLCU…(Hapag),
COAU…/COSU…(COSCO),SIT[TD]…(SITC),799…(T.S. Lines),1[45][01]…
(Evergreen/EMC),SNLF…(Sinotrans). - Booking — no stable public source; queries commonly return unavailable /
source_failed. Set this expectation with the user.
See references/result_schema.md for the complete enum tables and phrasing
guidance.