ESP8266: Visualizing Temp/Humidity Data

ESP8266: Visualizing Temp/Humidity Data

by ACROBOTIC Industries


Time to complete: 10–15min; Level of difficulty: Beginner

This guide will show you how to quickly set up an ESP8266 Serial to Wi-Fi module to read temperature and humidity data from a DHT-22 sensor and publish it to the web. We’ll set up a widget to easily visualize and monitor the measured data!

List of Materials

  • 1 x ESP8266 (ESP-12E) Development Board
  • 1 x Hum. and Temp. Sensor (DHT-22)
  • 1 x Jumper Wires Male/Male - 10-pack
  • 1 x Half-Sized Solderless Breadboard

Obtaining the Code

For this activity, we'll be loading a program to our ESP8266 Development Board, it's available in our Github repository:

We can open a new window in the Arduino environment and copy-paste the code.  We'll of course need to setup the Arduino IDE to program the ESP8266.  In addition, we'll need to install a library that will allow us to communicate with the DHT-22 sensor.

Step-by-step Video

We've made a video following the process described in this tutorial, if that's your preferred media for tutorials go right ahead:

Web Frontend for Visualizing ESP8266 (ESP-12E) Data

Installing Additional Libraries

In order to use the code we've written for our data visualization application, we'll need to install a libary.  Fortunately, the latest version of the Arduino software (IDE) includes a library manger.  Simply select the menu option Sketch → Include Library → Library Manager... and search for "DHT".  After selecting the latest version from the drop-down menu, click install and you're set!

Arduino IDE Library Manager

Temperature and Humidity Sensor Operation

The DHT family of sensors provide an effective and inexpensive way to collect temperature and humidity data using any microcontroller development board or single-board computer.  The sensors are limited to collect data at around 1Hz, but typically temperature and humidity do not fluctuate on a fast timesacale.

DHT-22/AM2302 Sensor

The sensors are comprised by a capacitive humidity sensor and a temperature-sensitive resistor (thermistor).  Different than simple analog sensors, which change resistance when as they detect a specific parameter, the DHTs have a chip inside that converts the analog sensor measurements to digital values.  The digital signal uses a private communication protocol that shares some similarities with the 1-Wire protocol (a major difference is that the DHTs do not posses an address).

The protocol has, of course, been reversed engineered and ported over to libraries available for most microcontroller development boards and single-board computers.  There are two models in the DHT family, which share a common pinout, shape, and communication protocol:

DHT-11 DHT-22
Ultra low cost Low cost
3~5V power and I/O; 2.5mA max current (requesting data) 3~5V power and I/O; 2.5mA max current (requesting data)
Hum.: 20~80% ± 5%
Temp.: 0~50°C ± 2°C 
Hum.: 0~100% ± 5%
Temp.: –40~125°C ± 0.5°C 
0.5 Hz max sampling rate 1 Hz max sampling rate
Size: 15.5mm x 12mm x 5.5mm Size: 15.1mm x 25mm x 7.7mm
4 pins with 0.1in spacing (VCC, DATA, NC, GND) 4 pins with 0.1in spacing (VCC, DATA, NC, GND)

As you can see, the DHT-22 is a little more accurate and good over a slightly larger range. Both use a single digital pin and are 'sluggish' in that you can't query them more than once every second or two.

Wiring: DHT Dataviz Ubidots

The wiring of the DHT sensor is straight forward following the diagram below.  Ensuring that the board isn't powered, we can place it on a solderless breadboard with the USB micro-B connector facing outwards.  Then, using a jumper wire, connect one of the GND pins on the ESP8266 Development Board to the rightmost pin on the DHT-22 sensor. Also connect the leftmost pin of the DHT-22 sensor (supply voltage) to 3.3VDC.  You can use the vertical rails on the breadboad as we've done, which makes the wiring more manegeable.

ESP8266 Weather Station Wiring Diagram

