Home Assistant Guide

Simple tutorials for powerful automations

Home Assistant REST Sensor - Beginner-Friendly Guide

The REST sensor lets Home Assistant fetch data from a device or web service over HTTP. Think of it as HA visiting a URL in the background, reading the response, and turning that into a sensor you can use on dashboards and in automations.

REST, HTTP, GET/POST, and JSON - quick definitions

  • REST - a common way devices/services share data over the web.
  • HTTP - the protocol used for web requests. You'll see URLs like http://192.168.1.50/status.
  • GET - request data (read-only).
  • POST - send some data and get a response back (e.g., ask for special info).
  • JSON - a simple text format. Example: {"temperature": 21.7, "device": "living_room"}.

Quick start - your first REST sensor

This example fetches your external IP from a free API and shows it as a sensor value.

sensor:
  - platform: rest
    name: External IP
    resource: https://api.ipify.org/?format=json
    value_template: "{{ value_json.ip }}"

The endpoint returns {"ip":"203.0.113.10"}. value_json.ip picks the ip field from the JSON response.

Two ways to define REST sensors

  • Single sensor via sensor: + platform: rest - good for one value.
  • Multiple sensors from one call via the rest: section - one HTTP request, many values.
rest:
  - resource: http://192.168.1.50/status
    sensor:
      - name: Room Temperature
        value_template: "{{ value_json.temperature }}"
        unit_of_measurement: "°C"
      - name: Room Humidity
        value_template: "{{ value_json.humidity }}"
        unit_of_measurement: "%"

Tip - using rest: avoids hammering the device with repeated calls for each sensor.

Core options you'll use most

1) Where to fetch

  • resource - the URL. Example: http://192.168.1.50/status.
  • resource_template - same as resource but you can use templates. Use either resource or resource_template, not both.
  • params - URL query parameters (supports templates). Equivalent to adding ?key=value to the URL.
sensor:
  - platform: rest
    name: Energy for Yesterday
    resource_template: https://api.example.com/energy
    params:
      start_date: "{{ (now() - timedelta(days=1)).strftime('%Y-%m-%d') }}"
      end_date: "{{ now().strftime('%Y-%m-%d') }}"

2) How to fetch

  • method - GET (default) or POST.
  • payload - body sent with POST. Usually JSON text.
  • headers - HTTP headers (e.g., Authorization, Content-Type). Can use templates.
  • username, password, authentication - for HTTP Basic/Digest auth to protected endpoints.
  • timeout - seconds to wait (default 10).
  • verify_ssl - verify HTTPS certs (default true). Set false if you're using a self-signed cert on your LAN.
  • encoding - character encoding if the server doesn't send one (default UTF-8).
sensor:
  - platform: rest
    name: Heater Status
    resource: http://192.168.1.75/api/heater
    method: POST
    headers:
      Content-Type: application/json
    payload: '{ "device": "heater_1" }'
    value_template: "{{ value_json.status }}"

3) What to extract

  • value_template - turn the response into the sensor's state (short, single value).
  • json_attributes - copy extra fields into attributes (good for long text or multiple values).
  • json_attributes_path - JSONPath to where those attributes live in the response.
sensor:
  - platform: rest
    name: Weather Snapshot
    resource: https://api.example.com/weather/today
    value_template: "{{ value_json.summary }}"
    json_attributes_path: "$.details.current"
    json_attributes:
      - temperature
      - humidity
      - wind_kph

In this example, value_template sets the main state to the short summary text, while json_attributes adds useful details as attributes.

4) How it appears in HA

  • name - friendly name.
  • device_class - tells HA what the sensor represents (e.g., temperature, humidity, battery).
  • unit_of_measurement - like °C, %, kWh.
  • state_class - for statistics/history (measurement, total_increasing, etc.).
  • icon - custom Material Design icon template if you want.
  • picture - URL or template for an entity picture.
  • unique_id - lets you rename the entity in the UI without YAML edits.

5) Availability & updates

  • availability - template that decides if the sensor is "available". Return true/false.
  • force_update - if true, record new history entries even when the value didn't change.
  • scan_interval - how often to poll the endpoint (seconds). Useful to slow down frequent calls.
sensor:
  - platform: rest
    name: Boiler Pressure
    resource: http://192.168.1.91/boiler
    value_template: "{{ value_json.pressure_bar }}"
    unit_of_measurement: "bar"
    device_class: pressure
    state_class: measurement
    availability: "{{ value_json.connected is defined and value_json.connected }}"
    scan_interval: 60

Security - tokens, headers, and secrets

Many APIs need a Bearer token in the Authorization header. Don't hardcode secrets in YAML - use secrets.yaml.

# configuration.yaml
sensor:
  - platform: rest
    name: My Secure Thing
    resource: https://api.example.com/device
    headers:
      Authorization: !secret my_secure_token
    value_template: "{{ value_json.state }}"

# secrets.yaml
my_secure_token: "Bearer eyJhbGciOi..."

If the endpoint uses HTTP Basic or Digest auth, you can also set username, password, and authentication: basic (or digest).

Templating essentials

  • value_json - the parsed JSON response. Example: {{ value_json.temperature }}.
  • value - the raw text if not JSON.
  • this - the current entity's state object (advanced; handy in availability or icon templates).
sensor:
  - platform: rest
    name: Plain Text Example
    resource: http://192.168.1.60/plain
    value_template: "{{ value | trim }}"

Handling long text - use attributes

Sensor state is limited to 255 characters. Store anything longer as attributes and keep the state short (like an ID or a short title).

sensor:
  - platform: rest
    name: News Article
    resource: https://example.com/article.json
    value_template: "{{ value_json.id }}"
    json_attributes:
      - title
      - body

