---
title: "Supply chain intelligence"
description: "Supply chain intelligence from the web: container tracking from Maersk, MSC and CMA CGM, supplier catalogs and stock, and disruption notices, as JSON."
canonical: https://www.zenrows.com/use-cases/supply-chain-intelligence
updated: 2026-10-18
---

# Supply chain intelligence

Supply chain intelligence turns outside signals into early warnings about your shipments and suppliers: container milestones, supplier stock and lead times, and disruption notices. Zenrows reads carrier tracking pages, supplier sites and port notices through protected access, clicks through tracking flows in a cloud browser, and returns each update as JSON for your visibility platform.

## Sample output: one container's journey

```json
{
  "container": "EXMU1234565",
  "bill_of_lading": "EXBL0098123",
  "carrier": "Example Ocean Line",
  "size_type": "40HC",
  "status": "in_transit",
  "pol": { "port": "Ningbo", "unlocode": "CNNGB" },
  "pod": { "port": "Hamburg", "unlocode": "DEHAM" },
  "eta_pod": "2026-11-18",
  "eta_changed_from": "2026-11-14",
  "events": [
    { "time": "2026-10-02T09:40:00+08:00", "event": "gate_in_empty_return", "location": "Ningbo" },
    { "time": "2026-10-05T22:10:00+08:00", "event": "loaded", "location": "Ningbo", "vessel": "EXAMPLE TRADER", "voyage": "531W" },
    { "time": "2026-10-06T04:30:00+08:00", "event": "vessel_departed", "location": "Ningbo" },
    { "time": "2026-10-16T13:05:00+08:00", "event": "transshipment_discharged", "location": "Singapore" }
  ],
  "checked_at": "2026-10-17T06:00:00Z"
}
```

An illustrative container record built from one carrier tracking page; `eta_changed_from` is what your pipeline sets when a run sees a new ETA.

## What supply chain intelligence covers

Supply chain intelligence teams watch three things outside their own systems: where shipments are, whether suppliers can deliver, and what is about to disrupt either. Most of it is on public carrier, supplier and port websites before it reaches an EDI feed or a news alert.

| Job | Data you collect | Typical sources |
|---|---|---|
| Ocean container tracking | Gate in, loaded, departed, transshipment, discharged and gate out events, vessel, ETA | Maersk, MSC, CMA CGM, Hapag-Lloyd, COSCO, ZIM, HMM tracking pages |
| Bill of lading history | The full event history per BL, for trade data, demurrage disputes and claims | Carrier tracking and BL lookup pages |
| Parcel shipment status | Scans, exceptions, delivery estimate, proof of delivery | FedEx, UPS, DHL, USPS tracking pages |
| Supplier monitoring | Product lines, certifications, price lists, lead times, ownership and address changes | Supplier websites, Thomasnet, Alibaba, Made-in-China, Global Sources |
| Component availability | Stock on hand, factory lead time, minimum order, price breaks | Mouser, Digi-Key, Arrow and other distributor sites |
| Disruption signals | Port closures and congestion notices, service suspensions, supplier fires, strikes and recalls | Port authority notices, carrier advisories, news sites, regulator recall lists |

## Why carrier tracking scraping breaks

Container tracking is high volume and time sensitive, and the carriers change their security often. A tracking feed that misses a day hands your customers a stale ETA.

| What breaks | What it looks like | How Zenrows handles it |
|---|---|---|
| Carrier bot protection | Cloudflare Turnstile, fingerprinting or CAPTCHAs on tracking pages; success drops overnight after a carrier change | Zenrows' stealth gets through Cloudflare Turnstile, CAPTCHAs and similar protections, maintained by Zenrows instead of your team |
| History behind a click | The event list only loads after "show details" or a location history tab, and that step is the one that gets blocked | A [Browser](/products/browser) session runs the clicks with Playwright or Puppeteer |
| Tracking page redesigns | Your parser returns empty events for days while someone rewrites it | Extract returns events and dates as fields without selectors |
| Daily volume | Tens of thousands of containers to re-check before the morning ETA report | Batch takes the whole container list as one job, results by webhook |
| Thousands of small supplier sites | One-off layouts, many with no sitemap | [Crawl](/products/crawl) each supplier domain and read pages with Extract |
| Regional supplier and marketplace pages | Prices, stock and currency change by country | Geotargeting reads each page from the market you buy in |

## How to build supply chain intelligence with Zenrows

1. **Split sources by flow.** Carriers that show tracking events on one URL go to Fetch and Batch. Carriers that need a search and a click go to Browser.
2. **Track every active container.** Submit container or BL numbers as Batch tasks with the number as `external_id`, so each result joins back to your shipment.
3. **Store events, then diff.** Keep each run's events and ETA, and alert when a new milestone or a changed ETA appears.
4. **Add supplier and disruption sources.** Crawl supplier sites and distributor pages weekly, and fetch port and carrier notice pages daily.

```javascript Node.js
// Tracking flow that needs a search and a click, in a Zenrows cloud browser
import { chromium } from "playwright";

const browser = await chromium.connectOverCDP(
  "wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY"
);
const page = await browser.newPage();
await page.goto(TRACKING_URL);
await page.fill("#tracking-number", "EXMU1234565");
await page.click("button[type=submit]");
await page.click("text=Show location history");
await page.waitForSelector(".event-row");

const events = await page.$$eval(".event-row", (rows) =>
  rows.map((row) => row.innerText.trim())
);
console.log(events); // selectors are illustrative; match them to the carrier
await browser.close();
```

