Coding an AI-Powered Hydration Widget


Disclosure: This article may contain affiliate links. We only recommend products we believe in.

Proper hydration is critical for metabolic health, mental performance, and exercise recovery. However, standard advice like “8 glasses a day” ignores individual variables like body weight, exercise intensity, climate, and biological status.

For developers building fitness dashboards, a hydration tracker widget is a great feature. In this guide, we’ll write a clean, object-oriented JavaScript module for a hydration widget. We will then explain how to integrate a lightweight AI prompt to parse unstructured natural language diary entries into precise calculation inputs.

The Mathematical Model

Our core algorithm calculates baseline water needs based on body mass, and then adds adjustments for physical activity, climate conditions, and reproductive status.

The Baseline Calculation

Baseline Fluid (fl oz) = weight (lbs) * 0.5

Dynamic Adjustments

  1. Exercise: +24 fl oz per 30 minutes of physical activity.
  2. Climate:
    • Hot/Humid: +20 fl oz daily.
    • High Altitude: +16 fl oz daily.
  3. Pregnancy / Lactation:
    • Pregnancy: Target is set to a minimum of 80 fl oz.
    • Lactation: Target is set to a minimum of 104 fl oz.

Core JavaScript Widget Logic

Here is the object-oriented state manager for our hydration widget. It validates input variables and computes the daily fluid target in fluid ounces or milliliters.

class HydrationWidget {
  constructor(config = {}) {
    this.weightLbs = config.weightLbs || 150;
    this.exerciseMinutes = config.exerciseMinutes || 0;
    this.climate = config.climate || 'temperate'; // 'temperate', 'hot', 'altitude'
    this.pregnancyStatus = config.pregnancyStatus || 'none'; // 'none', 'pregnant', 'lactating'
    this.targetMilliliters = 0;
    this.targetOunces = 0;

    this.calculateDailyTarget();
  }

  updateConfig(newConfig) {
    Object.assign(this, newConfig);
    this.calculateDailyTarget();
  }

  calculateDailyTarget() {
    // 1. Calculate baseline (0.5 oz per lb of body weight)
    let ounces = this.weightLbs * 0.5;

    // 2. Add physical activity adjustment (24 oz per 30 minutes of exercise)
    ounces += (this.exerciseMinutes / 30) * 24;

    // 3. Add environmental adjustments
    if (this.climate === 'hot') {
      ounces += 20;
    } else if (this.climate === 'altitude') {
      ounces += 16;
    }

    // 4. Handle reproductive status overrides
    if (this.pregnancyStatus === 'pregnant') {
      ounces = Math.max(80, ounces);
    } else if (this.pregnancyStatus === 'lactating') {
      ounces = Math.max(104, ounces);
    }

    this.targetOunces = Math.round(ounces);
    this.targetMilliliters = Math.round(ounces * 29.5735); // Convert to ml
  }
}

// Example usage:
const widget = new HydrationWidget({
  weightLbs: 180,
  exerciseMinutes: 45,
  climate: 'hot'
});
console.log(widget.targetOunces); // 180*0.5 + (45/30)*24 + 20 = 90 + 36 + 20 = 146 oz

Adding AI: Natural Language Parsing

Instead of forcing users to fill out long forms with dropdowns for climate and text inputs for minutes exercised, we can use a LLM API (like Claude or Gemini) to extract these parameters from a simple natural language diary entry.

Here is a system prompt and a JavaScript function that routes user input to an AI agent to parse parameters for the hydration calculator.

The System Prompt

You are a precise data extractor. Analyze the user's daily status message and extract:
1. weightLbs (number, default null if not mentioned)
2. exerciseMinutes (number of minutes exercised, default 0)
3. climate (string: "hot", "altitude", or "temperate")
4. pregnancyStatus (string: "pregnant", "lactating", or "none")

Return ONLY a valid JSON object matching this schema:
{
  "weightLbs": number | null,
  "exerciseMinutes": number,
  "climate": "hot" | "altitude" | "temperate",
  "pregnancyStatus": "pregnant" | "lactating" | "none"
}

The API Integration Script

async function parseDiaryWithAI(userText, apiKey) {
  const systemPrompt = `You are a precise data extractor. Extract: weightLbs, exerciseMinutes, climate ("hot", "altitude", "temperate"), and pregnancyStatus ("pregnant", "lactating", "none"). Return JSON only.`;

  try {
    const response = await fetch('https://api.gemini.ai/v1/chat/completions', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${apiKey}`
      },
      body: JSON.stringify({
        model: 'gemini-2.5-flash',
        messages: [
          { role: 'system', content: systemPrompt },
          { role: 'user', content: userText }
        ],
        response_format: { type: 'json_object' }
      })
    });

    const data = await response.json();
    return JSON.parse(data.choices[0].message.content);
  } catch (error) {
    console.error("AI Parsing failed, falling back to defaults.", error);
    return { exerciseMinutes: 0, climate: 'temperate', pregnancyStatus: 'none' };
  }
}

// Example usage:
// If the user says: "I did a tough 45 minute run in Denver today, it was super hot and dry."
// The AI extracts: { exerciseMinutes: 45, climate: 'hot' } (or altitude)

By connecting this AI parser to our client-side HydrationWidget, you can dynamically update targets automatically based on text logs.

For more guides on coding health calculators and rendering SVG charts or graphs in JavaScript, explore our guides on Building a Heart Rate Zone Visualizer in JavaScript and Implementing Logarithmic US Navy Body Fat Formulas in JavaScript.