Skip to main content



Device "shadows" (aka, "digital twins") refer to a JSON document stored in the cloud that contains data about the device's state. Shadows apply only to IP devices.

nRF Cloud runs on AWS, so if you would like to learn more about device shadows, see their documentation.

nRF Cloud defines JSON schemas for device shadows. If you want your device to be fully supported by nRF Cloud, it is best not to deviate from these schemas, at least where portions are defined. It is always permissible to add custom fields to a device shadow. Keep in mind, however, that AWS imposes an 8K limit for shadows, so you want to be careful about what you store there.

It's often best to interact with devices via their shadows instead of sending them messages directly. Devices can then subscribe to their /shadow/delta/delta topic and take action on any changes they detect while online and connected to an MQTT broker. Additionally, a device can be programmed to retrieve its shadow when it comes back online. This negates any concerns about a device being offline when you want to change its state.

For example, let's say you wanted to change your device's configuration, telling it to send temperature sensor readings more frequently. Instead of publishing a message directly to the device, you could update the device's configuration in the shadow. The device will see the change and update its message frequency (assuming the firmware has been programmed accordingly).

Example Shadows#

Non-Gateway Devices#

This example shadow conforms to the ipShadow JSON schema:

 {    "desired": {        "pairing": {        "state": "paired",        "topics": {            "d2c": "prod/63ae73c3-9918-4b03-a1a8-132174824392/m/d/nrf-352656101397613/d2c",            "c2d": "prod/63ae73c3-9918-4b03-a1a8-132174824392/m/d/nrf-352656101397613/c2d"          }        },        "nrfcloud_mqtt_topic_prefix": "prod/63ae73c3-9918-4b03-a1a8-132174824392/"    },    "reported": {        "connection": {        "status": "connected"        },        "pairing": {        "state": "paired",        "topics": {            "d2c": "prod/63ae73c3-9918-4b03-a1a8-132174824392/m/d/nrf-352656101397613/d2c",            "c2d": "prod/63ae73c3-9918-4b03-a1a8-132174824392/m/d/nrf-352656101397613/c2d"          }        },        "nrfcloud_mqtt_topic_prefix": "prod/63ae73c3-9918-4b03-a1a8-132174824392/",        "device": {        "networkInfo": {            "currentBand": 12,            "supportedBands": "(2,3,4,8,12,13,20,28)\r\n",            "areaCode": 34049,            "mccmnc": "310410",            "ipAddress": "",            "ueMode": 2,            "cellID": 128566289,            "networkMode": "LTE-M GPS"        },        "simInfo": {            "uiccMode": 1,            "iccid": "8931080019073573173",            "imsi": "204080813558856"        },        "deviceInfo": {            "modemFirmware": "mfw_nrf9160_1.2.2",            "batteryVoltage": 4121,            "imei": "352656101397613",            "board": "thingy91_nrf9160",            "appVersion": "v1.4.0",            "appName": "asset_tracker"        },        "serviceInfo": {            "ui": [            "GPS",            "FLIP",            "TEMP",            "HUMID",            "AIR_PRESS",            "BUTTON",            "LIGHT",            "RSRP"            ],            "fota_v2": [            "APP",            "MODEM",            "BOOT"          ]        }        },        "config": {        "GPS": {            "enable": false        }      }    }  }


This example shadow conforms to the gatewayShadow JSON schema:

  {    "desired": {      "nrfcloud_mqtt_topic_prefix": "prod/0d114c02-9699-4721-85f2-66baa38070d9/",      "desiredConnections": [        {          "id": "EA:78:EA:96:28:22"        }      ]    },    "reported": {      "connection": {        "status": "disconnected",        "disconnectReason": "CONNECTION_LOST",        "clientInitiatedDisconnect": false      },      "statusConnections": {        "EA:78:EA:96:28:22": {          "id": "EA:78:EA:96:28:22",          "status": {            "connected": true          }        }      }    }  }

Getting a Device's Shadow#

Via the REST API#

Users can retrieve a device's shadow by calling the FetchDevice or ListDevices endpoints. If using ListDevices you must set the includeState parameter to true.

Via the MQTT API#

Devices can retrieve their own shadows by publishing any message to the /shadow/get topic. See the MQTT API for more information.

Updating a Device's Shadow#

Via the REST API#

Users can update a device's shadow via the UpdateDeviceState endpoint.

Via the MQTT API#

Devices can retrieve their own shadows by publishing to the /shadow/update topic. See the shadow topics in our MQTT API documentation.

Example: Enabling FOTA#

Devices for which you want use nRF Cloud's Firmware Over-the-Air (FOTA) Updates service must be explicitly configured for FOTA. For non-gateway devices this means their shadow must contain a reported.device.serviceInfo.fota_v2 array in its shadow, e.g.:

  ...  "reported": {      "device": {        "serviceInfo": {          "fota_v2": [            "APP",            "MODEM",            "BOOT"          ]        }      }    }

Gateway devices that also support Bluetooth LE FOTA must also set a fota_v2_ble flag. In this example snippet from a gateway's shadow we see that it supports APP and MODEM (but not BOOT) FOTA for itself, as well as Bluetooth LE FOTA for its connected peripherals:

  ...  "reported": {      "device": {        "serviceInfo": {          "fota_v2": [            "APP",            "MODEM"          ],          "fota_v2_ble": true        },      }    }

See the configuration section of the FOTA documentation for how to do this via the REST API.

This could also be done over MQTT by sending the following message to the /shadow/update topic (Note here the additional state field, which must be included when sending over MQTT):

{  "state": {    "reported": {      "device": {        "serviceInfo": {          "fota_v2": [            "APP",            "MODEM",            "BOOT"          ]        }      }    }  }}