Goal: Understand exactly how this Step 4 demo uses localStorage to collect and save data right in your browser.
← Back to Step 4Imagine your web browser has a small, private filing cabinet for each website you visit. localStorage is the name for this filing cabinet. It lets our experiment save information directly on your computer. This is great because the data stays on your machine, it's private, and it persists even if you refresh the page or close the browser.
This is different from saving to a server, which involves sending your data over the internet to a remote computer. For this tutorial, we are keeping everything local and simple.
First, our code creates an empty container to hold all the data we collect. In JavaScript, this is called an array, which is just a fancy word for a list. We give it a descriptive name, `experimentData`.
// Global state: Create an empty list to store all our trial data
let experimentData = [];
let trialCount = 0; // Also create a counter to keep track of trials
Next, inside the `logChoice` function, we define exactly what information to capture every time you click a button (Rock, Paper, or Scissors). We create a small data "packet" (called an object in JavaScript) that includes the trial number, a timestamp, and your choice.
function logChoice(choice) {
trialCount++; // Increment the trial counter
// Create a "packet" of data for this specific trial
const trialData = {
trial: trialCount,
timestamp: new Date().toISOString(), // Record the exact time
playerChoice: choice,
step: 4, // Note which step this data is from
status: 'localStorage_collection' // Note the data collection method
};
// Add this new data packet to our main list
experimentData.push(trialData);
// Immediately save the entire updated list to the browser's storage
saveData();
// Update the status message on the screen
updateStatus(choice);
}
The `saveData` function takes our `experimentData` list, converts it into a special text format called JSON, and saves it to `localStorage` with a unique key, `rpsExperimentData`.
function saveData() {
// The browser can only store text, so we convert our data list to a string
// JSON.stringify is the standard way to do this
localStorage.setItem('rpsExperimentData', JSON.stringify(experimentData));
}
When you first open or refresh the page, the `loadData` function checks the browser's "filing cabinet" to see if any data already exists from a previous session. If it does, it loads it back into our `experimentData` list.
function loadData() {
// Look for our data in the browser's storage
const savedData = localStorage.getItem('rpsExperimentData');
// If we found something...
if (savedData) {
// ...convert it from a text string back into a usable JavaScript list
experimentData = JSON.parse(savedData);
// And update our trial counter to match
trialCount = experimentData.length;
}
}
To make all this happen automatically, we use a special event listener that runs code as soon as the page has finished loading. This single block of code kicks everything off in the right order.
// When the HTML document is fully loaded and ready...
document.addEventListener('DOMContentLoaded', () => {
// 1. Check for and load any data from previous sessions
loadData();
// 2. Update the status message based on what was (or wasn't) loaded
updateStatus();
// 3. Log helpful messages to the developer console
console.log('🚀 Step 4: Data collection experiment loaded');
if (experimentData.length > 0) {
console.log(`📁 Found ${experimentData.length} existing trials`);
} else {
console.log('📝 No existing data - ready for new session');
}
});
Once you've collected data, you need a way to get it out of the browser. The process involves converting your data list into text and creating a temporary download link.
// Function to download data as a JSON file (great for code)
function downloadJSON() {
// First, convert your data list into a nicely formatted text string
const dataStr = JSON.stringify(experimentData, null, 2);
// Create a 'Blob', which is a file-like object for the browser
const dataBlob = new Blob([dataStr], {type: "application/json"});
// Create a temporary, invisible URL that points to our data blob
const url = URL.createObjectURL(dataBlob);
// Create an invisible link element
const link = document.createElement('a');
link.href = url;
link.download = "rps-data.json"; // Set the desired filename
// Programmatically click the link to trigger the browser's download dialog
link.click();
}
// Function to download data as a CSV file (great for spreadsheets)
function downloadCSV() {
// Define the column headers for your file
const headers = "trial,timestamp,playerChoice,step,status";
// Convert each data object in your list into a single line of text
const rows = experimentData.map(d => `${d.trial},${d.timestamp},${d.playerChoice},${d.step},${d.status}`);
// Join the headers and all the rows into one big string
const csvContent = [headers, ...rows].join("\n");
const dataBlob = new Blob([csvContent], {type: "text/csv"});
const url = URL.createObjectURL(dataBlob);
const link = document.createElement('a');
link.href = url;
link.download = "rps-data.csv";
link.click();
}
You can see all of these functions working together in the step4-experiment.js file in your code editor. Reading the actual file is a great way to understand how all the pieces connect.
In this step, we used localStorage to collect data. In Step 5, we'll take this a step further and use the same browser storage to manage complex experiment configurations. You'll see how to save and load different settings for your AI opponents, which is a powerful way to design more advanced studies.