A Home Assistant custom integration that turns any public Unsplash collection into a rotating image entity. Use the entity as a dashboard background, a WallPanel slideshow source, a View Assist background, or anywhere else an image entity is supported.
Unsplash deprecated
source.unsplash.comin late 2021 and it's been intermittent since 2024. This integration uses the official Unsplash API instead — stable, supported, and rate-limit aware.
- Configure once with your free Unsplash Access Key
- Add as many collections as you want — each becomes its own
imageentity - Per-collection refresh intervals — fast-rotating photo streams alongside slow-rotating art collections, all under one integration
- Per-collection orientation — set landscape, portrait, or squarish on a per-collection basis (or inherit the global default)
unsplash.refreshservice — trigger an immediate photo change from automations, scripts, or Developer Tools- Exposes photographer name and profile URL as state attributes (required for Unsplash attribution)
- Fires Unsplash's per-photo download-tracking endpoint automatically — keeps you compliant with the API Guidelines
- Diagnostics support — download config + last-state JSON straight from the integration card
- Open HACS in Home Assistant
- Click the ⋮ menu → Custom repositories
- Add
https://github.com/dkedinger/ha-unsplashas an Integration - Find "Unsplash" in the HACS list and install
- Restart Home Assistant
- Download this repo and copy
custom_components/unsplash/into your HAconfig/custom_components/directory - Restart Home Assistant
- Go to unsplash.com/developers and create a free account
- Click New Application, accept the API terms, and give it a name (e.g. "Home Assistant")
- Copy the Access Key (not the Secret Key)
Demo applications are rate-limited to 50 requests/hour. With the default 15-minute refresh interval, you can run ~10 collections comfortably. Apply for production access in your Unsplash dashboard to raise this to 5000/hour.
- Settings → Devices & Services → Add Integration → Unsplash
- Paste your Access Key. The integration validates it against the API and rejects bad keys immediately.
- On the integration card, click Configure
- Choose Add a collection
- Enter a Collection ID. This is the number at the end of the collection URL — e.g. for
https://unsplash.com/collections/8975107, the ID is8975107 - Optionally provide a display name (otherwise the collection's title from Unsplash is used)
Each collection creates a single image entity, e.g. image.unsplash_morning_blue.
From the same Configure menu:
- Default refresh settings — sets per-integration defaults (refresh interval, orientation) that apply to any collection without its own override. Default is 900 seconds (15 minutes), landscape.
- Edit a collection — set per-collection overrides for refresh interval and orientation. Use
-1for the interval orinheritfor the orientation to fall back to the defaults above.
For example, you might want family photos to rotate every 5 minutes but a wallpaper art collection to rotate every 2 hours — each collection can have its own schedule.
Call the unsplash.refresh service from automations, scripts, or Developer Tools:
# Refresh a single entity
action: unsplash.refresh
data:
entity_id: image.unsplash_my_collection
# Refresh every Unsplash image entity (no target = all of them)
action: unsplash.refreshUseful for "new photo at sunrise" automations, or as a button on a dashboard:
type: button
name: New photo
tap_action:
action: call-service
service: unsplash.refresh
service_data:
entity_id: image.unsplash_my_collectiontype: vertical-stack
cards:
- type: custom:button-card
template: my_dashboard_template
styles:
card:
- background: >-
[[[ const e = hass.states['image.unsplash_my_collection'];
return `center / cover no-repeat url(${e.attributes.entity_picture})`; ]]]The entity_picture attribute is a Home Assistant-proxied URL that updates whenever the photo rotates. This is the recommended approach — it works without exposing your Unsplash key or the photographer's CDN URL to clients.
If you need the raw Unsplash CDN URL instead of HA's proxy:
{{ state_attr('image.unsplash_my_collection', 'image_url') }}type: picture-entity
entity: image.unsplash_my_collection
show_state: false
show_name: falseThis integration pairs nicely with View Assist. Use an automation to write the current image into your satellite's background attribute whenever it rotates:
automation:
- alias: "Sync Unsplash to View Assist satellite background"
triggers:
- trigger: state
entity_id: image.unsplash_my_collection
actions:
- action: view_assist.set_attribute
data:
device: sensor.viewassist_living_room
attribute: background
value: "{{ state_attr('image.unsplash_my_collection', 'image_url') }}"Each image entity exposes:
| Attribute | Description |
|---|---|
collection_id |
The Unsplash collection ID |
collection_name |
The configured display name |
photographer |
Name of the photographer (use for attribution) |
photographer_url |
Link to the photographer's Unsplash profile |
description |
Photo description from Unsplash, falls back to alt-text |
photo_page_url |
Link to the photo's Unsplash page |
image_url |
Direct CDN URL — regular size (~1080px wide) |
image_url_full |
Direct CDN URL — full size (original upload, often large) |
Unsplash's API terms require that you attribute the photographer wherever a photo is displayed. A simple way to surface this in a dashboard:
type: markdown
content: >
Photo by [{{ state_attr('image.unsplash_my_collection', 'photographer') }}]({{ state_attr('image.unsplash_my_collection', 'photographer_url') }})
on [Unsplash](https://unsplash.com)- Demo apps: 50 requests/hour. Each collection refresh = 1 request. The download-tracking ping is not counted against your hourly limit (it's a separate endpoint).
- Production apps: 5000 requests/hour. Apply via your Unsplash app dashboard once your integration is functional.
- The integration uses one
DataUpdateCoordinatorper collection, so each collection updates on its own schedule. They share the access key but make independent API calls. - If you hit the rate limit, individual coordinator updates will fail with an
UpdateFailed. The entity keeps showing its last image until the next successful refresh. No need to restart anything.
"Invalid access key" — Make sure you copied the Access Key, not the Secret Key. The Secret is longer and not used here.
Entity shows no image — Check the integration's diagnostics. Common causes: collection is private (must be public), collection has zero photos matching the orientation filter, or rate limit hit (wait an hour).
Image doesn't update on the dashboard — Make sure your dashboard card references attributes.entity_picture (which includes a cache-busting token), not a static URL.
MIT. See LICENSE.
Photos powered by Unsplash. This integration is not affiliated with or endorsed by Unsplash, Inc.