Custom Home Assistant integration for household parcel tracking via Ship24 universal tracking API.
- Track parcels across 1500+ carriers (DHL, DPD, Hermes, GLS, UPS, FedEx, Amazon, etc.) with a single API key
- Automatic carrier detection from tracking URLs
- Periodic status polling with configurable interval
- Deep links to carrier delivery preference pages (Abstellgenehmigung, etc.)
- Status change events for automations (door opener, notifications)
- Auto-cleanup of delivered parcels
- Get a free Ship24 API key (10 shipments/month) at https://dashboard.ship24.com
- Install as custom component in Home Assistant
- Add integration via UI β enter Ship24 API key
Register a new parcel for tracking.
# From tracking URL (carrier auto-detected)
action: parcel_tracker.add
data:
tracking_url: "https://www.dhl.de/de/privatkunden/dhl-sendungsverfolgung.html?piececode=1234567890123456"
description: "New keyboard"
# From tracking number
action: parcel_tracker.add
data:
tracking_number: "1234567890123456"
carrier: "DHL"action: parcel_tracker.remove
data:
tracking_number: "1234567890123456"Fired when a new parcel is registered. Includes the carrier's preference URL for delivery options.
Fired on every status transition.
event_data:
tracking_number: "1234567890123456"
carrier: "DHL"
old_status: "in_transit"
new_status: "out_for_delivery"
eta: "2026-05-08"
preference_url: "https://www.dhl.de/..."
tracking_url: "https://www.dhl.de/..."The integration creates one sensor entity per tracked parcel. You can view them via Settings β Devices & Services β Parcel Tracker or build a Lovelace dashboard card:
Auto-entities card (shows all active parcels)
Requires auto-entities from HACS:
type: custom:auto-entities
card:
type: entities
title: π¦ Parcels
show_header_toggle: false
filter:
include:
- entity_id: sensor.parcel_*
options:
type: custom:template-entity-row
state: "{{ state_attr(config.entity, 'carrier') }}: {{ states(config.entity) | replace('_', ' ') | title }}"
secondary: >
{{ state_attr(config.entity, 'tracking_number')[:12] }}β¦
{% if state_attr(config.entity, 'eta') %} Β· ETA {{ state_attr(config.entity, 'eta') }}{% endif %}
tap_action: |
{
"action": "url",
"url_path": "{{ state_attr(config.entity, 'tracking_url') }}"
}
sort:
method: state
reverse: true
show_empty: falseSimple entities card (no extra dependencies)
Manually list your parcel sensors (they appear/disappear as parcels are added/removed):
type: entities
title: π¦ Parcels
entities:
- type: custom:template-entity-row
entity: sensor.parcel_dhl_3456
state: "{{ state_attr('sensor.parcel_dhl_3456', 'carrier') }}: {{ states('sensor.parcel_dhl_3456') | replace('_', ' ') | title }}"
secondary: "ETA: {{ state_attr('sensor.parcel_dhl_3456', 'eta') }}"
tap_action: |
{
"action": "url",
"url_path": "{{ state_attr(config.entity, 'tracking_url') }}"
}Or use the built-in entity filter card for a zero-config list:
type: entity-filter
entities:
- sensor.parcel_dhl_3456
- sensor.parcel_dpd_7890
state_filter:
- registered
- in_transit
- out_for_deliveryNotify to set delivery preferences (Abstellgenehmigung)
When a new parcel is registered, send a notification with a direct link to set your drop-off preference on the carrier's website:
automation:
- alias: "Notify to set delivery drop-off"
triggers:
- trigger: event
event_type: parcel_tracker.parcel_added
conditions:
- condition: template
value_template: "{{ trigger.event.data.preference_url != '' }}"
actions:
- action: notify.mobile_app_your_phone
data:
title: "π¦ New parcel registered"
message: >
{{ trigger.event.data.carrier }} parcel added.
Set your Abstellgenehmigung now!
data:
url: "{{ trigger.event.data.preference_url }}"
actions:
- action: URI
title: "Set drop-off location"
uri: "{{ trigger.event.data.preference_url }}"Notify parcel in transit
automation:
- alias: "Notify parcel in transit"
triggers:
- trigger: event
event_type: parcel_tracker.status_changed
event_data:
new_status: in_transit
actions:
- action: notify.mobile_app_your_phone
data:
title: "π¦ Parcel on the way!"
message: "{{ trigger.event.data.carrier }} parcel is in transit (ETA: {{ trigger.event.data.eta }})"
data:
url: "{{ trigger.event.data.tracking_url }}"Share tracking links from your phone
The integration registers a webhook automatically β no HA automation needed. Just point your phone's share shortcut at:
POST https://<ha-external-url>/api/webhook/parcel_tracker_register
JSON body:
{"url": "<tracking-url>", "device": "<phone-name>"}Android step-by-step using HTTP Shortcuts (F-Droid / Play Store):
- Open the app β tap + (bottom-right) β Regular Shortcut
- Basic Request Settings
- Name:
Track Parcel - Method: POST
- URL:
https://<your-ha-url>/api/webhook/parcel_tracker_register
- Name:
- Request Body / Payload
- Tap Request Body β select Custom Text
- Content Type:
application/json - In the body text field, enter:
{"url": "{share_text}", "device": "my-pixel"}{share_text}is a built-in variable β the app replaces it automatically with whatever text is shared. Don't create a variable for it; just type it literally.Replace
my-pixelwith whatever name you want to identify this phone.
- Trigger from Share Sheet (Android 11+)
- Go back to the shortcut's main settings screen
- Tap Trigger & Execution Settings (β‘ icon)
- Enable "Accept shared text from other apps"
- You may need to restart HTTP Shortcuts (or reboot) for Android to register the new share target
- Save the shortcut (β top-right)
Usage (Android 11+): Share a tracking link β pick HTTP Shortcuts β select Track Parcel.
Alternative: older Android / home-screen shortcut (no share sheet)
If your device doesn't support the share-into feature (Android < 11), use a dialog variable instead:
- In HTTP Shortcuts, open Variables (drawer menu) β + β Text Input
- Variable key:
tracking_url - Title:
Tracking URL
- Variable key:
- Create the shortcut as above, but use this body:
{"url": "{tracking_url}", "device": "my-phone"} - Place the shortcut on your home screen (long-press shortcut β "Place on home screen" / use the widget picker)
- To use: copy the tracking link β tap the home-screen shortcut β paste β confirm
iOS β use the built-in Shortcuts app with a "Get Contents of URL" action (POST, same JSON body). Add the shortcut to your Share Sheet.
Open door for parcel delivery
alias: Open door for parcel delivery
triggers:
- entity_id: binary_sensor.doorbell_bell_signal
to: "on"
trigger: state
conditions:
- condition: template
value_template: >
{{ states.sensor
| selectattr('entity_id', 'match', 'sensor.parcel_.*')
| selectattr('state', 'in', ['in_transit', 'out_for_delivery'])
| selectattr('attributes.eta', 'eq', now().strftime('%Y-%m-%d'))
| list | count > 0 }}
actions:
- action: switch.turn_on
target:
entity_id: switch.doorbell_door_openerEach tracked parcel becomes a sensor entity:
- State:
registered|in_transit|out_for_delivery|delivered|failed_attempt|exception|unknown - Attributes:
carrier,tracking_number,eta,registered_by,registered_at,last_api_update,tracking_url,preference_url,description
Via UI (Settings β Integrations β Parcel Tracker β Configure):
| Option | Default | Description |
|---|---|---|
| Cleanup days | 3 | Days after delivery before auto-removal (1-30) |
| Scan interval | 2h | How often to poll Ship24 for updates (1-12h) |
Carrier preference links
| Carrier | Preference Page |
|---|---|
| DHL | Sendungsverfolgung β Empfangsoptionen |
| DPD | PaketankΓΌndigung |
| Hermes | Sendungsinformation |
| GLS | FlexDeliveryService |
| UPS | My Choice |
| FedEx | Delivery Manager |
| Amazon | Order History |
URL auto-detection patterns
| Carrier | URL Pattern |
|---|---|
| DHL | dhl.de, nolp.dhl.de |
| DPD | dpd.de, tracking.dpd |
| Hermes | myhermes.de, hermesworld |
| GLS | gls-group.com, gls-pakete |
| UPS | ups.com |
| FedEx | fedex.com |
| Amazon | amazon.de/progress-tracker |
# Run tests
uv run pytest tests/ -v
# Lint
uv run ruff check . && uv run ruff format --check .- Home Assistant 2024.1+
- Ship24 API key (free plan: https://dashboard.ship24.com)
- HTTP Shortcuts app on Android phones (for share sheet integration)