Posted in

Track your DHL Parcels in Home Assistant

Updated May 2026 — the integration is now a proper Home Assistant custom component, no Multiscrape required.

If you’re like me and rely heavily on Home Assistant to keep your smart home organized, you probably also want to track your incoming parcels alongside your automations. For quite some time, I used the PostNL integration in Home Assistant. It started as a core integration but eventually broke due to security restrictions on PostNL’s side. Later, it came back to life via a custom integration—only to break again when PostNL tightened their API access.

These days, PostNL tracking works again thanks to a browser extension for authentication, and it has been stable enough for me to get parcel updates reliably.

However, only about 50% of my packages are handled by PostNL. The other 50% typically come via DHL, with the occasional delivery from DPD or UPS. So naturally, I also wanted my DHL packages to show up in Home Assistant, providing a more complete overview of what’s on the way to my doorstep.

What You’ll Need

Note: The DHL API used here is unofficial (reverse-engineered). Any changes on DHL’s side can break this setup without warning.

Installation

  1. Open HACS in Home Assistant and go to Integrations.
  2. Click the three-dot menu (top right) → Custom repositories.
  3. Add https://github.com/peternijssen/ha-dhl-nl as an Integration.
  4. Search for DHL NL and install it.
  5. Restart Home Assistant.

Configuration

After restarting, go to Settings → Devices & Services → Add Integration and search for DHL NL.

You will be asked for your DHL account email address and password. The integration validates your credentials against the live API before saving. If you use multiple DHL accounts, you can add the integration multiple times.

No YAML configuration is needed.

Sensors

The integration creates the following sensors per account:

SensorDescription
DHL Incoming ParcelsCount of active incoming parcels. The parcels attribute contains the full list with sender, barcode, status, and delivery window.
DHL Outgoing ParcelsCount of active outgoing shipments. The shipments attribute contains the full list with recipient, destination, and status.
DHL Next DeliveryTimestamp of the earliest expected delivery across all active parcels. Useful for automations like “notify me 1 hour before delivery”.
DHL Parcels En Route to ServicePointCount of parcels being shipped to a DHL ServicePoint (not yet arrived).
DHL Parcels Awaiting PickupCount of parcels that have arrived at a ServicePoint and are ready for collection.
DHL Parcel <barcode>One sensor per active parcel. State is the parcel status; all parcel details are in the attributes. These sensors are automatically created and removed as parcels come and go.

The integration polls the DHL API every 30 minutes.

Dashboard Card

Here is a Markdown card that shows your incoming parcels in a table:

- type: markdown
  content: >
    {% set parcels = state_attr('sensor.dhl_incoming_parcels', 'parcels') %}
    {% if parcels and parcels | count > 0 %}
    | Carrier | Sender | Expected |
    |---|---|---|
    {% for p in parcels %}
    | DHL | {{ (p.sender or {}).get('name', 'Unknown') }} | {{ (p.receivingTimeIndication or {}).get('moment', 'Unknown') | as_datetime | as_local if (p.receivingTimeIndication or {}).get('moment') else 'Unknown' }} |
    {% endfor %}
    {% else %}
    No active DHL parcels.
    {% endif %}

And a conditional card that only shows up when there are parcels to pick up at a ServicePoint:

- type: conditional
  conditions:
    - condition: numeric_state
      entity: sensor.dhl_parcels_awaiting_pickup
      above: 0
  card:
    type: entities
    title: DHL Pickup Ready
    entities:
      - sensor.dhl_parcels_awaiting_pickup

Automations

Because DHL Next Delivery is a proper timestamp sensor, you can trigger automations relative to it:

automation:
  - alias: "DHL delivery reminder"
    trigger:
      - platform: template
        value_template: >
          {% set next = states('sensor.dhl_next_delivery') | as_datetime %}
          {% if next %}
            {{ (next - now()).total_seconds() < 3600 }}
          {% else %}
            false
          {% endif %}
    action:
      - service: notify.mobile_app_your_phone
        data:
          message: "DHL delivery start expected within the hour!"

Notes

  • The integration uses the same unofficial API that the DHL eCommerce app uses. It has been working reliably but is not officially supported by DHL.
  • For issues or feature requests, visit the GitHub repository.

Conclusion

Once the integration is running, you rarely think about it. DHL shipments appear in Home Assistant automatically, the dashboard card keeps the status visible, and the automation handles the notification at the right moment. No need to check tracking emails or open an app.

The integration covers the most common scenarios without any YAML configuration. If you also receive PostNL packages, the PostNL integration works the same way and sits neatly alongside it.

Join the discussion in the Home Assistant Community to see other implementations suggested by others.

6 thoughts on “Track your DHL Parcels in Home Assistant

  1. Hi,

    I keep getting error 400, does the DHL scrapping work for you ?

    Deze fout is ontstaan door een aangepaste integratie.

    Logger: custom_components.multiscrape.coordinator
    Bron: custom_components/multiscrape/coordinator.py:174
    integratie: Multiscrape (documentatie, problemen)
    Eerst voorgekomen: 11:37:25 (3 gebeurtenissen)
    Laatst gelogd: 13:25:14

    DHL packages # Updating failed with exception: Client error ‘400 Bad Request’ for url ‘https://my.dhlecommerce.nl/receiver-parcel-api/parcels’ For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400

    thanks,
    Rien

  2. My status remains unavailable

    This is what my log says:
    This error occurred due to a custom integration.

    Logger: custom_components.multiscrape.coordinator
    Source: custom_components/multiscrape/coordinator.py:174
    Integration: Multiscrape (documentation, issues)
    First occurred: 3:10:28 PM (1 event)
    Last logged: 3:10:28 PM

    Scraper_noname_1 # Updating failed with exception: Client error ‘400 Bad Request’ for url ‘https://my.dhlecommerce.nl/receiver-parcel-api/parcels’. For more information, check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400

  3. Hi Peter,

    Thanks for sharing the knowledge regarding Multiscraper. I did had the same issue like Rien and Rene did, but Gemini helped out:

    multiscrape:
    – name: DHL Tracker
    resource: “https://my.dhlecommerce.nl/receiver-parcel-api/parcels”
    scan_interval: 1800
    log_response: True
    # The form_submit block handles the login and keeps the session alive
    form_submit:
    submit_once: True
    resource: “https://my.dhlecommerce.nl/api/user/login”
    method: “post”
    headers:
    Content-Type: “application/json”
    # Adding a User-Agent helps bypass basic bot detection
    User-Agent: “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36”
    payload: ‘{“email”:”EMAIL”,”password”:”PASSWORD”}’
    sensor:
    – unique_id: dhl_packages
    name: DHL Pakketten
    value_template: “{{ value_json.parcels | selectattr(‘category’, ‘search’, ‘(PROBLEM|CUSTOMS|DATA_RECEIVED|EXCEPTION|INTERVENTION|IN_DELIVERY|LEG|UNDERWAY|UNKNOWN)’) | list | count }}”
    attributes:
    – name: parcels
    value_template: “{{ value_json.parcels | selectattr(‘category’, ‘search’, ‘(PROBLEM|CUSTOMS|DATA_RECEIVED|EXCEPTION|INTERVENTION|IN_DELIVERY|LEG|UNDERWAY|UNKNOWN)’) | list }}”

    In my error log I had this:
    Invalid value for: cookie X-AUTH-TOKEN (missing)

Leave a Reply

Your email address will not be published. Required fields are marked *