---
title: Low Bandwidth Design
description: When building an IoT application that is expected to operate over a long period of time with Blues Notecard, you'll want to ensure that bandwidth is preserved and monitored, wherever possible.
source_url: https://dev.blues.io/notecard/notecard-walkthrough/low-bandwidth-design/
canonical_url: https://dev.blues.io/notecard/notecard-walkthrough/low-bandwidth-design/
markdown_url: https://dev.blues.io/notecard/notecard-walkthrough/low-bandwidth-design.md
---

# Low Bandwidth Design

When building an application that is expected to operate over a long period of time, you'll want to ensure that bandwidth is preserved and monitored, wherever possible. The Notecard provides features that allow you to optimize the size of Notes at rest and in transit, as well as a set of usage monitoring APIs.

## Working with Note Templates

By default, the Notecard allows for maximum developer flexibility in the structure and content of Notes. As such, individual Notes in a Notefile do not share structure or schema. You can add JSON structures and payloads of any type and format to a Notefile, adding and removing fields as required by your application.

In order to provide this simplicity to developers, the design of the Notefile system is primarily memory based and designed to support no more than 100 Notes per Notefile. As long as your data needs and sync periods ensure regular uploads of data to Notehub, this limit is adequate for most applications.

Some applications, however, will need to track and stage bursts of data that may eclipse the 100 Note limit in a short period of time, and before a sync can occur. For these types of use cases, the Notecard supports using a flash-based storage system based on Note templates.

Using the `note.template` request with any `.qo` or `.qos` Notefile, developers can provide the Notecard with a schema of sorts to apply to future Notes added to the Notefile. This template acts as a hint to the Notecard that allows it to internally store data as fixed-length records rather than as flexible JSON objects, which tend to be much larger.

> **Note:**
>
> Note Templates are required for both inbound and outbound Notefiles when using **Notecard LoRa** or NTN mode with **Starnote**.

### Creating a Template

To create a template, use the `file` argument to specify the Notefile to which the template should be applied. Then, use the `body` argument to specify a template body, similar to the way you'd make a `note.add` request. That body must contain the name of each field expected in each `note.add` request, and a value that serves as the hint indicating the data type to the Notecard. Each field can be a boolean, integer, float, or string.

