ThingSpeak Data Logging with ESP32: Channels, Fields and Live Charts

Running your own server is educational, but sometimes you just want sensor data stored online and plotted on a chart without maintaining anything. ThingSpeak, a service from MathWorks, does exactly that. You create a channel, the ESP32 sends values with a simple HTTP request, and ThingSpeak stores them with timestamps and draws charts you can view from any browser or embed in a project report.

In this tutorial you will set up a channel with three fields, send temperature, humidity and Wi-Fi signal strength from an ESP32, customise the charts, and read the latest values back from another device. Free accounts have limits on message rate and yearly message count; check the current licence terms on the ThingSpeak website before planning a long deployment.

How ThingSpeak Organises Data

ConceptDescription
ChannelA container for one device or one data set, identified by a numeric Channel ID
FieldsUp to 8 numeric or text fields per channel, named field1 to field8
EntryOne row in the channel: a timestamp plus values for any of the fields
Write API KeySecret key that allows adding entries; keep it out of public code
Read API KeyNeeded to read a private channel; public channels can be read without it
StatusAn optional text message stored with an entry

Every update creates a new entry, even if you only send one field. That means the fields you send together share the same timestamp, so always send related readings in a single request rather than one request per field.

Creating the Channel

  1. Sign up at thingspeak.com with a MathWorks account and open Channels > My Channels > New Channel.
  2. Name the channel, for example "Lab Weather Node".
  3. Tick Field 1, Field 2 and Field 3 and name them Temperature (°C), Humidity (%) and RSSI (dBm).
  4. Save the channel. Note the Channel ID shown at the top of the page.
  5. Open the API Keys tab and copy the Write API Key and Read API Key.

Test the channel from a browser before writing firmware. Paste the URL below with your own write key. The browser shows a number: the new entry ID. A reply of 0 means the key is wrong or you updated too soon.

https://api.thingspeak.com/update?api_key=YOUR_WRITE_KEY&field1=27.5&field2=60&field3=-55

ESP32 Sketch

The sketch below sends a form-encoded POST request rather than putting the key in a GET URL. It uses WiFiClientSecure with setInsecure() to keep the example short; this encrypts the traffic but does not verify the server's certificate. The security tutorial shows how to pin a root certificate instead.

ESP32 logs DHT22 data and RSSI to three ThingSpeak fields every 20 seconds
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <DHT.h>

const char* WIFI_SSID = "YourWiFi";
const char* WIFI_PASS = "YourWiFiPassword";
const char* WRITE_KEY = "YOUR_WRITE_KEY";
const uint32_t PERIOD_MS = 20000;   // stay above the 15 s free-account limit

DHT dht(4, DHT22);
uint32_t lastUpdate = 0;

long sendToThingSpeak(float t, float h, int rssi) {
  WiFiClientSecure client;
  client.setInsecure();              // encrypts, but no certificate check
  HTTPClient http;
  if (!http.begin(client, "https://api.thingspeak.com/update")) return -1;
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");

  String body = "api_key=" + String(WRITE_KEY) +
                "&field1=" + String(t, 1) +
                "&field2=" + String(h, 1) +
                "&field3=" + String(rssi);

  int code = http.POST(body);
  long entryId = -1;
  if (code == 200) {
    entryId = http.getString().toInt();   // 0 means rejected
  } else {
    Serial.printf("HTTP error %d", code);
    Serial.println();
  }
  http.end();
  return entryId;
}

void setup() {
  Serial.begin(115200);
  dht.begin();
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(500);
  Serial.println("WiFi connected");
}

void loop() {
  if (millis() - lastUpdate < PERIOD_MS) return;
  lastUpdate = millis();

  float t = dht.readTemperature();
  float h = dht.readHumidity();
  if (isnan(t) || isnan(h)) { Serial.println("DHT error, skipped"); return; }

  long id = sendToThingSpeak(t, h, WiFi.RSSI());
  if (id > 0)       Serial.printf("Entry %ld stored", id);
  else if (id == 0) Serial.print("Rejected: too fast or bad key");
  else              Serial.print("Request failed");
  Serial.println();
}

Open the channel's Private View tab. A new point should appear on each chart roughly every 20 seconds. The charts refresh automatically.

Making the Charts Useful

Click the pencil icon on any chart to open its options. The settings that matter most are listed below.

OptionUse
Title, X-axis, Y-axisLabel units so the chart is readable in a report
ResultsHow many recent entries to show
DaysShow a fixed time window instead of a count
Timescale / Average / MedianCombine entries into averages over minutes, which smooths noisy sensors
Min / MaxFix the Y-axis range so small changes are not exaggerated
TypeLine, bar, column or spline

Add a Numeric Display or Gauge widget from the Add Widgets button to show the latest value in large text. For anything more advanced, such as dew point calculated from temperature and humidity, the MATLAB Visualization and MATLAB Analysis apps let you run MATLAB code on your channel data inside ThingSpeak.

Reading Data Back

Another ESP32, a Python script or a mobile app can fetch data with the channel feed API. Append &api_key=YOUR_READ_KEY if the channel is private.

Latest value of field 1 as plain text:
https://api.thingspeak.com/channels/CHANNEL_ID/fields/1/last.txt

Last 10 entries of all fields as JSON:
https://api.thingspeak.com/channels/CHANNEL_ID/feeds.json?results=10

Download the whole channel as CSV:
https://api.thingspeak.com/channels/CHANNEL_ID/feeds.csv

The CSV export is handy for project reports: open it in Excel, plot temperature against time, and compute daily minimum and maximum values.

Common Mistakes

  • Every other update returns 0: the interval is below the limit. Network delays can bunch two requests together, so leave a margin above 15 seconds.
  • Charts show nothing but the entry ID increases: you sent text such as "nan" in a numeric field. Skip the update when the sensor read fails, as the sketch does.
  • Using the Read key to write: the two keys are different; only the Write key accepts updates.
  • Publishing code with the Write key on GitHub: anyone can then fill your channel with junk. Regenerate the key from the API Keys tab if it leaks.
  • HTTP error -1: DNS or TLS failure. Check that Wi-Fi is connected and the board has enough free heap for a TLS session.

Summary

ThingSpeak turns an ESP32 into a cloud data logger with one HTTP request per reading. Group related values into one update, stay above the minimum update interval, configure chart averaging and axis limits, and use the feed API or CSV export to reuse the data elsewhere. When you need instant two-way control rather than logging, Firebase and MQTT-based tools are a better fit.