cronometer-node
v0.1.0
Published
Node.js client for Cronometer - export your nutrition, exercise, and biometric data
Maintainers
Readme
cronometer-node
A Node.js client for Cronometer - export your nutrition, exercise, and biometric data programmatically.
This library is a JavaScript port of gocronometer.
Installation
npm install cronometer-nodeRequirements
- Node.js 18.0.0 or higher
- A Cronometer account
Quick Start
import { CronometerClient } from 'cronometer-node';
const client = new CronometerClient({
username: process.env.CRONOMETER_USERNAME,
password: process.env.CRONOMETER_PASSWORD,
});
// Login
await client.login();
// Export food servings for a date range
const servings = await client.exportServings({
start: '2024-01-01',
end: '2024-01-31',
});
// Save to file
await client.saveToFile(servings, './servings.csv');
// Logout when done
await client.logout();API Reference
CronometerClient
The main client class for interacting with Cronometer.
Constructor
const client = new CronometerClient({
username: '[email protected]',
password: 'your-password',
});Methods
login()
Authenticates with Cronometer. Must be called before any export methods.
await client.login();logout()
Logs out and clears the session.
await client.logout();Export Methods (Raw CSV)
All export methods accept a date range object:
const dateRange = {
start: '2024-01-01', // YYYY-MM-DD format
end: '2024-01-31',
};| Method | Description |
|--------|-------------|
| exportDailyNutrition(dateRange) | Daily nutrition summary |
| exportServings(dateRange) | Individual food servings |
| exportExercises(dateRange) | Exercise records |
| exportBiometrics(dateRange) | Biometric measurements (weight, blood pressure, etc.) |
| exportNotes(dateRange) | Notes entries |
All methods return a Promise<string> containing the raw CSV data.
Export Methods (Parsed)
For convenience, parsed versions return JavaScript objects:
| Method | Returns |
|--------|---------|
| exportDailyNutritionParsed(dateRange) | DailyNutritionRecord[] |
| exportServingsParsed(dateRange) | ServingRecord[] |
| exportExercisesParsed(dateRange) | ExerciseRecord[] |
| exportBiometricsParsed(dateRange) | BiometricRecord[] |
| exportNotesParsed(dateRange) | NoteRecord[] |
Example:
const records = await client.exportServingsParsed({
start: '2024-01-15',
end: '2024-01-15',
});
for (const record of records) {
console.log(`${record.foodName}: ${record.energyKcal} kcal`);
}saveToFile(data, filePath)
Utility method to save data to a file.
const csv = await client.exportServings(dateRange);
await client.saveToFile(csv, './servings.csv');Data Types
ServingRecord
Contains detailed nutritional information for each food entry:
{
recordedTime: Date,
group: string, // Meal group (Breakfast, Lunch, etc.)
foodName: string,
quantityValue: number,
quantityUnits: string,
energyKcal: number,
proteinG: number,
carbsG: number,
fatG: number,
fiberG: number,
// ... 60+ additional nutrient fields
}ExerciseRecord
{
recordedTime: Date,
exercise: string,
minutes: number,
caloriesBurned: number,
group: string,
}BiometricRecord
{
recordedTime: Date,
metric: string, // e.g., "Weight", "Blood Pressure"
unit: string, // e.g., "kg", "mmHg"
amount: number,
}NoteRecord
{
recordedTime: Date,
note: string,
group: string,
}CLI Usage
The package includes a command-line interface for quick exports.
Installation (Global)
npm install -g cronometer-nodeCommands
Export Data
# Export servings to CSV
cronometer export --type servings --start 2024-01-01 --end 2024-01-31 --out servings.csv
# Export daily nutrition summary
cronometer export --type daily --start 2024-01-01 --end 2024-01-31 --out daily.csv
# Export as JSON (parsed data)
cronometer export --type servings --start 2024-01-01 --end 2024-01-31 --json --out servings.json
# Output to stdout
cronometer export --type exercises --start 2024-01-01 --end 2024-01-31Export types: daily, servings, exercises, biometrics, notes
Test Login
cronometer test-loginCredentials
Credentials can be provided via:
Environment variables (recommended):
export CRONOMETER_USERNAME="[email protected]" export CRONOMETER_PASSWORD="your-password" cronometer export --type servings --out servings.csvCommand-line options:
cronometer export --type servings -u "[email protected]" -p "password" --out servings.csv
Security Note: Avoid passing credentials as command-line arguments in shared environments, as they may be visible in process listings.
Examples
Export All Data Types
import { CronometerClient } from 'cronometer-node';
async function exportAllData() {
const client = new CronometerClient({
username: process.env.CRONOMETER_USERNAME,
password: process.env.CRONOMETER_PASSWORD,
});
await client.login();
const dateRange = {
start: '2024-01-01',
end: '2024-01-31',
};
// Export all data types
const [daily, servings, exercises, biometrics, notes] = await Promise.all([
client.exportDailyNutrition(dateRange),
client.exportServings(dateRange),
client.exportExercises(dateRange),
client.exportBiometrics(dateRange),
client.exportNotes(dateRange),
]);
// Save to files
await Promise.all([
client.saveToFile(daily, './daily.csv'),
client.saveToFile(servings, './servings.csv'),
client.saveToFile(exercises, './exercises.csv'),
client.saveToFile(biometrics, './biometrics.csv'),
client.saveToFile(notes, './notes.csv'),
]);
await client.logout();
console.log('All data exported successfully!');
}
exportAllData();Calculate Daily Macros
import { CronometerClient } from 'cronometer-node';
async function getDailyMacros(date) {
const client = new CronometerClient({
username: process.env.CRONOMETER_USERNAME,
password: process.env.CRONOMETER_PASSWORD,
});
await client.login();
const records = await client.exportServingsParsed({
start: date,
end: date,
});
const totals = records.reduce(
(acc, record) => ({
calories: acc.calories + record.energyKcal,
protein: acc.protein + record.proteinG,
carbs: acc.carbs + record.carbsG,
fat: acc.fat + record.fatG,
}),
{ calories: 0, protein: 0, carbs: 0, fat: 0 }
);
await client.logout();
console.log(`Macros for ${date}:`);
console.log(` Calories: ${totals.calories.toFixed(0)} kcal`);
console.log(` Protein: ${totals.protein.toFixed(1)} g`);
console.log(` Carbs: ${totals.carbs.toFixed(1)} g`);
console.log(` Fat: ${totals.fat.toFixed(1)} g`);
return totals;
}
getDailyMacros('2024-01-15');Express.js Integration
import express from 'express';
import { CronometerClient } from 'cronometer-node';
const app = express();
app.get('/api/nutrition', async (req, res) => {
const { start, end } = req.query;
const client = new CronometerClient({
username: process.env.CRONOMETER_USERNAME,
password: process.env.CRONOMETER_PASSWORD,
});
try {
await client.login();
const data = await client.exportServingsParsed({ start, end });
await client.logout();
res.json(data);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(3000);Testing
# Run unit tests (no credentials needed)
npm test
# Run integration tests (requires credentials)
export CRONOMETER_USERNAME="your-email"
export CRONOMETER_PASSWORD="your-password"
npm run test:integrationTroubleshooting
"Could not find anti-CSRF token"
This usually indicates a network issue or that Cronometer's login page structure has changed. Ensure you have internet connectivity and try again.
"Login failed: Invalid username or password"
Double-check your credentials. Note that Cronometer uses your email address as the username.
"GWT authentication failed"
This may occur if Cronometer updates their web application. The GWT permutation values may need to be updated. Please open an issue if this persists.
"Must be logged in to export data"
Ensure you call client.login() before any export methods.
Security
- Never hardcode credentials in your source code
- Use environment variables for credentials
- The library does not store or transmit credentials except to Cronometer's servers
- Session cookies are stored in memory and cleared on logout
License
MIT
Credits
This is a JavaScript port of gocronometer by Jeremy Canady.
