npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cronometer-node

v0.1.0

Published

Node.js client for Cronometer - export your nutrition, exercise, and biometric data

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-node

Requirements

  • 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-node

Commands

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-31

Export types: daily, servings, exercises, biometrics, notes

Test Login

cronometer test-login

Credentials

Credentials can be provided via:

  1. Environment variables (recommended):

    export CRONOMETER_USERNAME="[email protected]"
    export CRONOMETER_PASSWORD="your-password"
    cronometer export --type servings --out servings.csv
  2. Command-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:integration

Troubleshooting

"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.