View attributes in Developer Tools - States. You can also create template sensors to display attributes elsewhere.

Understanding json_attributes_path

When an API returns a complicated JSON structure, the data you want might not be at the very top - it could be nested several levels deep. Instead of listing every level in json_attributes, you can use json_attributes_path to tell Home Assistant "start here" before grabbing the listed fields.

Let's look at an example response from an imaginary weather API:

{
  "data": {
    "current": {
      "temperature": 20.5,
      "humidity": 56,
      "wind": {
        "speed": 12.4,
        "direction": "NW"
      }
    }
  }
}

If you only want the temperature and humidity, those are inside data → current. To reach them, you can set the path to $.data.current.

sensor:
  - platform: rest
    name: "Weather Snapshot"
    resource: https://api.example.com/weather
    value_template: "{{ value_json.data.current.temperature }}"
    unit_of_measurement: "°C"
    json_attributes_path: "$.data.current"
    json_attributes:
      - humidity
      - wind

This tells Home Assistant:

  • Use value_template for the temperature (the main value).
  • Start inside data → current when looking for attributes.
  • Copy humidity and wind (a small dictionary itself) as attributes.

If you omit the path, Home Assistant looks for attributes at the top level of the response. Using json_attributes_path just saves you from repeating long dotted paths like value_json.data.current.humidity for every field.

Working with XML endpoints

If the server reports XML (text/xml, application/xml, etc.), Home Assistant auto-converts it to JSON (keys become JSON fields). You can then use value_json as if it were JSON originally.

sensor:
  - platform: rest
    name: Steam Time Remaining
    resource: http://192.168.1.105/status.xml
    value_template: "{{ value_json.response.time0 }}"

Using JSONPath for attributes

json_attributes_path lets you point at a nested part of a response and copy fields from there into attributes.

sensor:
  - platform: rest
    name: First User
    resource: https://jsonplaceholder.typicode.com/users
    value_template: "{{ value_json[0].name }}"
    json_attributes_path: "$.[0].address"
    json_attributes:
      - street
      - suite
      - city
      - zipcode

POST with parameters and content type

When posting JSON, set Content-Type: application/json. You can also combine params with a payload.

sensor:
  - platform: rest
    name: Billing Summary
    resource: https://api.example.com/billing/summary
    method: POST
    headers:
      Content-Type: application/json
      Authorization: "Bearer {{ states('input_text.api_token') }}"
    params:
      month: "{{ now().strftime('%Y-%m') }}"
    payload: >
      { "account_id": "{{ states('input_text.account_id') }}",
        "include": ["totals","last_payment"] }
    value_template: "{{ value_json.totals.amount_due }}"

Making multiple sensors from one call (recommended)

rest:
  - resource: http://192.168.1.50/env
    scan_interval: 30
    sensor:
      - name: Env Temp
        device_class: temperature
        unit_of_measurement: "°C"
        state_class: measurement
        value_template: "{{ value_json.temp }}"
      - name: Env Humidity
        device_class: humidity
        unit_of_measurement: "%"
        state_class: measurement
        value_template: "{{ value_json.humid }}"
      - name: Env Status
        value_template: "{{ value_json.status }}"
        json_attributes:
          - last_seen
          - firmware

Availability template - mark sensor as offline/online

sensor:
  - platform: rest
    name: Inverter Power
    resource: http://192.168.1.88/inverter
    value_template: "{{ value_json.power_w }}"
    unit_of_measurement: "W"
    availability: >
      {{ value_json is defined and value_json.ok is defined and value_json.ok }}

Troubleshooting tips

  • Test the URL in a browser or with curl to see the raw response.
  • Use the right field in value_template - print the whole object temporarily:
    value_template: "{{ value_json | tojson }}"
  • Quotes in templates - if you use single quotes inside a template, wrap the template in double quotes (or vice versa).
  • resource vs resource_template - you must pick one.
  • SSL issues on local HTTPS - try verify_ssl: false while testing.
  • State too long - keep state short and move the rest to json_attributes.
  • Slow endpoints - increase timeout and/or scan_interval.
# Inspect raw response during setup
sensor:
  - platform: rest
    name: Debug Response
    resource: http://192.168.1.50/status
    value_template: "{{ value_json | tojson }}"

Copy-paste reference - common options in one place

sensor:
  - platform: rest
    name: Example REST Sensor
    unique_id: example_rest_sensor_1
    resource_template: https://api.example.com/data
    params:
      q: "kitchen"
      date: "{{ now().strftime('%Y-%m-%d') }}"
    method: GET  # or POST
    headers:
      Authorization: !secret api_bearer
      User-Agent: Home Assistant
      Accept: application/json
    # payload: '{ "example": true }'    # only for POST
    timeout: 15
    verify_ssl: true
    encoding: utf-8

    value_template: "{{ value_json.result.value }}"
    json_attributes_path: "$.result.details"
    json_attributes:
      - foo
      - bar
      - baz

    device_class: power
    unit_of_measurement: "W"
    state_class: measurement
    icon: "{{ 'mdi:flash' if (value|float(0) > 0) else 'mdi:flash-off' }}"
    picture: "{{ value_json.image_url if value_json.image_url is defined else none }}"
    availability: "{{ value_json.available | default(false) }}"
    force_update: false
    scan_interval: 60

Recap

  • Use value_template for the main value and json_attributes for extra fields or long text.
  • Secure tokens via secrets.yaml and headers. For HTTP auth, use username/password/authentication.
  • Shape the result with device_class, unit_of_measurement, and state_class.
  • Fetch many values at once using the rest: block with multiple sensor entries.
  • Remember - use either resource or resource_template.

With these building blocks, you can pull in data from almost any device or service and make it feel "native" in Home Assistant.