# DHL Package Tracking Scraper (`muhammadafzal/dhl-package-tracking-scraper`) Actor

Track DHL packages and export current status, delivery estimates, routes, checkpoints, and service details as structured records.

- **URL**: https://apify.com/muhammadafzal/dhl-package-tracking-scraper.md
- **Developed by:** [Muhammad Afzal](https://apify.com/muhammadafzal) (community)
- **Categories:** Other, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 tracked dhl shipments

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## DHL Package Tracking Scraper

Track DHL packages by tracking number and return a compact, machine-readable record with the current status, latest checkpoint, estimated delivery, origin/destination, service, and event history. Use it for shipment visibility, customer-support workflows, logistics monitoring, and agent pipelines that need structured DHL tracking data.

### What it extracts

Each matched shipment becomes one default-dataset item with:

| Field | Description |
| --- | --- |
| `trackingNumber`, `shipmentId` | Requested ID and DHL's canonical shipment ID |
| `status`, `statusCode`, `description`, `statusTimestamp` | Current milestone and when DHL reported it |
| `estimatedDelivery` | DHL's ETA/date when available |
| `currentLocation` | Latest public checkpoint locality |
| `origin*`, `destination*` | Public country, postal code, and city fields |
| `service`, `productName`, `totalPieces` | DHL business unit/product and piece count |
| `events` | Normalized checkpoint history with timestamp, status, description, and location |
| `serviceUrl`, `sourceUrl`, `retrievedAt` | DHL links and retrieval provenance |
| `isDemoData`, `raw` | Demo marker and optional original shipment object |

Protected recipient details may require `recipientPostalCode`. DHL may omit fields when a shipment or service does not expose them.

### Input

`trackingNumbers` accepts one to ten DHL IDs. Spaces, commas, and semicolons are treated as separators, and IDs must contain only letters, numbers, or hyphens after normalization.

For real shipments, turn `demoMode` off. In `auto` mode, the Actor uses the official DHL Shipment Tracking - Unified API when `dhlApiKey` is supplied, otherwise it opens DHL's public tracking page in a consistent browser session. Set `accessMode` to `api` to require the API or `website` to require the public page.

The API route is the recommended production path. Request a Consumer Key for Shipment Tracking - Unified at [developer.dhl.com](https://developer.dhl.com/tracking), then paste it into the secret `dhlApiKey` input. The key is sent only in the `DHL-API-Key` header and is never written to logs, the dataset, or `SUMMARY`.

The default sample input uses DHL's documented sample ID `7777777770` with `demoMode: true`. DHL returns a mocked response for the special `demo-key`; this is intentionally labelled with `isDemoData: true` and must not be used as a real shipment lookup. `demoMode` rejects other tracking IDs so a forgotten demo setting cannot silently return unrelated data. The optional `recipientPostalCode` is ignored in demo mode because DHL's sample fixture does not model postal-code disambiguation; the Actor records that decision in `SUMMARY.warnings`.

#### Console example (real API)

```json
{
  "trackingNumbers": ["00340434292135100186"],
  "demoMode": false,
  "accessMode": "api",
  "dhlApiKey": "your-consumer-key",
  "language": "en",
  "requesterCountryCode": "US",
  "includeRaw": false
}
```

#### API example

```bash
apify call YOUR_USERNAME/dhl-package-tracking-scraper \
  --input '{"trackingNumbers":["00340434292135100186"],"demoMode":false,"accessMode":"api","dhlApiKey":"..."}' \
  --wait
```

Do not put a DHL key in a URL or a public README. Use the secret input or an environment-managed run payload.

### Output example

```json
{
  "trackingNumber": "7777777770",
  "shipmentId": "00340434292135100186",
  "service": "ecommerce",
  "productName": "DHL SM Parcel Plus Expedited",
  "statusCode": "delivered",
  "status": "DELIVERED",
  "description": "DELIVERED - PARCEL LOCKER",
  "statusTimestamp": "2023-05-08T10:37:00",
  "estimatedDelivery": null,
  "originCountryCode": "US",
  "originCity": "HEBRON",
  "destinationCountryCode": "US",
  "destinationCity": "HENDERSON",
  "currentLocation": "Henderson, NV, US",
  "totalPieces": 1,
  "events": [],
  "isDemoData": true,
  "raw": null
}
```

The complete run summary is stored as `SUMMARY` in the default key-value store. It includes requested, delivered, empty, blocked, and failed counts, the access route, warnings, and expected synthetic dataset-item events. A successful data run writes one automatically billable `apify-default-dataset-item` event per delivered record; the Actor does not manually double-charge results.

### Pricing and limits

| Event | Price |
| --- | ---: |
| Actor start | $0.00005 (synthetic) |
| Tracked DHL shipment | $0.02 per dataset record (synthetic) |

Examples: one matched shipment costs up to $0.02005 in events; ten matched shipments cost up to $0.2005. Empty, blocked, rejected, and failed lookups write no result records and therefore incur no result event. Apify may also account for the platform resources selected for a run. The Actor processes at most ten tracking numbers and deliberately spaces multi-number API calls to respect DHL's initial one-call-per-five-seconds limit.

### Reliability and failure behavior

The Actor uses DHL's first-party API when authorized, with bounded 30-second request timeouts and no fabricated records. Website mode uses a single consistent browser session and an Apify Proxy configuration by default; 403/428/429 responses and challenge pages are classified as `blocked`. A valid ID with no shipment is `empty`, malformed combinations are `rejected`, and upstream/runtime problems are `failed`. Partial valid results are preserved, and every skipped request is listed in `SUMMARY`.

Tracking events commonly appear 24–48 hours after DHL receives an ID. DHL's API and public tracking pages may limit destination or recipient information for privacy. A postal code can only be supplied for one shipment at a time in this Actor, matching DHL's protected-detail behavior.

### Data-use note

Use tracking data only for legitimate shipment-tracking purposes and comply with DHL's developer terms, applicable privacy law, postal secrecy, and your data-retention obligations. Obtain any required sender/recipient consent. DHL's published Unified Tracking terms require appropriate attribution and may require deleting tracking data after delivery; review the current terms before redistributing results. Do not combine tracking data with advertising or use this Actor to bypass authentication, CAPTCHAs, paywalls, or other access controls.

### Related use

This Actor tracks DHL IDs and returns shipment status. It does not create labels, calculate rates, download proof-of-delivery documents, or monitor push notifications. Use DHL's authorized APIs directly for those workflows.

# Actor input Schema

## `trackingNumbers` (type: `array`):

Use this to track 1–10 DHL shipment IDs. Enter one ID per row, for example 7777777770. Separators and surrounding spaces are removed; IDs shorter than 5 characters are rejected.

## `demoMode` (type: `boolean`):

Use this only with DHL's documented sample ID 7777777770 to return DHL's mocked API response without credentials. Turn it off for real packages.

## `accessMode` (type: `string`):

Use auto to prefer the official API when a key is supplied and otherwise use DHL's public tracking page. API requires a DHL key; website uses a browser and can be challenged.

## `dhlApiKey` (type: `string`):

Use this for reliable real-package tracking through DHL Shipment Tracking - Unified. Paste the Consumer Key from developer.dhl.com; it is never written to output or logs.

## `recipientPostalCode` (type: `string`):

Use this when DHL requires destination verification or when you need protected destination details. Supply one postal code that applies to the single requested shipment.

## `language` (type: `string`):

Use this for localized DHL status descriptions. Enter a two-letter ISO 639-1 code such as en or de; the default is en.

## `requesterCountryCode` (type: `string`):

Use this to localize public tracking behavior. Enter a two-letter ISO 3166-1 code such as US or DE; the default is US.

## `includeRaw` (type: `boolean`):

Use this for debugging or fields not yet normalized. It can significantly enlarge each result; the default false keeps output compact.

## `proxyConfiguration` (type: `object`):

Use this for website mode when DHL challenges direct cloud traffic. Apify Proxy is enabled by default; API and demo modes do not need it.

## Actor input object example

```json
{
  "trackingNumbers": [
    "7777777770"
  ],
  "demoMode": true,
  "accessMode": "auto",
  "recipientPostalCode": "",
  "language": "en",
  "requesterCountryCode": "US",
  "includeRaw": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

Schema-validated shipment records in the default dataset.

## `summary` (type: `string`):

Counts, access route, warnings, and result-charge diagnostics.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("muhammadafzal/dhl-package-tracking-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("muhammadafzal/dhl-package-tracking-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call muhammadafzal/dhl-package-tracking-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,muhammadafzal/dhl-package-tracking-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/kIrai96paWkMltvtc/builds/g5JVE1Yg8ehPVED5c/openapi.json
