📦 Part of ha-parcel-integrations, a family of package-tracking integrations for Home Assistant that all publish the same parcel format, statuses and events, so they plug into cross-carrier automations and the optional Parcel Aggregator. Browse the other carriers on the website.
💬 Questions or feedback? Join the discussion on the Home Assistant community.
A custom Home Assistant integration that tracks your DPD shipments — including shipments handled through BRT, DPD's brand name in Italy. Same operator, same myDPD backend; BRT is just DPD's public identity in that one country, so this integration answers to both names there.
- Features
- Requirements
- Installation
- Configuration
- Options
- Dynamic polling
- Removal
- Sensors
- Parcel status reference
- Events
- Examples
- Debugging
- Troubleshooting
- Related integrations
- Disclaimer
- Contributing
- License
- Incoming and outgoing active-parcel count sensors
- Per-parcel sensor per active incoming shipment, with full status details as attributes
- Optional per-parcel status history timeline (opt-in; off by default)
- Configurable delivered-parcels sensor (last N days, or N most recent)
- Automatic lifecycle management — per-parcel sensors are created and removed as parcels move through delivery
- Re-authentication support
- Country (business unit) selection during setup — Netherlands plus 14 other countries on DPD's shared myDPD backend (Argentina, Belgium, Croatia, Czech Republic, Estonia, France, Hungary, Italy, Latvia, Lithuania, Luxembourg, Portugal, Slovakia, Slovenia), the UK (riding on the same NL backend), and Germany, Poland, Austria and the UK MyDPD app (each its own separate backend), more to come
- UI translated into the language of every supported country (plus English), including the country dropdown itself
- A DPD account (the same credentials you use in the myDPD mobile app). For Germany, a myDPD account with an e-mail address and password; accounts that only sign in with Apple, Google, Facebook or netID are not supported.
This integration is available in the default HACS store.
- Open HACS, search for DPD and install it
- Restart Home Assistant if HACS asks you to
Or click the button below to open it directly in HACS:
- Copy the
dpdfolder into yourconfig/custom_components/directory - Restart Home Assistant
Or set it up by hand:
- Go to Settings → Devices & Services → Add Integration
- Search for DPD
- Pick your country, then enter its account credentials. Poland uses a mobile number and one SMS code; United Kingdom (MyDPD) uses a sign-in link from your email; every other country, Austria included, uses email and password.
- Choose how you want the delivered parcels sensor to filter (last N days, or N most recent)
- Click Submit
| Field | Description |
|---|---|
| Country | Choose the country before entering credentials. Netherlands and the other shared-backend countries use a DPD account email and password. Germany uses the email and password of your myDPD account at dpd.com, and Austria has its own backend, also with email and password. Poland uses a Polish nine-digit mobile number and a one-time SMS code; Home Assistant stores the refresh token only, never the SMS code. |
For Poland, the phone field accepts the local nine-digit form as well as
+48/0048 prefixes (with spaces or dashes). It normalizes every accepted
form to the nine digits expected by DPD Polska. The receiver inbox is read-only:
outgoing parcels are not requested.
United Kingdom (MyDPD) is for accounts that sign in to the DPD UK app
with an emailed link (the accounts United Kingdom (Business), which rides
on the shared myDPD backend, cannot log in). In the app, or at
login.dpd.co.uk, choose email sign-in, then copy
the full link from the email without opening it and paste it into the setup form.
The email address field is only needed for the link from the app; a
login.dpd.co.uk link needs none. The link works once and expires quickly. The account
needs a finished DPD UK consumer profile. Only parcels you receive are read.
Home Assistant keeps the sign-in refresh token, a generated device id and which
sign-in route was used, never the link. When the sign-in lapses, Home Assistant asks for a new link.
The UK MyDPD app source is a pre-release. Signing in and reading delivered parcels work on a real account, but a parcel on its way has not been seen yet. The integration shows the status, the sender, the tracking link, the weight of a single-parcel shipment, the expected delivery day and, with the history option on, the timeline. Delivered parcels are confirmed; the status of a parcel on its way and the timeline still await a real parcel. Please attach the integration's diagnostics to an issue, and report any warning it logs: it lists field names and codes, never values. The diagnostics keep the fields that describe the delivery and leave out everything about you, including the address, the tracking number and DPD's status sentence.
For Germany, the integration signs in to your myDPD account and reads its parcel list: the Empfang, Versand and Retoure tabs. It shows the status, the five daily steps DPD lists (data handed over, on the road, at the depot, in delivery, delivered), the weight and a link to the tracking page, with the delivery day for a parcel that is out for delivery (once DPD has shown one). It does not show times of day, locations, the sender or dimensions, and no sender or recipient names. Germany setups made before this change keep working without signing in again. If DPD asks for a captcha at login, Home Assistant cannot answer it: the integration logs a warning, keeps showing the last data and waits six hours between sign-in attempts. A reload does not retry sooner; signing in again through the integration's re-authenticate option (or re-adding it) does. Signing in once at dpd.com in your browser may clear it.
For Austria, use the email address and password of your mydpd.at account. If you created that account with Google, Facebook or Apple sign-in, it has no password and cannot be used here — set a password on the portal first, or use a different account. One poll reads incoming, sent and returned parcels together.
Austria is a pre-release. One real delivered parcel has been confirmed end to end, but several cases have not been seen yet: an active parcel (so the delivery window is unverified), a parcel waiting at a ParcelShop, a failed delivery and a return. The integration logs a warning with a link when it meets a status it cannot map — please report those; they are what makes the mapping precise.
Click Configure on the integration card. The form is split into two sections:
| Option | Description |
|---|---|
| Filter by | Days keeps delivered parcels visible for the last N days. Number of parcels keeps only the N most recent regardless of age. |
| Amount | The N used by the filter above. |
| Option | Description |
|---|---|
| Include status history | Adds a history attribute to each parcel — the ordered list of status updates (timestamp, canonical status, original DPD text), capped to the most recent 20. Off by default. The attribute is kept out of the recorder database. |
Polling isn't a setting here — instead of checking DPD at the same rate around the clock, the integration adjusts its own cadence to what your parcels are actually doing:
- Quiet hours — no polling between 00:00–06:00 local time, aside from one catch-up check at each end of that window (around midnight and around 6 AM), so an overnight update is never missed.
- Hot (every 15 minutes) — while any tracked incoming or outgoing parcel is out for delivery today, starting an hour before its delivery window opens (or immediately if no window is known yet).
- Normal (every 45 minutes) otherwise — this is also the minimum cadence, since it's the only way to discover a new shipment that appears on the account without going through Home Assistant. Delivered parcels never affect the cadence — only what's still in transit counts.
- A small, fixed per-install offset is added on top, so not every DPD installation out there polls at exactly the same second.
This applies to every backend the integration talks to — the general/myDPD one, DPD Germany and DPD Poland alike. Installs that were still on a fixed interval move over automatically — nothing to change. This is now the polling behaviour across the parcel-integrations suite, where the cadence is no longer a setting anywhere.
Standard HA removal applies: Settings → Devices & Services → DPD → ⋮ → Delete. No DPD-side cleanup is needed; deleting the config entry stops the polling. To revoke API access entirely, change your DPD account password — the integration will trigger a re-auth notification, which you can then ignore.
The integration creates one device per DPD account, named
DPD (<your-email>). With multiple accounts each gets its own device
named after its email. The entities below show the friendly-name pattern;
their entity_ids carry the same account suffix:
| Friendly name pattern | Description |
|---|---|
DPD (account) Incoming parcels |
Number of active incoming parcels |
DPD (account) Parcel <barcode> |
Canonical status of a single incoming shipment |
DPD (account) Next delivery |
Earliest expected delivery datetime |
DPD (account) En route to ParcelShop |
Active incoming parcels still in transit to a DPD ParcelShop |
DPD (account) Awaiting pickup |
Parcels that have arrived at a ParcelShop and are ready to collect |
DPD (account) Delivered parcels |
Recently delivered incoming parcels (configurable window) |
DPD (account) Outgoing parcels |
Number of active outgoing parcels |
DPD (account) Outgoing delivered parcels |
Recently delivered outgoing parcels (same configurable window) |
DPD (account) Deliveries |
Read-only calendar of expected deliveries, no extra API calls |
DPD (account) Last update |
Diagnostic timestamp of the last successful poll — alert on this if the integration goes silently stale |
A DPD (account) Deliveries calendar entity is also created, showing
expected delivery dates for active parcels — read-only, no extra API calls.
A DPD (account) Refresh button entity forces an immediate poll,
without waiting for the next scheduled interval.
Every parcel exposed on a sensor attribute uses a carrier-agnostic shape:
| Key | Type | Meaning |
|---|---|---|
carrier |
string | "DPD" |
barcode |
string | Parcel tracking number |
sender |
string | null | Sender name (e.g. webshop) |
receiver |
string | null | Recipient name. May briefly be null the first time a new barcode appears. |
status |
ParcelStatus |
Canonical status — see the status reference |
raw_status |
string | null | Original DPD status description |
delivered |
bool | Whether the parcel has been delivered |
delivered_at |
ISO 8601 | null | Delivery moment, if known |
planned_from |
ISO 8601 | null | Expected delivery window start (the precise hour on delivery day, otherwise midnight on the planned date) |
planned_to |
ISO 8601 | null | Expected delivery window end |
pickup |
bool | Destined for a pickup point rather than a home address |
pickup_point |
string | null | ParcelShop name when pickup is true (always null for now — DPD does not expose the field) |
url |
string | null | Deep link to the parcel's tracking page |
weight |
float | null | Parcel weight in kilograms |
dimensions |
dict | null | Parcel dimensions in centimeters: {length, width, height, text} where text is a pre-formatted "L x W x H cm" string |
history |
list | null | Ordered status timeline (oldest → newest), each entry {timestamp, status, raw_status}, capped to the most recent 20. null unless the Parcel history option is enabled — see Options. |
raw |
dict | The original DPD API payload |
status on every parcel is one of the canonical ParcelStatus values
below. Use these in your automations rather than DPD's raw description
strings — the raw value stays available on raw_status for power
users.
status |
Meaning | DPD raw description that maps here |
|---|---|---|
registered |
DPD knows about the label but the parcel is not yet in transit | ORDER_CREATED |
in_transit |
Picked up; somewhere in DPD's network | PARCEL_HANDED, IN_TRANSIT, AT_DELIVERY_CENTER, UNSUCCESSFUL_DELIVERY_ATTEMPT |
out_for_delivery |
On the delivery vehicle today | PARCEL_OUT_FOR_DELIVERY |
at_pickup_point |
Arrived at the ParcelShop, ready to collect | AVAILABLE_FOR_COLLECTION |
delivered |
Handed over (mailbox, recipient, neighbour, picked up) | DELIVERED |
returning |
Failed delivery, on the way back to the sender | RETURN_TO_SENDER |
problem |
Carrier reports an exception, intervention, or other issue | (not yet observed) |
unknown |
Raw description we have not mapped yet | anything else — logged once at warning level with a ready-to-paste issue link so it can be added to the map |
For Germany the status follows the furthest of the five daily steps DPD lists
for the parcel (data handed over is registered, on the road and at the depot
are in_transit, in delivery is out_for_delivery, delivered is delivered).
A parcel on its way back to the sender is returning even once it is delivered
back to them, so it never fires the delivered event.
The coordinator fires events on the HA event bus when something interesting happens to a parcel, so automations can react without polling per-parcel sensors.
| Event | When | Payload |
|---|---|---|
dpd_parcel_registered |
A new barcode appears in the active list | The full parcel dict (see the table above) |
dpd_parcel_status_changed |
A known barcode's canonical status value changes, except the final hop to delivered |
Same payload plus old_status and new_status |
dpd_parcel_delivered |
An incoming parcel is delivered | The full parcel dict |
dpd_parcel_delivery_time_changed |
A known barcode's expected delivery time changes to a new value | Same payload plus old_planned_from, new_planned_from, old_planned_to, new_planned_to |
dpd_outgoing_parcel_status_changed |
A known outgoing parcel (something you sent) changes status, except the final hop to delivered | Same payload plus old_status and new_status |
dpd_outgoing_parcel_delivered |
An outgoing parcel reaches the recipient | The full parcel dict |
Every payload also carries a device_id identifying the DPD account the
parcel belongs to, so automations can tell two accounts apart.
Events do not fire for parcels that were already in your account when HA first started.
If you build automations in the UI, these same events are also available as no-code device triggers (Settings → Automations → Create → Add trigger → Device), scoped to the selected account's device. The raw events above are there for templates and YAML automations.
See examples/automations/ for ready-to-paste
event-driven automations, or the
parcel aggregator
for a carrier-agnostic re-emit layer that fires
parcel_aggregator_parcel_* events covering every installed carrier
in one go.
Ready-to-paste automations and dashboard cards live in examples/.
Third-party cards that work with this integration's sensors:
To capture the raw DPD API response (useful when reporting a bug or helping map the shipment object structure), enable debug logging for the integration:
- Add this to your
configuration.yaml:logger: default: warning logs: custom_components.dpd: debug
- Restart Home Assistant.
- Wait for the next poll cycle (or reload the integration from Settings → Devices & Services → DPD → ⋮ → Reload).
- Open Settings → System → Logs, filter for
dpd, and copy theDPD raw parcels payload: ...line into your bug report or message to the maintainer.
The raw payload is only logged when there is at least one incoming or outgoing shipment.
| Symptom | Likely cause |
|---|---|
invalid_auth error during setup |
Wrong email or password |
captcha error during setup, or a captcha warning in the log |
DPD Germany is asking for a captcha at login. Sign in once at dpd.com in your browser, then try again |
cannot_connect error during setup |
DPD API is unreachable; check your network |
| Re-authentication prompt appears | DPD session expired and could not be refreshed silently; log in again |
| Sensors not updating | Check Settings → System → Logs for dpd entries |
This integration is part of ha-parcel-integrations — a family of parcel-carrier integrations that all publish the same canonical parcel format, statuses and events.
- Parcel Aggregator rolls every installed carrier up into one set of sensors.
- Browse the organisation for the current list of supported carriers.
This is an independent, community-built project. It is not affiliated with, endorsed by, sponsored by, or supported by DPD, Home Assistant, or any other third party referenced in this project. Please don't contact DPD for support with this integration.
All third-party trademarks, trade names, product names, logos, and other brand assets are the property of their respective owners. References to them are solely to identify the relevant carrier or service and do not imply affiliation, sponsorship, or endorsement. Nothing in this project grants or implies any licence or right to use third-party brand assets.
This integration may rely on public, unofficial, or undocumented carrier interfaces, accessed with your own account or API key where required. These may change or be withdrawn without notice and may be subject to DPD's terms. Data is sent only to DPD's own services or those of its group; this project operates no servers of its own. You are responsible for ensuring that your use complies with applicable law and those terms. Use is at your own risk; see the licence for warranty limitations.
Pull requests and issues are welcome. Please open an issue before submitting a large change.
MIT