Proceed to connect the sensor's 2nd pin (from the left) to pin D2 of the board. Finally, connect the 1KOhm resistor between the 3.3V supply voltage and the data pin, which will act as a pull-up on the data signal.

Code Walkthrough: DHT Tester

After double-checking the wiring, we can go ahead and connect the USB micro-B cable to the ESP8266 board and our computer (remember to install the VCP drivers if you haven't done so already).  We can then upload the dht_sensor_test.ino file to ensure the proper operation of the DHT-22 sensor.

In the the first portion of the code  we define the pin that will be used for communicating with the sensor, and the type of sensor we'll be using (the library supports a few models that share the same functionality).  As usual, we also initialize the Serial object to communicate via USB with the computer.

#include "DHT.h"

#define DHTPIN D2     // what pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302)

DHT dht(DHTPIN, DHTTYPE); // instantiate a DHT object

void setup() {
  Serial.println("DHTxx test!");
  dht.begin(); // call the DHT 'start' method for collecting data

In the second portion of the code, we call the methods that handle the communication with the sensor.  These high-level functions return the data already interpreted.  For example calling the readTemperature() method with no arguments returns the temperature data in Celsius (passing a value of true makes the method return Fahrenheit).

  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println("Failed to read from DHT sensor!");

  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);

  Serial.print("Humidity: ");
  Serial.print(" %\t");

The computeHeatIndex() method returns the Heat Index, which is a function of both humidity and temperature.  As the sensors are a bit sluggish, we set a 2-second delay at the beginning of each measurement iteration to ensure that it's ready for the next cycle.  The loop() function is mostly for sending the measured values to the Serial object, so that they can be visualized on the Serial Monitor window:

Serial Monitor Output of the DHT Sensor Test

A functioning sensor will result in temperature and humidity reading printing to the serial monitor.

Configuring the Ubidots Backend API

In order to publish our Temperature and Humidity data to the web we need two things in place: a place that we can access and store the data, and a way to communicate with it.  The way this is typically done is through a Web Application (place) and an API (way of communicating).

A Web Application is similar to other applications (programs) that run locally on our computers with the distinction that they reside on the web (e.g., Yahoo Mail and Google Maps). The API, in this context, specifies the way we exchange data with the Web Application. 

In this tutorial, we will be using Ubidots as our choice for Web Application, and we will show how to use the specifications of their API in order to store our Temperature and Humidity measurements.  The very first step is to open up a browser and navigate to and setup an account.

Ubidots Account Signup Page

After creating the account we're ready to setup the data source that will provide the API to publish our data.  To do so, we can click on "Sources" from the Top Navigation Menu, and on the new page select "Add Data Source".

Adding a Data Source on Ubidots

Feel free to name the Data Source anything you'd like, in our case we named it "ESP8266 IoT WS".  Hit enter after naming it, and click on the name to go onto the next screen.  Next, we can add a variable to the Data Source that will contain the measurements collected and published by our ESP8266.  In this specific case, we'll want to add two variables of type "Default": one named "Temperature"  and named "Humidity".  

Adding a Variable to a Data Source in Ubidots

After both variables are created, we are going to need their "Variable ID" value so that we can substitute them in our DHT Dataviz Ubidots program.  To do so, from the "Data Source" view we can click on either variables' information icon on the top right-hand corner of the widget.

Getting the Variables' ID Value on Ubidots

We'll be using both "Variable ID" values on the next step.  The last piece we'll need is the security token that prevents other users from posting data to our variables.  In order to get this token, we can use the Top Navigation Menu to select our profile page, which is linked from the drop-down menu under our username.

We can then use the Left Navigation Menu to select "API Keys" and click on the "Create Token" button.  The generated alphanumeric string is the Authentications Token we'll need for the next step!  Unlike we've done below, be sure to keep your token safe (i.e., hidden) smile

Getting the Access Token on Ubidots

Code Walkthrough: DHT Dataviz Ubidots

We're now ready to run our second program DHT Dataviz Ubidots.  As we did in the previous program (DHT Test) we begin by defining a few constants and variables that will be used throughout the code.  And, we also create an instance of the DHT Class.  We'll be using the built-in LED on our ESP8266 Development Board, which is connected to pin 16, for debugging purposes.  In this section of the code is where we modify values that depend on our particular setup:

  • idvariable1: the "Variable ID" alphanumeric string from Ubidots corresponding to "Temperature"
  • idvariable2: the "Variable ID" alphanumeric string from Ubidots corresponding to "Humidity"
  • token: the "Access Token" alphanumeric string from our Ubidots account API settings
  • ssid: the name of our local Wi-Fi network
  • password: the password of our local Wi-Fi network

A step-by-step guide is included on the previous step for how to find these values.  After you've substituted them in the code, you can go ahead and connect the ESP8266 Development Board to the USB port of the computer and upload the code.

#define errorPin 16
#define DHTPIN D2
#define DHTTYPE DHT22

// Instantiates and initializes the dht object

// Define and initialize constants and variables that we'll use later in the code
const int sleepTimeS = 20;  // Time to sleep (in seconds) between posts to Ubidots
long lastReadingTime = 0;
WiFiClient client;
char results[4];

// After creating an account on Ubidots, you'll be able to setup variables where you 
// will store the data. In order to post the measurements to the Ubidots variables,
// we need their "IDs", which are given on the website
String idvariable1 = "------your_temperature_variableID--------";
String idvariable2 = "------your_humidity_variableID----------";

// In addition, we'll need the API token, which is what prevents other users
// Ubidots to publish their data to one of your variables
String token = "---------your_access_token------------";

// We'll also initialize the values for our Wi-Fi network
const char* ssid = "your_WiFi_SSID";
const char* password = "your_WiFi_password";

After initializing the variables we define our setup() function.  Therein we initialize Serial Communication, DHT Sensor, and the Wi-Fi connection between the ESP8266 and your local Wi-Fi network.

  // Initialize Serial (USB) communication, which will be used for sending debugging messages
  // to the computer
  // Start the communication with the DHT sensor by callibg the begin method of the dht object:W
  // Manual delay while the communication with the sensor starts

  // If networks are found, attempt to connect to our Wi-Fi network
  WiFi.begin(ssid, password);

  // While the connection is not established, IDLE inside this while loop
  while (WiFi.status() != WL_CONNECTED) {

The loop() function is very compact, and it only includes calls to other functions that do the hard work.  We use the methods of the DHT Class to get the temperature and humidity measurements from the sensor, and we pass those values to our user-defined function ubiSave_value().  We also print a few messages with the Serial object so that we can debug any problems using the Serial Monitor when the code is running!

  // Read the current temperature and humidity measured by the sensor
  float temp = dht.readTemperature(true);
  float hum = dht.readHumidity();

  // Call our user-defined function ubiSave_value (defined below), and pass it both the 
  // measurements as well as the corresponding Ubidots variable IDs
  ubiSave_value(String(idvariable1), String(temp));
  ubiSave_value(String(idvariable2), String(hum));


As mentioned, the main portion of this program is handled by functions defined outside of loop().  The main one is defined in our code and has the name ubiSave_value().  This function takes two parameters, a Ubidots "Variable ID" string and a value.  The two parameters that are passed are used to form the URL specified by the Ubidots API, where we need to post the data that we want to store in the corresponding variable.

The Ubidots API  tells us that in order to add a value to a variable on one of the Data Sources in our account, we need to send an HTTP request with the following specifications:

  • Method: POST
  • Request-URI:
  • HTTP-Version: HTTP/1.1
  • Host:
  • Content-Type: application/json
  • Content-Length: length of the value that's to be stored
  • X-Auth-Token: our Ubidots account's alphanumeric token
Message Body
  • The data in JSON format (e.g., {"value" : "NNN"} where NNN is a number)

To construct the request within our program, we use the WiFiClient object quite similarly than we would the Serial object.  That is using the WiFiClient's println() method.  This, of course, after connecting to the server (port 80) using the connect() method:

  // Prepare the value that we're to send to Ubidots and get the length of the entire string
  // that's being sent
  int num=0;
  String var = "{\"value\": " + String(value)+"}"; // We'll pass the data in JSON format
  num = var.length();

  // If we get a proper connection to the Ubidots API
  if (client.connect("", 80)) {
    Serial.println("connected ubidots");

    // Construct the POST request that we'd like to issue
    client.println("POST /api/v1.6/variables/"+idvariable+"/values HTTP/1.1");
    // We also use the Serial terminal to show how the POST request looks like
    Serial.println("POST /api/v1.6/variables/"+idvariable+"/values HTTP/1.1");
    // Specify the contect type so it matches the format of the data (JSON)
    client.println("Content-Type: application/json");
    Serial.println("Content-Type: application/json");
    // Specify the content length
    client.println("Content-Length: "+String(num));
    Serial.println("Content-Length: "+String(num));
    // Use our own API token so that we can actually publish the data
    client.println("X-Auth-Token: "+token);
    Serial.println("X-Auth-Token: "+token);
    // Specify the host
    // Send the actual data

The rest of the code in this user-defined function deals with the the case where we can't connect to the server, and also prints the response we get from it if the connection is succesful.

Using the Ubidots Frontend Widgets

Once the code is uploaded to the ESP8266 Development Board the measured temperature and humidity values start being posted to the Ubidots API.  If everything is configured properly, we can then use "Widgets" to build our Frontend and visualize the stored data.  To do this on Ubidots, we simply use the Top Navigation Menu to access the "Dashboard".

For new accounts, there are quite a few example Widgets already in the "Dashboard".  We can remove them (optional) by clicking on the trash can icon on the top right corner of the Widget.   To add our own Widget we click on the icon on the top right corner of the page, and select Chart → Line chart from the options.

Data Visualization Options on Ubidots

After selecting the type of visualization, we can then choose the Data Source and Variable that we want to visualize.  In our case, we find the Temperature and Humidity variables under the My ESP8266 source.

Choosing a Data Source and Variable for Visualization on Ubidots

After repeating the process for both the avaiable variables (Temperature and Humidity) we can start visualizing our data.  The information can be accessed from wherever there's an Internet connection available even if the ESP8266 Development Board isn't physically present nearby!

Visualizing Data on Ubidots

Leave a comment

  • Please note, comments must be approved before they are published

$1 Days
$2 Hours
$3 Minutes
$4 Second
{ "en":{ "general": { "field": { "required": "Required", "actions": "Actions", "top_btn": "Top" }, "accessibility": { "skip_to_content": "Skip to content", "close_modal": "Close (esc)" }, "meta": { "tags": "Tagged \"[[ tags ]]\"", "page": "Page [[ page ]]" }, "404": { "title": "404 Page Not Found", "subtext": "The page you requested does not exist.", "link": "Continue shopping" }, "pagination": { "previous": "Previous", "next": "Next", "current_page": "Page [[ current ]] of [[ total ]]" }, "password_page": { "opening_soon": "Opening Soon", "login_form_heading": "Enter store using password", "login_form_password_label": "Password", "login_form_password_placeholder": "Your password", "login_form_submit": "Enter", "signup_form_email_label": "Email", "signup_form_success": "We will send you an email right before we open!", "admin_link_html": "Are you the store owner? Log in here<\/a>", "password_link": "Enter using password", "powered_by_shopify_html": "This shop will be powered by [[ shopify ]]" }, "social": { "share_on_facebook": "Share", "share_on_twitter": "Tweet", "share_on_pinterest": "Pin it", "alt_text": { "share_on_facebook": "Share on Facebook", "share_on_twitter": "Tweet on Twitter", "share_on_pinterest": "Pin on Pinterest" } }, "search": { "no_results_html": "Your search for \"[[ terms ]]\" did not yield any results.", "results_with_count": { "one": "[[ count ]] result for \"[[ terms ]]\"", "other": "[[ count ]] results for \"[[ terms ]]\"" }, "title": "Search our site", "placeholder": "Search", "submit": "Submit", "close": "Close search" }, "newsletter_form": { "newsletter_email": "Join our mailing list", "email_placeholder": "Email address", "confirmation": "Thanks for subscribing", "submit": "Subscribe", "show_me_text": "Do not show me again" }, "filters": { "show_more": "Show More", "show_less": "Show Less" }, "breadcrumbs": { "home": "Home", "create_account": "Create account", "account": "Account", "addresses": "Addresses" }, "item": { "remove": "Remove Item" } }, "sections": { "header": { "top_header_login": "Login", "top_header_register": "Register", "top_header_wishlist": "Wish list", "register_dropdown": "No account? Create one here", "forgot": "Forgot password", "all_collection": "All Collections", "world_wide_delivery": "Worldwide delivery", "shipping_text": "Free UK Delivery on orders over £ 100", "hot_line": "Hot line" }, "menu": { "mobile_menu_tab": "Menu", "mobile_account_tab": "Account", "mobile_settings_tab": "Settings" }, "slideshow": { "next_slide": "Next slide", "previous_slide": "Previous slide", "pause_slideshow": "Pause slideshow", "play_slideshow": "Play slideshow", "play_video": "Play video", "close_video": "Close video" }, "map": { "get_directions": "Get directions", "address_error": "Error looking up that address", "address_no_results": "No results for that address", "address_query_limit_html": "You have exceeded the Google API usage limit. Consider upgrading to a Premium Plan<\/a>.", "auth_error_html": "There was a problem authenticating your Google Maps account. Create and enable the JavaScript API<\/a> and Geocoding API<\/a> permissions of your app." } }, "blogs": { "article": { "view_all": "View all", "all_topics": "All topics", "by_author": "by [[ author ]]", "posted_in": "Posted in", "read_more": "Read more", "back_to_blog": "Back to [[ title ]]" }, "comments": { "title": "Leave a comment", "name": "Name", "email": "Email", "message": "Message", "post": "Post comment", "moderated": "Please note, comments must be approved before they are published", "success_moderated": "Your comment was posted successfully. We will publish it in a little while, as our blog is moderated.", "success": "Your comment was posted successfully! Thank you!", "comments_with_count": { "one": "[[ count ]] comment", "other": "[[ count ]] comments" } } }, "cart": { "general": { "title": "Your cart", "note": "Add a note to your order", "remove": "Remove", "subtotal": "Subtotal", "savings": "You're saving", "shipping_at_checkout": "Shipping & taxes calculated at checkout", "update": "Update", "checkout": "Process Check out", "empty": "Your cart is currently empty.", "cookies_required": "Enable cookies to use the shopping cart", "edit": "Edit", "cancel": "Cancel", "continue_shopping": "Continue shopping", "recently_added_item": "Recently added item(s)", "remove_item": "Remove This Item", "view_and_edit_cart": "View and edit cart", "clear": "Clear cart", "empty_page_title": "Shopping Cart is Empty", "here": "here", "empty_continue_html": "Click here to continue shopping.", "processing": "Processing...", "items_count_label" : "[[ count ]] item(s) in your cart", "ok" : "Ok" }, "label": { "product": "Product", "price": "Price", "quantity": "Quantity", "total": "Total", "total_item": "Total item", "sub_total_top": "Cart Subtotal" } }, "collections": { "general": { "view_all": "View all", "clear_all": "Clear All", "no_matches": "Sorry, there are no products in this collection", "items_with_count": { "one": "[[ count ]] product", "other": "[[ count ]] products" }, "load_more": "Load More", "sidebar_btn": "Filter by" }, "sorting": { "title": "Sort by", "manual": "Featured", "best_selling": "Best Selling", "title_ascending": "Alphabetically, A-Z", "title_descending": "Alphabetically, Z-A", "price_ascending": "Price, low to high", "price_descending": "Price, high to low", "created_descending": "Date, new to old", "created_ascending": "Date, old to new" }, "filters": { "title_tags": "Filter", "all_tags": "All products", "categories": "categories", "title": "Filter", "color": "Color", "size": "Size", "brand": "Brand", "price": "Price", "green": "Green", "blue": "Blue", "red": "Red", "pink": "Pink", "black": "Black", "purple": "Purple", "white": "White", "orange": "Orange" }, "product_item": { "quick_shop": "Quick View", "compare": "Compare", "wishlist": "Add to Wishlist" } }, "contact": { "form": { "name": "Name", "email": "Email", "phone": "Phone Number", "message": "Message", "submit": "Submit", "post_success": "Thanks for contacting us. We'll get back to you as soon as possible.", "address": "Address", "telephone": "Telephone", "title": "Write us", "required": "Required" } }, "customer": { "account": { "title": "My Account", "details": "Account Details", "view_addresses": "View Addresses", "return": "Return to Account Details" }, "activate_account": { "title": "Activate Account", "subtext": "Create your password to activate your account.", "password": "Password", "password_confirm": "Confirm Password", "submit": "Activate Account", "cancel": "Decline Invitation" }, "addresses": { "title": "Your Addresses", "default": "Default", "add_new": "Add a New Address", "edit_address": "Edit address", "first_name": "First Name", "last_name": "Last Name", "company": "Company", "address1": "Address1", "address2": "Address2", "city": "City", "country": "Country", "province": "Province", "zip": "Postal\/Zip Code", "phone": "Phone", "set_default": "Set as default address", "add": "Add Address", "update": "Update Address", "cancel": "Cancel", "edit": "Edit", "delete": "Delete", "delete_confirm": "Are you sure you wish to delete this address?" }, "login": { "title": "Login", "desc": "If you have an account, sign in with your email address.", "email": "Email", "password": "Password", "forgot_password": "Forgot your password?", "sign_in": "Sign In", "guest_title": "Continue as a guest", "guest_continue": "Continue" }, "orders": { "title": "Order History", "order_number": "Order", "date": "Date", "payment_status": "Payment Status", "fulfillment_status": "Fulfillment Status", "total": "Total", "none": "You haven't placed any orders yet." }, "order": { "title": "Order [[ name ]]", "date": "Placed on [[ date ]]", "cancelled": "Order Cancelled on [[ date ]]", "cancelled_reason": "Reason: [[ reason ]]", "billing_address": "Billing Address", "payment_status": "Payment Status", "shipping_address": "Shipping Address", "fulfillment_status": "Fulfillment Status", "discount": "Discount", "shipping": "Shipping", "tax": "Tax", "product": "Product", "sku": "SKU", "price": "Price", "quantity": "Quantity", "total": "Total", "fulfilled_at": "Fulfilled [[ date ]]", "subtotal": "Subtotal" }, "recover_password": { "title": "Reset your password", "email": "Email", "submit": "Submit", "cancel": "Cancel", "subtext": "We will send you an email to reset your password.", "success": "We've sent you an email with a link to update your password." }, "reset_password": { "title": "Reset account password", "subtext": "Enter a new password for [[ email ]]", "password": "Password", "password_confirm": "Confirm Password", "submit": "Reset Password" }, "register": { "title": "Create Account", "first_name": "First Name", "last_name": "Last Name", "email": "Email", "password": "Password", "submit": "Create", "desc": "Creating an account is easy. Just fill in the form below." } }, "homepage": { "onboarding": { "product_title": "Your product's name", "product_description": "This area is used to describe your product’s details. Tell customers about the look, feel, and style of your product. Add details on color, materials used, sizing, and where it was made.", "collection_title": "Your collection's name", "blog_title": "Your post's title", "blog_excerpt": "Your store hasn’t published any blog posts yet. A blog can be used to talk about new product launches, tips, or other news you want to share with your customers. You can check out Shopify’s ecommerce blog for inspiration and advice for your own store and blog.", "blog_author": "Author name", "no_content": "This section doesn’t currently include any content. Add content to this section using the sidebar." } }, "layout": { "navigation": { "search": "Search", "toggle": "expand\/collapse", "expand": "expand", "collapse": "collapse", "all_categories": "All Categories" }, "cart": { "title": "Cart", "items_count": { "one": "item", "other": "items" } }, "customer": { "account": "Account", "log_out": "Log out", "logout": "Log out", "log_in": "Log in", "create_account": "Create account", "sign_up": "Sign up", "wishlist": "Wishlist" }, "footer": { "social_platform": "[[ name ]] on [[ platform ]]" }, "list_page": { "grid": "Grid", "list": "List" } }, "products": { "product": { "regular_price": "Regular price", "sold_out": "Sold out", "unavailable": "Unavailable", "on_sale": "Sale", "quantity": "Quantity", "add_to_cart": "Add to cart", "back_to_collection": "Back to [[ title ]]", "related_title": "Related Products", "qty_increase": "Increase", "qty_decrease": "Decrease", "deal_days": "Days", "deal_hours": "Hours", "deal_minutes": "Minutes", "deal_second": "Second", "select_option": "Select Option", "add_to_wishlist": "Add to Wishlist", "add_to_review": "Add to review", "compare_success_msg": "[[ product_title ]] has added to comparing box successful", "compare_exist_msg": "[[ product_title ]] is exist in comparing box", "compare_cart_msg": "[[ product_title ]] has added to shopping cart", "compare_remove_msg": "[[ product_title ]] has removed from comparing box", "compare_remove_msg": "[[ product_title ]] has removed from comparing box", "comparing_box": "Comparing box", "compare_no_items": "There is no items in comparing box", "wishlist_success_msg": "[[ product_title ]] has added to wishlist successful", "wishlist_exist_msg": "[[ product_title ]] is exist in wishlist", "wishlist_cart_msg": "[[ product_title ]] has added to shopping cart", "wishlist_box": "Wishlist", "wishlist_remove_msg": "[[ product_title ]] has removed from wishlist", "wislist_no_items": "There is no items in wishlist", "upsell_cart_msg": "\"[[ product_title ]]\" has added to shopping cart", "upsell_block_title": "Frequently bought with \"[[ product_title ]]\"", "upsell_cart_qty": "[[ count ]] item(s)", "upsell_product_page_title": "You may also like these products", "upsell_checkout_btn": "Checkout", "share": "Share product", "share_on_facebook": "Share on Facebook", "share_on_twitter": "Share on Twitter", "share_on_pinterest": "Share on Pinterest", "share_on_google": "Share on Google+", "share_on_linkedin": "Share on LinkedIn", "availability": "Availability", "in_stock": "In Stock", "out_of_stock": "Out of stock", "quick_overview": "Quick Overview", "details": "Details", "reviews": "Reviews", "first_review": "Be the first review", "tags": "Product Tags", "size_chart": "Size Chart", "options": "Options", "vendor": "Vendor", "features": "Features", "sale_left_text": "[[ sales ]] SOLD. HURRY! ONLY A FEW LEFT!", "checkout_text": "Secured and trusted checkout with" }, "upsell": { "recommend_text": "Someone purchased a", "minute_ago": "minutes ago" } }, "gift_cards": { "issued": { "title_html": "Here's your [[ value ]] gift card for [[ shop ]]!", "subtext": "Your gift card", "disabled": "Disabled", "expired": "Expired on [[ expiry ]]", "active": "Expires on [[ expiry ]]", "redeem_html": "Use this code at checkout to redeem your [[ value ]] gift card", "shop_link": "Start shopping", "print": "Print this gift card", "remaining_html": "[[ balance ]] left", "add_to_apple_wallet": "Add to Apple Wallet" } }, "date_formats": { "month_day_year": "%B %d, %Y" } } }