> **Note:**
>
> Additionally, the `format` and `port` arguments are required for Notecard for LoRa and when working with Starnote. The `format` argument must be set to `"compact"`, and the `port` argument must be set to a unique integer in the range 1-100. See [Creating Compact Templates](#creating-compact-templates) for an example.

**JSON**

```json
{
  "req": "note.template",
  "file": "readings.qo",
  "body": {
    "new_vals": true,
    "temperature": 14.1,
    "humidity": 11,
    "pump_state": "-"
  }
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.template");
JAddStringToObject(req, "file", "readings.qo");

J *body = JCreateObject();
JAddBoolToObject(body, "new_vals", true);
JAddNumberToObject(body, "temperature", 14.1);
JAddNumberToObject(body, "humidity", 11);
JAddStringToObject(body, "pump_state", "-");
JAddItemToObject(req, "body", body);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.template"}
req["file"] = "readings.qo"
req["body"] = {
    "new_vals": True,
    "temperature": 14.1,
    "humidity": 11,
    "pump_state": "-"
  }

rsp = card.Transaction(req)
```

The Notecard responds to `note.template` with a single `bytes` field, indicating the number of bytes that will be transmitted to Notehub, per note, before compression.

```json
{
  "bytes": 40
}
```

> **Warning:**
>
> Simultaneously using multiple templates for the same Notefile name is not supported.
>
> In addition, attempting to "update" an existing template's `body` schema by reusing the same `file` argument **does not overwrite the previous template**, but rather creates a new one. This can become an issue if you create numerous Notefile templates (>25) for the same Notefile to accommodate changes in data from individual Note schemas. You may end up negating the advantage of templates by filling the flash storage on the Notecard and consuming additional cellular data by syncing each new template with Notehub.
>
> To avoid these issues, we recommend defining one template for each distinct Note schema in use. You may also binary-encode data and send it via the [note.add](https://dev.blues.io/api-reference/notecard-api/note-requests.md#note-add) `payload` argument.

### Understanding Template Data Types

The hints in each template Note body value come with a few expectations and requirements, as well as options for advanced usage.

- **Boolean** values must be specified in a template as `true`.

- **String** values must be specified as non-empty string values, e.g. `"-"`.

- **Integer** fields should use a specific value to indicate their type and length based on the following:

  - `11` - for a 1 byte signed integer (e.g. -128 to 127).
  - `12` - for a 2 byte signed integer (e.g. -32,768 to 32,767).
  - `13` - for a 3 byte signed integer (e.g. -8,388,608 to 8,388,607).
  - `14` - for a 4 byte signed integer (e.g. -2,147,483,648 to 2,147,483,647).
  - `18` - for a 8 byte signed integer (e.g. -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807).
  - `21` - for a 1 byte unsigned integer (e.g. 0 to 255). Available as of *v3.3.1*.
  - `22` - for a 2 byte unsigned integer (e.g. 0 to 65535). Available as of *v3.3.1*.
  - `23` - for a 3 byte unsigned integer (e.g. 0 to 16777215). Available as of *v3.3.1*.
  - `24` - for a 4 byte unsigned integer (e.g. 0 to 4294967295). Available as of *v3.3.1*.

- **Float** fields should also use a specific value to indicate their type and length based on the following:

  - `12.1` - for an IEEE 754 2 byte float.
  - `14.1` - for an IEEE 754 4 byte float.
  - `18.1` - for an IEEE 754 8 byte float.

> **Note:**
>
> In [note-c](https://github.com/blues/note-c) and [note-arduino](https://github.com/blues/note-arduino), the following data types are defined:
>
> | Data Type        | C/C++ Definition                                | Description                        |
> | ---------------- | ----------------------------------------------- | ---------------------------------- |
> | Boolean          | `TBOOL`                                         | Boolean true/false value           |
> | String           | `TSTRINGV`                                      | Variable length UTF-8 text         |
> | String           | `TSTRING(N)`                                    | Fixed length UTF-8 text            |
> | Integer          | `TINT8`, `TINT16`, `TINT24`, `TINT32`, `TINT64` | Signed integers of various sizes   |
> | Unsigned Integer | `TUINT8`, `TUINT16`, `TUINT24`, `TUINT32`       | Unsigned integers of various sizes |
> | Float            | `TFLOAT16`, `TFLOAT32`, `TFLOAT64`              | IEEE 754 floating point numbers    |

### Using Arrays in Templates

If you're working with more complex data structures, it's possible to use arrays of data types when creating a template. The same definitions are used when assigning data types to the array.

**JSON**

```json
{
  "req": "note.template",
  "file": "readings.qo",
  "body": {
    "new_vals": true,
    "temperature": 14.1,
    "humidity": 11,
    "pump_state": "-",
    "array_vals": [true, 14.1, 11, "-"]
  }
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.template");
JAddStringToObject(req, "file", "readings.qo");

J *body = JCreateObject();
JAddBoolToObject(body, "new_vals", true);
JAddNumberToObject(body, "temperature", 14.1);
JAddNumberToObject(body, "humidity", 11);
JAddStringToObject(body, "pump_state", "-");

J *arr = JCreateArray();
JAddItemToArray(arr, JCreateBool(true));
JAddItemToArray(arr, JCreateNumber(14.1));
JAddItemToArray(arr, JCreateNumber(11));
JAddItemToArray(arr, JCreateString("-"));
JAddItemToObject(body, "array_vals", arr);

JAddItemToObject(req, "body", body);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.template"}
req["file"] = "readings.qo"
req["body"] = {
    "new_vals": True,
    "temperature": 14.1,
    "humidity": 11,
    "pump_state": "-",
    "array_vals": [True, 14.1, 11, "-"]
  }

rsp = card.Transaction(req)
```

Starting with [Notecard Firmware v9.1.1](https://dev.blues.io/notecard/notecard-firmware-releases.md), templated Notefiles now support variable-length arrays. Define an array in your template using a single Integer or Float, and subsequent `note.add` requests can include any number of elements of that same type.

**JSON**

```json
{
  "req": "note.template",
  "file": "readings.qo",
  "body": {
    "new_vals": true,
    "temperature": 14.1,
    "humidity": 11,
    "pump_state": "-",
    "array_vals": [14.1]
  }
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.template");
JAddStringToObject(req, "file", "readings.qo");

J *body = JCreateObject();
JAddBoolToObject(body, "new_vals", true);
JAddNumberToObject(body, "temperature", 14.1);
JAddNumberToObject(body, "humidity", 11);
JAddStringToObject(body, "pump_state", "-");

J *arr = JCreateArray();
JAddItemToArray(arr, JCreateNumber(14.1));
JAddItemToObject(body, "array_vals", arr);

JAddItemToObject(req, "body", body);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.template"}
req["file"] = "readings.qo"
req["body"] = {
    "new_vals": True,
    "temperature": 14.1,
    "humidity": 11,
    "pump_state": "-",
    "array_vals": [14.1]
  }

rsp = card.Transaction(req)
```

### Use of `omitempty` in Templates

When using templated Notefiles it's important to know that the Notecard and Notehub enforce the usage of the `omitempty` instruction when serializing JSON objects. `omitempty` indicates that a field should be eliminated from the serialized output of a JSON object if that field has an empty value - meaning a null, false, 0, or empty string ("").

> **Note:**
>
> You can bypass usage of `omitempty` in `note.add` requests that use templated Notefiles by using the `"full":true` argument.

This directly impacts templated Notefiles, especially in the `body` field as they appear in Notehub. For instance, while the following `body` would be present in Notehub when using a non-templated `note.add` request:

```json
"body": {
  "alert": true,
  "warning": false,
  "temp": 23.4,
  "count": 0,
  "status": "ok",
  "prevstatus": ""
}
```

...that same `body` will look like this in Notehub if using a templated Notefile:

```json
"body": {
  "alert": true,
  "temp": 23.4,
  "status": "ok"
}
```

### Verifying a Template

You can use the `verify:true` argument to return the current template for a Notefile.

**JSON**

```json
{
  "req": "note.template",
  "file": "readings.qo",
  "verify": true
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.template");
JAddStringToObject(req, "file", "readings.qo");
JAddBoolToObject(req, "verify", true);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.template"}
req["file"] = "readings.qo"
req["verify"] = True

rsp = card.Transaction(req)
```

If the `file` provided has an active template, it will be returned in a response `body`.

```json
{
 "body": {
  "new_vals": true,
  "temperature": 14.1,
  "humidity": 11,
  "pump_state": "-"
 },
 "template": true,
 "length": 32
}
```

### Creating Compact Templates

By default all Note templates automatically include metadata, including a timestamp for when the Note was created, various fields about a device's location, as well as a timestamp for when the device's location was determined.

By providing the `note.template` request a `"format"` of `"compact"`, you can tell the Notecard to omit this additional metadata to save on storage and bandwidth. The use of `"format": "compact"` is required for Notecard for LoRa and a Notecard paired with Starnote.

**JSON**

```json
{
  "req": "note.template",
  "file": "readings.qo",
  "port": 10,
  "format": "compact",
  "body": {
    "temperature": 14.1
  }
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.template");
JAddStringToObject(req, "file", "readings.qo");
JAddNumberToObject(req, "port", 10);
JAddStringToObject(req, "format", "compact");

J *body = JCreateObject();
JAddNumberToObject(body, "temperature", 14.1);
JAddItemToObject(req, "body", body);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.template"}
req["file"] = "readings.qo"
req["port"] = 10
req["format"] = "compact"
req["body"] = {
  "temperature": 14.1
}

rsp = card.Transaction(req)
```

When using "compact" templates, you may include the following keywords in your template to restore selected fields to their original position in the Note (e.g. `best_lat`) that would otherwise be omitted:

- `_lat`: The device's latitude. For a value provide either `12.1` (2-byte float), `14.1` (4-byte float), or `18.1` (8-byte float) depending on your desired precision.
- `_lon`: The device's longitude. For a value provide either `12.1` (2-byte float), `14.1` (4-byte float), or `18.1` (8-byte float) depending on your desired precision.
- `_ltime`: A timestamp for when the device's location was determined. For a value provide `14` (4-byte integer).
- `_time`: A timestamp for when the Note was created. For a value provide `14` (4-byte integer).

For example, the following template includes all additional fields.

**JSON**

```json
{
  "req": "note.template",
  "file": "readings.qo",
  "port": 10,
  "format": "compact",
  "body": {
    "temperature": 14.1,
    "_lat": 14.1,
    "_lon": 14.1,
    "_ltime": 14,
    "_time": 14
  }
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.template");
JAddStringToObject(req, "file", "readings.qo");
JAddNumberToObject(req, "port", 10);
JAddStringToObject(req, "format", "compact");

J *body = JCreateObject();
JAddNumberToObject(body, "temperature", 14.1);
JAddNumberToObject(body, "_lat", 14.1);
JAddNumberToObject(body, "_lon", 14.1);
JAddNumberToObject(body, "_ltime", 14);
JAddNumberToObject(body, "_time", 14);
JAddItemToObject(req, "body", body);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.template"}
req["file"] = "readings.qo"
req["port"] = 10
req["format"] = "compact"
req["body"] = {
  "temperature": 14.1,
  "_lat": 14.1,
  "_lon": 14.1,
  "_ltime": 14,
  "_time": 14
}

rsp = card.Transaction(req)
```

> **Warning:**
>
> When using the **string** data type in a compact template, each string value in a Note is limited to a maximum of 255 characters. Notecard will return the following error if a string > 255 characters is used:
>
> ```unknown
> {
>  "err": "error adding note: compact mode only supports strings up to 255 bytes 
>  {template-incompatible}"
> }
> ```

### Using Templates with a Payload

The most efficient way to send base64-encoded binary data with Notecard is to use the `payload` argument in a `note.add` request. When using templates, you can arbitrarily add a `payload` to any `note.add` request.

You can also define a payload-only template by sending `note.template` with an empty `body` (`{}`) and no `payload` argument. Subsequent `note.add` requests to the Notefile can then include a `payload` without any `body` fields:

**JSON**

```json
{
  "req": "note.template",
  "file": "readings.qo",
  "body": {}
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.template");
JAddStringToObject(req, "file", "readings.qo");

J *body = JCreateObject();
JAddItemToObject(req, "body", body);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.template"}
req["file"] = "readings.qo"
req["body"] = {}

rsp = card.Transaction(req)
```

When your template includes both `body` fields and a `payload`, use the `length` argument to pre-allocate a fixed-size payload slot in each Note stored for the Notefile. Every Note reserves exactly `length` bytes for the payload — whether or not a given Note actually includes a payload — and any payload larger than `length` bytes will be truncated to fit.

**JSON**

```json
{
  "req": "note.template",
  "file": "readings.qo",
  "body": {
    "new_vals": true,
    "temperature": 14.1,
    "humidity": 11,
    "pump_state": "-"
  },
  "length": 32
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.template");
JAddStringToObject(req, "file", "readings.qo");
JAddNumberToObject(req, "length", 32);

J *body = JCreateObject();
JAddBoolToObject(body, "new_vals", true);
JAddNumberToObject(body, "temperature", 14.1);
JAddNumberToObject(body, "humidity", 11);
JAddStringToObject(body, "pump_state", "-");
JAddItemToObject(req, "body", body);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.template"}
req["file"] = "readings.qo"
req["body"] = {
    "new_vals": True,
    "temperature": 14.1,
    "humidity": 11,
    "pump_state": "-"
  }
req["length"] = 32

rsp = card.Transaction(req)
```

The four `body` fields account for 40 bytes; adding a `length` of 32 gives a total of 72 bytes per record.

```json
{
  "bytes": 72
}
```

> **Warning:**
>
> Please be aware when using a `payload` with compact templates in NTN mode (e.g. with Starnote for Skylo), the maximum packet size is 256 bytes.

### Adding Notes to a Template Notefile

After a template is created, use `note.add` requests to create Notes that conform to the template.

**JSON**

```json
{
  "req": "note.add",
  "file": "readings.qo",
  "body": {
    "new_vals": true,
    "temperature": 22.22,
    "humidity": 43,
    "pump_state": "off"
  }
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.add");
JAddStringToObject(req, "file", "readings.qo");

J *body = JCreateObject();
JAddBoolToObject(body, "new_vals", true);
JAddNumberToObject(body, "temperature", 22.22);
JAddNumberToObject(body, "humidity", 43);
JAddStringToObject(body, "pump_state", "off");
JAddItemToObject(req, "body", body);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.add"}
req["file"] = "readings.qo"
req["body"] = {
      "new_vals": True,
      "temperature": 22.22,
      "humidity": 43,
      "pump_state": "off"
    }

rsp = card.Transaction(req)
```

When adding Notes to a Notefile with an active template, the following JSON object is returned by the Notecard:

```json
{ "template": true }
```

Notefiles with an active template validate each Note upon a `note.add` request. If any value in the Note `body` does not adhere to the template, or if the `payload` is longer than specified, an error is returned. For instance, the following Note includes a float for the humidity, which was specified in the template as an integer.

**JSON**

```json
{
  "req": "note.add",
  "file": "readings.qo",
  "body": {
    "new_vals": true,
    "temperature": 22.22,
    "humidity": 43.22, // mistakenly specified here as a float instead of integer
    "pump_state": "off"
  }
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.add");
JAddStringToObject(req, "file", "readings.qo");

J *body = JCreateObject();
JAddBoolToObject(body, "new_vals", true);
JAddNumberToObject(body, "temperature", 22.22);
JAddNumberToObject(body, "humidity", 43.22); // mistakenly specified here as a float instead of integer
JAddStringToObject(body, "pump_state", "off");
JAddItemToObject(req, "body", body);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.add"}
req["file"] = "readings.qo"
req["body"] = {
      "new_vals": True,
      "temperature": 22.22,
      "humidity": 43.22, # mistakenly specified here as a float instead of integer
      "pump_state": "off"
    }

rsp = card.Transaction(req)
```

```json
{
 "err": "error adding note: integer expected because of template"
}
```

### Modifying a Template

If the needs of your application evolve, you can modify a template with another `note.template` request to the same Notefile. A new template can be set at any time and is non-destructive, meaning it has no impact on existing Notes in the Notefile.

For instance, you may need to modify the template field data types and/or add/remove fields:

**JSON**

```json
{
  "req": "note.template",
  "file": "readings.qo",
  "body": {
    "new_vals": true,
    "temperature": 14.1, // Change to a 4 byte float
    "humidity": 11,
    "pump_state": "-",
    "pressure": 12.1 // New field
  }
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.template");
JAddStringToObject(req, "file", "readings.qo");

J *body = JCreateObject();
JAddBoolToObject(body, "new_vals", true);
JAddNumberToObject(body, "temperature", 14.1); // Change to a 4 byte float
JAddNumberToObject(body, "humidity", 11);
JAddStringToObject(body, "pump_state", "-");
JAddNumberToObject(body, "pressure", 12.1); // New field
JAddItemToObject(req, "body", body);

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.template"}
req["file"] = "readings.qo"
req["body"] = {
    "new_vals": True,
    "temperature": 14.1, # Change to a 4 byte float
    "humidity": 11,
    "pump_state": "-",
    "pressure": 12.1 # New field
  }

rsp = card.Transaction(req)
```

These template changes will be applied only to new Notes in the Notefile. Existing Notes remain unchanged.

### Clearing a Template

To clear a template from a Notefile, simply call `note.template` with the Notefile name and omit the `body` and `payload` arguments. After clearing the template, all Notes written to the Notefile are stored as arbitrary JSON structures. This request, if successful, will return an empty JSON body (`{}`).

**JSON**

```json
{
  "req": "note.template",
  "file": "readings.qo"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("note.template");
JAddStringToObject(req, "file", "readings.qo");

NoteRequest(req);
```

**Python**

```python
req = {"req": "note.template"}
req["file"] = "readings.qo"

rsp = card.Transaction(req)
```

## Measuring Data Usage

Cellular-enabled Notecards and Starnotes include a fixed lifetime data allocation for both inbound and outbound traffic. When a Notecard runs low on data, [Connectivity Assurance](https://dev.blues.io/notehub/notehub-walkthrough.md#managing-connectivity-assurance) tops up the data allocation and extends its expiration. Likewise, when a Starnote exhausts its initial data allocation, it continues to operate normally, with any data overages billed monthly in arrears.

Actual data usage is primarily driven by the size and frequency of user payloads sent via requests like `note.add`, but it can fluctuate. Per-session TLS and TCP overhead may increase usage, while data compression can reduce it.

Ultimately, you control how much data your product syncs and how frequently it communicates with Notehub. To help you track and plan effectively, Notecard and Notehub offer multiple tools to monitor data usage and forecast long-term data availability based on your current workload.

- [Obtaining Historical Usage via API](#obtaining-historical-usage-via-api)
- [Viewing Usage Data on Notehub](#viewing-usage-data-on-notehub)
- [Projecting the Lifetime of Available Cellular Data](#projecting-the-lifetime-of-available-data)

### Obtaining Historical Usage via API

The `card.usage.get` request provides actual cellular and WiFi usage statistics, and can provide this information across the Notecard's entire life since activation, or for periods of one hour, one day, or a 30 day period.

> **Note:**
>
> Usage data is updated by the Notecard **at the end of each session**. When operating in `continuous` mode, usage data is updated only after the interval specified by the [hub.set/duration argument](https://dev.blues.io/api-reference/notecard-api/hub-requests.md#hub-set) elapses.
>
> Please note that the `card.usage` APIs only apply to cellular and WiFi data, not LoRa or satellite (NTN).

A no argument request:

**JSON**

```json
{
  "req": "card.usage.get"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.usage.get");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.usage.get"}

rsp = card.Transaction(req)
```

Is the same as:

**JSON**

```json
{
  "req": "card.usage.get",
  "mode": "total"
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.usage.get");
JAddStringToObject(req, "mode", "total");

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.usage.get"}
req["mode"] = "total"

rsp = card.Transaction(req)
```

This request returns an object with the number of `seconds` since the Notecard was activated, the total number of `bytes_sent` and `bytes_received`, the approximate number of `notes_sent` and `notes_received`, the number of standard (`sessions_standard`) and TLS (`sessions_secure`) sessions, and the UNIX Epoch `time` of device activation.

```json
{
 "seconds": 661135,
 "bytes_sent": 65445,
 "bytes_received": 136651,
 "notes_sent": 50,
 "notes_received": 18,
 "sessions_standard": 51,
 "sessions_secure": 14,
 "time": 1598479763
}
```

To analyze a period of time, the `mode` argument also accepts the values of `1hour`, `1day`, or `30day` and an `offset` argument to skip backwards in time before returning stats for the `mode` unit specified. For instance, the following request will skip back two days, and return a single day of usage data.

**JSON**

```json
{
  "req": "card.usage.get",
  "mode": "1day",
  "offset": 2
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.usage.get");
JAddStringToObject(req, "mode", "1day");
JAddNumberToObject(req, "offset", 2);

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.usage.get"}
req["mode"] = "1day"
req["offset"] = 2

rsp = card.Transaction(req)
```

> **Note:**
>
> To accurately determine the start of the calculated time period when using `offset`, use the `time` value of the response. Likewise, to calculate the end of the time period, add the `seconds` value to the `time` value.

### Viewing Usage Data on Notehub

Another place to view comprehensive information about data and events used by Notecards and Starnotes is on Notehub.

- [View Data Used by Multiple Devices](#view-data-used-by-multiple-devices)
- [Notecard Event Usage](#notecard-event-usage)
- [Notecard Cellular Data Usage](#notecard-cellular-data-usage)
- [Notecard Cellular Data Plan Information](#notecard-cellular-data-plan-information)
- [Satellite Data Usage](#satellite-data-usage)

#### View Data Used by Multiple Devices

By navigating to **Devices > Usage** you can see the sum total of MB transferred to-date for each Notecard associated with a given project.

![sim usage on notehub](https://dev.blues.io/images/guides/notecard-guides/data-sim-usage.png?v=eb9f1fb5)

#### Notecard Event Usage

By navigating to the **Usage** tab of an individual Notecard, you can see a summary of the last four weeks of events sent and received.

![event usage summary on notehub](https://dev.blues.io/images/guides/notecard-guides/data-event-usage-device.png?v=c032f9c4)

#### Notecard Cellular Data Usage

Also on the **Usage** tab of an individual Notecard, you can see a summary of the last four weeks of cellular data usage.

![data usage summary on notehub](https://dev.blues.io/images/guides/notecard-guides/data-cell-usage-device.png?v=a39895b2)

> **Note:**
>
> The usage statistics provided by `card.usage` may differ from what appears on Notehub. You should consider `card.usage` as more accurate than the values you see in Notehub. This is because the `card.usage` statistics are derived from the Notecard "asking" the modem (every time the modem powers down - or the `duration` of `hub.set` is met) how many bytes were transferred over the cellular network. Notehub can only approximate this number by looking at how many bytes were transferred at a higher level (over TCP or TLS). The numbers in Notehub are also updated nightly by a process that queries the cellular carrier to determine how much data has been used on the SIM.

#### Notecard Cellular Data Plan Information

Open the **Data Plan** tab on any Notecard to see detailed information about its embedded SIM and data plan status.

![device data plan information on notehub](https://dev.blues.io/images/guides/notecard-guides/data-plan.png?v=19a83ea3)

#### Satellite Data Usage

If using Notecard for Skylo, or if a Starnote device is associated with the selected Notecard, the **Usage** tab displays satellite (NTN) data usage for the past four weeks.

![ntn data usage summary on notehub](https://dev.blues.io/images/guides/notecard-guides/data-ntn-usage-device.png?v=fa759805)

To view total lifetime satellite data usage for the device, click **View Lifetime Usage**.

![ntn data usage lifetime](https://dev.blues.io/images/guides/notecard-guides/data-ntn-lifetime.png?v=fc5dfc75)

For a monthly breakdown (including separate uplink and downlink usage), navigate to the **Devices** page and select the **Satellite Usage** tab.

![ntn data usage aggregated](https://dev.blues.io/images/guides/notecard-guides/data-ntn-monthly.png?v=b310b770)

> **Note:**
>
> 1. Billable bytes will always be greater than or equal to uplink/downlink bytes due to the minimum billable packet size defined by [Skylo](https://dev.blues.io/datasheets/starnote-datasheet/starnote-for-skylo.md#satellite-ntn-communications) and [Iridium](https://dev.blues.io/datasheets/starnote-datasheet/starnote-for-iridium.md#satellite-ntn-communications).
>
> 2. See [Satellite Best Practices](https://dev.blues.io/starnote/satellite-best-practices.md) for recommendations on optimizing NTN data efficiency.

### Projecting the Lifetime of Available Data

Once your Notecard is running a workload that you feel is representative of its deployed use, you can use the `card.usage.test` request to estimate the lifetime of available cellular data given its current usage rate.

When called with no arguments, `card.usage.test` performs its projections based on all data since activation. Alternatively, use the `days` argument to specify the most recent number of days to analyze, `hours` to analyze a number of hours, and `megabytes` to specify the Notecard data quota from which to estimate. If `megabytes` is omitted, it defaults to `1024` (1 GB).

For example, if your project has been running production-ready firmware for the last week, and your data cap is 500 MB, you'd send the following request:

**JSON**

```json
{
  "req": "card.usage.test",
  "days": 7,
  "megabytes": 500
}
```

**C/C++**

```cpp
J *req = NoteNewRequest("card.usage.test");
JAddNumberToObject(req, "days", 7);
JAddNumberToObject(req, "megabytes", 500);

NoteRequest(req);
```

**Python**

```python
req = {"req": "card.usage.test"}
req["days"] = 7
req["megabytes"] = 500

rsp = card.Transaction(req)
```

This request returns all of the fields that `card.usage.get` does so you can see actual usage over the defined period. In addition, the returned object contains the number of `days` used for the test, the average `bytes_per_day` sent during the analyzed period, and the `max` number of days of Notecard lifetime based on daily usage of the analyzed period. For example, if your Notecard sends around 44 kilobytes per day, it would take 11,833 days, or over 32 years before it eclipsed its data cap!

> **Note:**
>
> Usage information provided by the Notecard is representative of all network traffic, including TCP/IP and TLS overhead.

```json
{
  "days":              7,
  "bytes_per_day":     44289,
  "max":               11833,
 
  // Fields also sent with card.usage.get
  "bytes_sent":        29327,
  "bytes_received":    59252,
  "notes_sent":        16,
  "notes_received":    13,
  "sessions_standard": 24,
  "sessions_secure":   5
}
```

## Data Usage Estimates

Since the Cellular Notecards come prepaid with 500MB of cellular data, a common inquiry is precisely *how much* of that allocation is consumed when sending/receiving data.

This section aims to lay out some commonly-used scenarios and provide metrics around what **approximate data usage numbers** to expect, given the following set of testing parameters.

- [Testing Parameters](#testing-parameters)
- [Initial Cellular Connection](#initial-cellular-connection)
- [Periodic/Minimum Mode Usage](#periodic-minimum-mode-usage)
- [Continuous Mode Usage](#continuous-mode-usage)
- [Additional Notes and FAQs](#additional-notes-and-faqs)

### Testing Parameters

- Tests were performed using firmware v7.3.1 on a WBNAW Notecard using cellular data only.
- Notecard was factory reset with a [card.restore](https://dev.blues.io/api-reference/notecard-api/card-requests.md#card-restore) request: `{"req":"card.restore","delete":true,"connected":true}`
- Measurements were taken after a cold boot of the Notecard + three (3) completed [hub.sync](https://dev.blues.io/api-reference/notecard-api/hub-requests.md#hub-sync) requests to ensure any data overhead related to its first connection was cleared: `{"req":"hub.sync"}`
- The body of the Note used for all tests was `{"temp":12.3,"alert":true}`.
- When a [Note Template](https://dev.blues.io/notecard/notecard-walkthrough/low-bandwidth-design.md) was used, "temp" was set to a 4 byte float and "alert" was set to bool: `{"req":"note.template","file":"test.qo","body":{"temp": 14.1,"alert": true}}`
- The tests were performed with inbound and outbound arguments omitted from the [hub.set](https://dev.blues.io/api-reference/notecard-api/hub-requests.md#hub-set) request: `{"req":"hub.set","mode":"continuous","product":"<productuid>"}`

### Initial Cellular Connection

After a power cycle or `card.restart`, the Notecard must re-negotiate its connection with Notehub. This always involves a TLS connection (for security purposes), even if there is no user data that needs to be synced. This is why we strongly encourage users to leave the Notecard powered-on, in an idle state, and to only restart the Notecard when strictly necessary.

> **Note:**
>
> The data usage for an initial connection will vary depending on the state of the connected Notehub project. For instance, upon boot, the Notecard will sync data in any existing .db/dbs Notefiles, any pending .qo/.qos Notefiles, and any Notefile templates. This is because part of the Notecard's boot process is to examine the data present on both sides (Notecard and Notehub) to make sure everything is completely in-sync after the initial power-on.
>
> The value range provided below is based on a factory-reset Notecard associated with a newly-created Notehub project.

**Approximate Data Usage: 26KB +/- 3KB.**

### Periodic/Minimum Mode Usage

The Notecard, by default, is set to `periodic` mode to conserve power by only connecting when it needs to sync with Notehub. The following tests were performed in `minimum` mode, which is similar to `periodic`, but requires an explicit `hub.sync` request to send and receive data.

The **Compact** column refers to a Notefile template that uses the `"format":"compact"` argument which [omits potentially unneeded metadata](https://dev.blues.io/notecard/notecard-walkthrough/low-bandwidth-design.md#creating-compact-templates).

| Test: Templated Notefile                                     | Standard | Compact |
| ------------------------------------------------------------ | -------- | ------- |
| Sync with 1 .qo Note (the first time a new template is used) | 2.3 KB   | 2.2 KB  |
| Sync with 1 .qo Note                                         | 1.2 KB   | 1.2 KB  |
| Sync with 10 .qo Notes                                       | 1.3 KB   | 1.2 KB  |
| Sync with 100 .qo Notes                                      | 1.6 KB   | 1.2 KB  |
| Sync with 5000 .qo Notes                                     | 16.4 KB  | 4.7 KB  |

| Test: Standard (non-Templated) Notefile | Data   |
| --------------------------------------- | ------ |
| Sync with 1 .qo Note                    | 1.3 KB |
| Sync with 10 .qo Notes                  | 1.3 KB |
| Sync with 100 .qo Notes                 | 3.5 KB |

| Test: Templated [Secure .qos](https://dev.blues.io/notecard/notecard-walkthrough/essential-requests.md#adding-notes-for-secure-transport) Notefile | Standard | Compact |
| -------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- |
| Sync with 1 .qos Note (the first time a new template is used)                                                                                      | 6.2 KB   | 6.2 KB  |
| Sync with 1 .qos Note                                                                                                                              | 5.0 KB   | 5.0 KB  |
| Sync with 10 .qos Notes                                                                                                                            | 5.1 KB   | 5.1 KB  |
| Sync with 100 .qos Notes                                                                                                                           | 5.6 KB   | 5.6 KB  |
| Sync with 5000 .qos Notes                                                                                                                          | 21.6 KB  | 8.9 KB  |

| Test: Standard (non-Templated) [Secure .qos](https://dev.blues.io/notecard/notecard-walkthrough/essential-requests.md#adding-notes-for-secure-transport) Notefile | Data   |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| Sync with 1 .qos Note                                                                                                                                             | 5.2 KB |
| Sync with 10 .qos Notes                                                                                                                                           | 5.3 KB |
| Sync with 100 .qos Notes                                                                                                                                          | 7.5 KB |

### Continuous Mode Usage

The use of `continuous` mode is only recommended when the Notecard is connected to line power and requires a low latency of syncing Notes with Notehub.

The **Compact** column refers to a Notefile template that uses the `"format":"compact"` argument which [omits potentially unneeded metadata](https://dev.blues.io/notecard/notecard-walkthrough/low-bandwidth-design.md#creating-compact-templates).

| Test: Templated Notefile                                     | Standard | Compact |
| ------------------------------------------------------------ | -------- | ------- |
| Sync with 1 .qo Note (the first time a new template is used) | 1.9 KB   | 1.9 KB  |
| Sync with 1 .qo Note                                         | 0.7 KB   | 0.7 KB  |
| Sync with 10 .qo Notes                                       | 0.7 KB   | 0.7 KB  |
| Sync with 100 .qo Notes                                      | 1.3 KB   | 1.2 KB  |
| Sync with 5000 .qo Notes                                     | 17.5 KB  | 4.4 KB  |

| Test: Templated Notefile                                     | Data   |
| ------------------------------------------------------------ | ------ |
| Sync with 1 .qo Note (the first time a new template is used) | 1.0 KB |
| Sync with 1 .qo Note                                         | 0.7 KB |
| Sync with 10 .qo Notes                                       | 0.7 KB |
| Sync with 100 .qo Notes                                      | 1.3 KB |

| Test: Standard (non-Templated) Notefile | Data   |
| --------------------------------------- | ------ |
| Sync with 1 .qo Note                    | 0.7 KB |
| Sync with 10 .qo Notes                  | 0.7 KB |
| Sync with 100 .qo Notes                 | 3.2 KB |

When a Notecard is in `continuous` mode, it needs to occasionally negotiate with the carrier to maintain its session. This is why we are also documenting the usage of `continuous` mode in two "idle" states:

There are two options for a `continuous` mode connection:

- [hub.set](https://dev.blues.io/api-reference/notecard-api/hub-requests.md#hub-set) `"sync":false` to prevent the Notecard from checking for inbound Notefile changes.
- [hub.set](https://dev.blues.io/api-reference/notecard-api/hub-requests.md#hub-set) `"sync":true` to routinely check Notehub for inbound Notefile changes.

With `sync:true` both the Notecard and Notehub employ mechanisms to ensure that the socket connection between the Notecard and Notehub does not "silently" drop, as can happen with wireless connections. These mechanisms consume additional data usage, but allow a robust and near instantaneous notification of changes from Notehub to Notecard, which is essential in some applications.

| Test: Idle (hub.set with sync:false) | Data    |
| ------------------------------------ | ------- |
| One (1) hour idle                    | 1.3 KB  |
| Ten (10) hours idle                  | 11.7 KB |

| Test: Idle (hub.set with sync:true) | Data    |
| ----------------------------------- | ------- |
| One (1) hour idle                   | 2.5 KB  |
| Ten (10) hours idle                 | 25.6 KB |

### Additional Notes and FAQs

- **Why is less bandwidth required (sometimes) to send 10 Notes vs 1 Note?**
  - This is due to the fact that binary compression on the Notecard is only triggered at a certain threshold. This scenario is highly dependent on the size of the Note body or payload.
- **Why do syncs in continuous mode generally consume slightly less bandwidth than in periodic/minimum mode?**
  - Periodic syncs require a small amount of overhead to establish a session, while continuous mode syncs are performed during an already-established session.
- **Why do syncs involving .qos, .qis, or .dbs files consume more bandwidth than similar syncs with .qo, .qi, or .db Notefiles?**
  - If any of the Notefiles in a sync has a .qos, .qis, or .dbs file extension the Notecard must establish a TLS connection to Notehub before performing the sync, and the establishment of a TLS connection has an overhead of \~4KB.

[Low-Power Firmware Design](https://dev.blues.io/notecard/notecard-walkthrough/low-power-firmware-design.md "Low-Power Firmware Design") [Working with the Notecard AUX Pins](https://dev.blues.io/notecard/notecard-walkthrough/working-with-the-notecard-aux-pins.md "Working with the Notecard AUX Pins")