```python Python
# Re-check every active container as one Batch job
import requests

containers = ["EXMU1234565", "EXMU7654321", "EXMU2468135"]
payload = {
    "type": "regular",
    "status": "closed",
    "zenrows_params": {"mode": "auto", "extract": "auto"},  # Adaptive Stealth Mode
    "tasks": [
        {"url": f"{TRACKING_URL_PREFIX}{number}", "external_id": number}
        for number in containers
    ],
}
response = requests.post(
    "https://async.api.zenrows.com/v1/jobs",
    headers={"X-API-Key": "YOUR_ZENROWS_API_KEY"},
    json=payload,
)
print(response.json()["job_id"])
```

```bash CLI
npx -y @zenrows/cli init
# One tracking page as structured events
zenrows extract TRACKING_URL --autoparse
# Every active container: one {"url": "..."} per line
zenrows batch create containers.jsonl --wait
zenrows batch results JOB_ID --out tracking.jsonl
```

```text Claude Code (MCP)
# Connect once
claude mcp add zenrows -e ZENROWS_API_KEY=YOUR_ZENROWS_API_KEY -- npx -y @zenrows/mcp

# Then ask:
Use Zenrows to check these five supplier websites and their Thomasnet profiles. For each supplier, list ISO certifications, stated lead times, plant locations, and any news of closures, recalls or ownership changes.
```

## Which Zenrows product fits

| If you need to | Use | Why |
|---|---|---|
| Read a tracking page that shows events on one URL | [Fetch](/products/fetch) | One request with Adaptive Stealth Mode returns the events |
| Run a tracking flow with a search and clicks | [Browser](/products/browser) | Your Playwright or Puppeteer code drives a cloud browser over CDP |
| Get events and supplier facts as fields | [Extract](/products/extract) | Automatic structured extraction returns data that holds up when a page is redesigned |
| Re-check thousands of containers every few hours | [Batch](/products/batch) | One job per polling cycle, each result tagged with its container number |
| Let an analyst research a supplier in plain English | [MCP Server](/mcp) | Claude or Cursor fetches supplier pages through Zenrows as a tool |

## What success looks like

| Measure | What good looks like | How to check it |
|---|---|---|
| Tracking coverage | Every active container returns a current status on each cycle | Share of active containers with a successful result in the last run |
| Milestone latency | A carrier event reaches your data within one polling interval | Compare the event timestamp with the time you stored it |
| ETA change capture | Every published ETA change is recorded with its old and new date | Count voyages where the ETA moved and check each has a change record |
| Carrier success over time | Per-carrier success stays steady through carrier security changes | Track successful requests per carrier per day |
| Disruption lead time | Alerts fire before affected shipments reach the port | Compare alert time with the arrival date of affected containers |
| Cycle run time | Each polling cycle finishes before the next one starts | Log start and end time of each Batch job against the polling interval |

## Supply chain intelligence FAQ

### What is supply chain intelligence?

Supply chain intelligence is the practice of collecting outside data about shipments, suppliers and risks, and turning it into decisions: rebook a late container, find a second supplier, warn a customer before a delay reaches them. Web data covers the carriers, suppliers and ports that do not send you a feed.

### Why scrape carrier websites when EDI and carrier APIs exist?

Carrier websites often show an event before it reaches EDI, and they cover carriers you have no integration or data partnership with. Web data fills gaps in EDI and adds a new carrier in days instead of an integration project. Keep both sources and reconcile them per container.

### Can I build a multi-carrier container tracking API with Zenrows?

Yes. Put a thin API in front of Zenrows that maps a container or BL number to the right carrier's tracking URL, fetches it, and normalizes the events into one schema. Use Fetch for single-page tracking and Browser for carriers that need clicks, and run scheduled refreshes through Batch.

### How do I track containers across Maersk, MSC, CMA CGM and Hapag-Lloyd?

Each carrier has its own tracking page and protection. Fetch each one with Adaptive Stealth Mode, and use a Browser session where the event history sits behind a click. Map the events to a shared set of milestones such as loaded, departed, discharged and gate out.

### How often should container status be refreshed?

A common cadence is to poll active containers every few hours and increase the rate as a vessel nears port, when discharge and gate out events matter most. Containers already delivered can drop out of the job. Polling only what is active keeps each cycle in line with your shipment count.

### What container tracking data can I collect?

Whatever the carrier shows a shipper on its tracking page: container number and type, booking or BL reference, vessel and voyage, port of loading and discharge, each event with its location and timestamp, and the current ETA. Store the carrier, fetch time and source URL with every record, and keep the raw event text so you can remap milestones later.

### How do I monitor suppliers for risk?

Crawl each supplier's website and marketplace profile on a schedule and diff the results for changed certifications, addresses, product lines and contact details. For news of fines, labour violations or fraud tied to a supplier, see adverse media screening .

## Related use cases

- [Logistics data scraping](https://www.zenrows.com/use-cases/logistics-data.md): Vessel schedules, freight rates, surcharges and terminal status from carrier and port websites, for forwarders.
- [Adverse media screening](https://www.zenrows.com/use-cases/adverse-media-screening.md): Negative news on customers, directors and suppliers from global and local sources, with text and screenshots as evidence.

Start free: https://app.zenrows.com/register. Docs: https://docs.zenrows.com
