TutorialsAISQLdashboards

How to Track Daily Active Users (DAU) From Your Database

Your users interact with your product every day. But do you actually know how many of them came back today versus yesterday, last week, or the same week las...

Priya Sharma· Product LeadApril 1, 20266 min read

Your users interact with your product every day. But do you actually know how many of them came back today versus yesterday, last week, or the same week last month? For most SaaS teams, getting that answer requires either an analytics tool that's lagging reality by 24 hours, a hand-maintained spreadsheet someone forgot to update, or a request to an engineer who's busy with other things.

Daily active users is one of the most important metrics in any product-led business. It's a direct signal of engagement not just acquisition. Yet it's also one of the metrics teams most often track inconsistently. This post walks through exactly how DAU is calculated, what it actually means, how to pull it from your database, and how to set up monitoring so you know the moment something changes.

What Counts as a "Daily Active User"?

Before you write a single query, you need to define what "active" means for your product. This sounds obvious, but it's where most DAU tracking breaks down.

Active could mean:

  • A user logged in (a session was created)
  • A user performed any action (an event was logged)
  • A user used a specific core feature (e.g., ran a report, sent a message, processed a transaction)
  • For a communication tool, a login is probably good enough. For a productivity app, you might only count users who created or edited something. For an analytics platform, you might only count users who ran a query.

    Your definition should match your product's core value action the thing a user does when they're genuinely getting value from the product. Once you've defined that, the SQL is straightforward.

    The Basic DAU Query

    Assuming you have a table that logs user activity let's call it user_events with at least a user_id and a created_at timestamp, a basic DAU query looks like this:

    SELECT
      DATE(created_at) AS activity_date,
      COUNT(DISTINCT user_id) AS daily_active_users
    FROM user_events
    WHERE created_at >= CURRENT_DATE - INTERVAL '30 days'
    GROUP BY DATE(created_at)
    ORDER BY activity_date DESC;

    This gives you a row per day with a count of unique users who had at least one event. Simple, but already useful.

    If your events table is large, add an index on created_at and user_id to keep this fast:

    CREATE INDEX idx_user_events_created_user
    ON user_events (created_at, user_id);

    Filtering to Only Your Core Action

    If you want to count only users who performed a meaningful action not just any event add a filter:

    SELECT
      DATE(created_at) AS activity_date,
      COUNT(DISTINCT user_id) AS daily_active_users
    FROM user_events
    WHERE
      created_at >= CURRENT_DATE - INTERVAL '30 days'
      AND event_type = 'query_executed'  -- or whatever your core action is
    GROUP BY DATE(created_at)
    ORDER BY activity_date DESC;

    You can also track multiple core actions by using IN:

    WHERE event_type IN ('query_executed', 'dashboard_viewed', 'report_exported')

    DAU vs. MAU: The Engagement Ratio

    DAU alone is useful, but most teams also want to understand it in context. A common derived metric is the DAU/MAU ratio what percentage of your monthly actives are active on any given day.

    A DAU/MAU ratio above 20% is generally considered a sign of a sticky product. WhatsApp and Slack are north of 50%. A B2B SaaS product doing 10-15% is in reasonable territory.

    Here's how to calculate it:

    WITH monthly AS (
      SELECT COUNT(DISTINCT user_id) AS mau
      FROM user_events
      WHERE created_at >= CURRENT_DATE - INTERVAL '30 days'
    ),
    daily AS (
      SELECT COUNT(DISTINCT user_id) AS dau
      FROM user_events
      WHERE DATE(created_at) = CURRENT_DATE - INTERVAL '1 day'
    )
    SELECT
      daily.dau,
      monthly.mau,
      ROUND(100.0 * daily.dau / monthly.mau, 1) AS dau_mau_ratio_pct
    FROM daily, monthly;

    A single DAU number is less useful than a trend. You want to know: is engagement going up, going down, or holding steady? Here's a query that shows you DAU over the last 90 days alongside a 7-day rolling average:

    WITH daily_counts AS (
      SELECT
        DATE(created_at) AS activity_date,
        COUNT(DISTINCT user_id) AS dau
      FROM user_events
      WHERE created_at >= CURRENT_DATE - INTERVAL '90 days'
      GROUP BY DATE(created_at)
    )
    SELECT
      activity_date,
      dau,
      ROUND(
        AVG(dau) OVER (
          ORDER BY activity_date
          ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
        ),
        1
      ) AS rolling_7day_avg
    FROM daily_counts
    ORDER BY activity_date DESC;

    The rolling average smooths out weekend dips and one-off anomalies, giving you a cleaner signal of the underlying trend.

    Segmenting DAU by User Cohort or Plan

    Raw DAU is fine for a quick pulse check, but breaking it down by plan tier, acquisition channel, or user cohort tells you much more. Are your paying users more active than free users? Are users acquired via content more engaged than those from paid ads?

    SELECT
      DATE(e.created_at) AS activity_date,
      u.plan_tier,
      COUNT(DISTINCT e.user_id) AS dau
    FROM user_events e
    JOIN users u ON u.id = e.user_id
    WHERE e.created_at >= CURRENT_DATE - INTERVAL '30 days'
    GROUP BY DATE(e.created_at), u.plan_tier
    ORDER BY activity_date DESC, plan_tier;

    Segmented DAU is often where product teams find the most actionable insight. If free-tier DAU is flat but paid DAU is growing, you're seeing strong monetisation with an acquisition problem. If the inverse is true, you may have an activation or conversion problem.

    Setting Up Automatic DAU Monitoring

    Writing queries manually every morning is a workflow that breaks down quickly. What you actually want is a dashboard that refreshes itself and an alert that fires when DAU drops below a threshold.

    With AI for Database, you can connect your PostgreSQL, MySQL, or other database directly and ask it in plain English: "Show me daily active users for the last 30 days, broken down by plan tier." It translates your question to SQL, runs it, and returns a chart no query writing required.

    More practically, you can set up a self-refreshing DAU dashboard that updates every morning automatically. And using the action workflow feature, you can define a condition like "when today's DAU is more than 20% below the 7-day average" and trigger a Slack message or email. You'll know about engagement drops before your team notices them in a standup.

    Getting Started

    The queries in this post will work on PostgreSQL, MySQL, and most SQL-compatible databases with minor syntax adjustments. Start with the basic 30-day DAU query, confirm your definition of "active" with your team, and then build from there.

    If you'd rather skip the query-writing and get a live DAU dashboard in minutes, give AI for Database a try. Connect your database, ask your question in plain English, and set up an alert the whole setup takes under 10 minutes.

    Ready to try AI for Database?

    Query your database in plain English. No SQL required. Start free today.