Can AI build me a free habit tracker?
Yes. A simple habit tracker page or spreadsheet is well within what AI builds reliably, and it saves the subscription.
01Why bot
- Habit trackers are simple: a list, checkboxes and a streak count.
- AI can make it save your progress in your own browser.
- No account, no ads, no fees.
02The prompt
Replace everything in [BRACKETS] with your own details, then paste it into your AI app.
Build a habit tracker as a single HTML file I can open in my browser. Habits to track: [LIST] Features I want: daily checkboxes, current streak per habit, a 30-day grid view. Requirements: - One index.html file, no external libraries. - Save progress in the browser's local storage so it stays after I close the tab. - Clean, phone-friendly design with large tap targets. Explain how to open it and how to back up my data.
03Steps
- Paste the prompt with your habits.
- Save the file and open it in your browser.
- Bookmark it.
04What can go wrong
- Browser storage can be erased if you clear your browsing data. Back it up.
05What to use
06Our test runs
2 runs, each with a different made-up sample. 1 of 2 passed every check.
The made-up sample:
[LIST]Drink water, Meditate, Read 20 minutes, Exercise, Write journal
- Provide a single HTML file with no external libraries
- Store progress in browser local storage
- Include daily checkboxes and current streak per habit
- Explain how to open the file and back up data
- Didn't make up details we never gave it
What came back (excerpt):
Below is a simple habit tracker implemented as a single HTML file. This file uses JavaScript to store data in the browser's local storage, ensuring that your progress is saved even after you close the tab.
Read the full answer
Below is a simple habit tracker implemented as a single HTML file. This file uses JavaScript to store data in the browser's local storage, ensuring that your progress is saved even after you close the tab.
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Habit Tracker</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
background-color: #f0f0f0;
}
.habit {
margin-bottom: 20px;
}
.habit-name {
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
}
.checkboxes {
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-gap: 10px;
}
.checkbox {
width: 30px;
height: 30px;
}
.streak {
font-size: 18px;
color: #00698f;
}
button {
padding: 10px;
border: none;
border-radius: 5px;
background-color: #4CAF50;
color: #fff;
cursor: pointer;
}
button:hover {
background-color: #3e8e41;
}
</style>
</head>
<body>
<h1>Habit Tracker</h1>
<div class="habits">
<div class="habit">
<div class="habit-name">Drink water</div>
<div class="checkboxes" id="water-checkboxes"></div>
<div class="streak" id="water-streak">Streak: 0 days</div>
</div>
<div class="habit">
<div class="habit-name">Meditate</div>
<div class="checkboxes" id="meditate-checkboxes"></div>
<div class="streak" id="meditate-streak">Streak: 0 days</div>
</div>
<div class="habit">
<div class="habit-name">Read 20 minutes</div>
<div class="checkboxes" id="read-checkboxes"></div>
<div class="streak" id="read-streak">Streak: 0 days</div>
</div>
<div class="habit">
<div class="habit-name">Exercise</div>
<div class="checkboxes" id="exercise-checkboxes"></div>
<div class="streak" id="exercise-streak">Streak: 0 days</div>
</div>
<div class="habit">
<div class="habit-name">Write journal</div>
<div class="checkboxes" id="journal-checkboxes"></div>
<div class="streak" id="journal-streak">Streak: 0 days</div>
</div>
</div>
<button id="backup-button">Backup Data</button>
<button id="restore-button">Restore Data</button>
<script>
// Get habits and their checkboxes
const habits = {
water: {
checkboxes: document.getElementById('water-checkboxes'),
streak: document.getElementById('water-streak')
},
meditate: {
checkboxes: document.getElementById('meditate-checkboxes'),
streak: document.getElementById('meditate-streak')
},
read: {
checkboxes: document.getElementById('read-checkboxes'),
streak: document.getElementById('read-streak')
},
exercise: {
checkboxes: document.getElementById('exercise-checkboxes'),
streak: document.getElementById('exercise-streak')
},
journal: {
checkboxes: document.getElementById('journal-checkboxes'),
streak: document.getElementById('journal-streak')
}
};
// Load data from local storage
let data = JSON.parse(localStorage.getItem('habit-tracker'));
if (!data) {
data = {
water: Array(30).fill(false),
meditate: Array(30).fill(false),
read: Array(30).fill(false),
exercise: Array(30).fill(false),
journal: Array(30).fill(false)
};
localStorage.setItem('habit-tracker', JSON.stringify(data));
}
// Render checkboxes
Object.keys(habits).forEach(habit => {
for (let i = 0; i < 30; i++) {
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'checkbox';
checkbox.checked = data[habit][i];
checkbox.addEventListener('change', () => {
data[habit][i] = checkbox.checked;
localStorage.setItem('habit-tracker', JSON.stringify(data));
updateStreaks();
});
habits[habit].checkboxes.appendChild(checkbox);
}
});
// Update streaks
function updateStreaks() {
Object.keys(habits).forEach(habit => {
let streak = 0;
for (let i = 29; i >= 0; i--) {
if (data[habit][i]) {
streak++;
} else {
break;
}
}
habits[habit].streak.textContent = `Streak: ${streak} days`;
});
}
// Backup data
document.getElementById('backup-button').addEventListener('click', () => {
const textarea = document.createElement('textarea');
textarea.value = JSON.stringify(data);
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
alert('Data copied to clipboard');
});
// Restore data
document.getElementById('restore-button').addEventListener('click', () => {
const textarea = document.createElement('textarea');
textarea.placeholder = 'Paste backup data here';
document.body.appendChild(textarea);
textarea.focus();
textarea.addEventListener('blur', () => {
try {
data = JSON.parse(textarea.value);
localStorage.setItem('habit-tracker', JSON.stringify(data));
location.reload();
} catch (e) {
alert('Invalid data');
} finally {
document.body.removeChild(textarea);
}
});
});
updateStreaks();
</script>
</body>
</html>
```
### How to Open It
1. Copy the above code into a text editor (like Notepad on Windows or TextEdit on Mac).
2. Save the file with an `.html` extensionMake sure the user saves the code with an .html extension before opening.
The made-up sample (a messier one):
[LIST]drink water (aim for 8 glasses), morning meditation 5‑10min, read 20 pages, workout (push‑ups or jog), floss teeth, limit social media to 30min, practice guitar, journal before bed
- Provide a single HTML file with no external libraries
- Save progress using browser local storage
- Include daily checkboxes, streak count, and a 30‑day grid view
- Explain how to open the file and back up the data
- Didn't make up details we never gave it
What came back (excerpt):
DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.
Read the full answer
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Habit Tracker</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
background-color: #f0f0f0;
}
.habits {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.habit {
margin: 10px;
padding: 20px;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
width: calc(33.33% - 20px);
text-align: center;
}
.habit input[type="checkbox"] {
margin: 10px;
width: 20px;
height: 20px;
}
.habit span {
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
display: block;
}
.habit .streak {
font-size: 16px;
color: #666;
}
.grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-gap: 10px;
margin-top: 20px;
}
.grid .day {
background-color: #fff;
padding: 10px;
border: 1px solid #ddd;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.grid .day span {
font-size: 16px;
}
.backup {
margin-top: 20px;
text-align: center;
}
</style>
</head>
<body>
<h1>Habit Tracker</h1>
<div class="habits">
<div class="habit">
<span>Drink Water (8 glasses)</span>
<input type="checkbox" id="water" onclick="updateHabit('water', this.checked)">
<div class="streak" id="water-streak">Streak: 0 days</div>
</div>
<div class="habit">
<span>Morning Meditation (5-10min)</span>
<input type="checkbox" id="meditation" onclick="updateHabit('meditation', this.checked)">
<div class="streak" id="meditation-streak">Streak: 0 days</div>
</div>
<div class="habit">
<span>Read (20 pages)</span>
<input type="checkbox" id="read" onclick="updateHabit('read', this.checked)">
<div class="streak" id="read-streak">Streak: 0 days</div>
</div>
<div class="habit">
<span>Workout (push-ups or jog)</span>
<input type="checkbox" id="workout" onclick="updateHabit('workout', this.checked)">
<div class="streak" id="workout-streak">Streak: 0 days</div>
</div>
<div class="habit">
<span>Floss Teeth</span>
<input type="checkbox" id="floss" onclick="updateHabit('floss', this.checked)">
<div class="streak" id="floss-streak">Streak: 0 days</div>
</div>
<div class="habit">
<span>Limit Social Media (30min)</span>
<input type="checkbox" id="social-media" onclick="updateHabit('social-media', this.checked)">
<div class="streak" id="social-media-streak">Streak: 0 days</div>
</div>
<div class="habit">
<span>Practice Guitar</span>
<input type="checkbox" id="guitar" onclick="updateHabit('guitar', this.checked)">
<div class="streak" id="guitar-streak">Streak: 0 days</div>
</div>
<div class="habit">
<span>Journal Before Bed</span>
<input type="checkbox" id="journal" onclick="updateHabit('journal', this.checked)">
<div class="streak" id="journal-streak">Streak: 0 days</div>
</div>
</div>
<div class="grid">
<!-- 30-day grid will be generated here -->
</div>
<div class="backup">
<button onclick="backupData()">Backup Data</button>
<button onclick="restoreData()">Restore Data</button>
</div>
<script>
// Initialize habits and streaks
const habits = {
water: { streak: 0, days: [] },
meditation: { streak: 0, days: [] },
read: { streak: 0, days: [] },
workout: { streak: 0, days: [] },
floss: { streak: 0, days: [] },
'social-media': { streak: 0, days: [] },
guitar: { streak: 0, days: [] },
journal: { streak: 0, days: [] },
};
// Load data from local storage
if (localStorage.getItem('habits')) {
habits = JSON.parse(localStorage.getItem('habits'));
updateUI();
}
// Update habit and streak
function updateHabit(habit, checked) {
const today = new Date().toISOString().split('T')[0];
if (checked) {
habits[habit].days.push(today);
habits[habit].streak = getStreak(habits[habit].days);
} else {
const index = habits[habit].days.indexOf(today);
if (index !== -1) {
habits[habit].days.splice(index, 1);
habits[habit].streak = getStreak(habits[habit].days);
}
}
updateUI();
saveData();
}
// Get streak from days array
function getStreak(days) {
const today =The solution is incomplete and missing the required usage instructions.
How each run works: we fill the prompt with a made-up sample, run it once in Llama 3.3 70B, and GPT-OSS 120B grades the answer against the prompt's own rules. Word limits are counted by code, and every quote flagged as made up is checked against the full answer. Your results can differ. How we test.