Build an Automated Data Monitoring & Alert System with DuckDB + Cron
Do you ever face this pain point—your business data grows every day, but you have no idea when something goes wrong. By the time your customers complain, the damage is already done.
Today I’ll show you how to build a fully automated Data Health Monitoring System using DuckDB. It runs queries on a schedule, detects anomalies, and sends instant Telegram alerts. No complex ETL, no expensive monitoring tools—just a Python script + DuckDB.

1. Why Do You Need Data Monitoring?
Let’s clarify the value first. Why build a monitoring system?
- E-commerce: GMV drops 30% overnight—you need to catch it before customers place orders, not discover it the next day from reports
- Finance: A stock breaks through a key level with high volume—push the signal to subscribers instantly
- SaaS: User registrations drop for 3 consecutive days—something is broken in your product
- Content: A video’s views spike unexpectedly—catch the trend while it’s hot
The common thread: fast detection, accurate alerts, minimal cost.
DuckDB’s role in this system: it’s not a database—it’s a query engine. It reads directly from CSV/Parquet/API files, runs one SQL query to find anomalies, and hands results to Telegram for delivery.
2. System Architecture
CSV/Parquet Data Sources
↓
DuckDB (Query Engine)
↓
Python Anomaly Detection
↓
Telegram Bot API
↓
Real-time Mobile Notifications
Everything runs in Python with zero external service dependencies. Data is stored in a single .duckdb file with incremental appends.
3. Core Monitoring Logic
Let’s say you’re an e-commerce seller tracking three core metrics:
- Daily order volume anomalies
- Sustained decline in average order value
- Sudden spikes in refund rate
Your data source is daily order CSV exports. Here’s the DuckDB monitoring query:
import duckdb
import json
from datetime import datetime, timedelta
con = duckdb.connect("monitor.duckdb")
# Merge historical orders into a persistent table (one-time import)
con.execute("""
CREATE TABLE IF NOT EXISTS orders AS
SELECT * FROM read_csv_auto('orders_2024*.csv')
""")
# Monitor query: compute core metrics for the past 14 days
def check_health():
today = datetime.now().date()
result = con.execute("""
WITH daily_stats AS (
SELECT
DATE(order_date) AS stat_date,
COUNT(*) AS order_count,
ROUND(AVG(amount), 2) AS avg_order_value,
ROUND(SUM(CASE WHEN status = 'refunded' THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) AS refund_rate
FROM orders
WHERE DATE(order_date) >= CURRENT_DATE - INTERVAL '14' DAY
GROUP BY DATE(order_date)
)
SELECT
MAX(CASE WHEN stat_date = CURRENT_DATE - INTERVAL '1' DAY THEN order_count END) AS yesterday_orders,
AVG(order_count) OVER (ORDER BY stat_date ROWS BETWEEN 6 PRECEDING AND 1 PRECEDING) AS ma7_orders,
MAX(CASE WHEN stat_date = CURRENT_DATE - INTERVAL '1' DAY THEN refund_rate END) AS yesterday_refund_rate,
AVG(refund_rate) OVER (ORDER BY stat_date ROWS BETWEEN 6 PRECEDING AND 1 PRECEDING) AS ma7_refund_rate
FROM daily_stats
ORDER BY stat_date DESC
LIMIT 1
""").fetchone()
return {
'yesterday_orders': result[0],
'ma7_orders': result[1],
'yesterday_refund_rate': result[2],
'ma7_refund_rate': result[3]
}
Key points:
read_csv_auto('orders_2024*.csv')— DuckDB supports wildcards to read multiple files at once, no manual concatenation needed- Window function
AVG(...) OVER (...)— Computes 7-day moving average without pre-aggregation - Results persist in
.duckdbfile — Incremental append, not full rebuild each time
4. Anomaly Detection Algorithm
With baseline metrics in hand, the next step is determining whether something is actually abnormal.
We use a simple statistical approach: if the current value deviates from the 7-day average beyond a threshold, flag it as anomalous.
def detect_anomalies(stats):
"""Returns a list of anomalies, each with metric name, current value, expected range, and severity."""
anomalies = []
# Order volume anomaly
if stats['ma7_orders'] > 0:
order_drop = (stats['yesterday_orders'] - stats['ma7_orders']) / stats['ma7_orders']
if order_drop < -0.20: # Drop exceeds 20%
anomalies.append({
'metric': 'Orders',
'value': stats['yesterday_orders'],
'expected': f"~{stats['ma7_orders']:.0f}",
'severity': '🔴 Critical',
'message': f"Yesterday's orders: {stats['yesterday_orders']}, down {abs(order_drop)*100:.1f}% from 7-day avg"
})
elif order_drop > 0.50: # Surge exceeds 50%
anomalies.append({
'metric': 'Orders',
'value': stats['yesterday_orders'],
'expected': f"~{stats['ma7_orders']:.0f}",
'severity': '🟡 Attention',
'message': f"Yesterday's orders: {stats['yesterday_orders']}, up {order_drop*100:.1f}% from 7-day avg—verify if this is a legitimate promotion"
})
# Refund rate anomaly
if stats['ma7_refund_rate'] > 0:
refund_spike = (stats['yesterday_refund_rate'] - stats['ma7_refund_rate']) / stats['ma7_refund_rate']
if refund_spike > 0.50: # Refund rate surges 50%
anomalies.append({
'metric': 'Refund Rate',
'value': f"{stats['yesterday_refund_rate']:.2f}%",
'expected': f"~{stats['ma7_refund_rate']:.2f}%",
'severity': '🔴 Critical',
'message': f"Yesterday's refund rate: {stats['yesterday_refund_rate']:.2f}%, up {refund_spike*100:.1f}% from 7-day avg"
})
return anomalies
Benefits of this approach:
- Tunable thresholds (
-0.20,0.50)—adjust based on business sensitivity - Detects both drops and surges in a single pass
- Structured output—easy to push via Telegram or log to file
5. Telegram Push Module
Use Python’s requests library to call the Telegram Bot API and push anomaly alerts to a channel or group.
import requests
TELEGRAM_BOT_TOKEN = "YOUR_BOT_TOKEN"
CHAT_ID = "YOUR_CHAT_ID" # Group ID or channel ID
def send_telegram(message):
url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
payload = {
'chat_id': CHAT_ID,
'text': message,
'parse_mode': 'HTML'
}
try:
r = requests.post(url, json=payload, timeout=10)
return r.json().get('ok', False)
except Exception as e:
print(f"Push failed: {e}")
return False
def notify_anomalies(anomalies):
if not anomalies:
send_telegram(
f"✅ <b>Daily Data巡检 Complete</b>\n\n"
f"📅 {datetime.now().strftime('%Y-%m-%d')}\n"
f"All metrics normal. No action needed.\n\n"
f"— DuckDB Monitor Bot"
)
return
lines = [
f"🚨 <b>Data Anomaly Alert</b>",
f"📅 {datetime.now().strftime('%Y-%m-%d %H:%M')}",
""
]
for a in anomalies:
lines.append(f"{a['severity']} {a['metric']}")
lines.append(f" Current: {a['value']}")
lines.append(f" Expected: {a['expected']}")
lines.append(f" {a['message']}")
lines.append("")
lines.append("--- DuckDB Monitor Bot")
send_telegram("\n".join(lines))
6. Complete Script & Cron Scheduling
Now combine everything into a complete monitoring script:
import os
import glob
import json
from datetime import datetime
def incremental_update():
"""Incremental update: only import new CSV files"""
today_str = datetime.now().strftime('%Y%m%d')
new_files = glob.glob(f'orders_{today_str}*.csv')
if not new_files:
print("No new data files today")
return
for f in new_files:
count = con.execute(f"SELECT COUNT(*) FROM read_csv_auto('{f}')").fetchone()[0]
con.execute(f"""
INSERT INTO orders
SELECT * FROM read_csv_auto('{f}')
WHERE order_id NOT IN (SELECT order_id FROM orders)
""")
print(f"Imported {f}: {count} records")
def main():
# 1. Incremental data update
incremental_update()
# 2. Run health check
stats = check_health()
anomalies = detect_anomalies(stats)
# 3. Push results
notify_anomalies(anomalies)
# 4. Log today's run
log_entry = {
'date': datetime.now().strftime('%Y-%m-%d'),
'anomalies': len(anomalies),
'stats': stats
}
with open('monitor_log.jsonl', 'a') as f:
f.write(json.dumps(log_entry, ensure_ascii=False) + '\n')
print(f"巡检 complete. Found {len(anomalies)} anomalies")
if __name__ == '__main__':
main()
Schedule with cron (Linux):
# Run automatically at 9 AM every day
0 9 * * * cd /home/user/duckdb-monitor && python3 monitor.py >> monitor.log 2>&1
Or use macOS launchd or Windows Task Scheduler—the principle is the same.
7. Advanced: Multi-Source Cross-Database Monitoring
Real-world monitoring often requires crossing data sources. Your e-commerce data is in Shopify API, logistics data is in a JSON file, and financial data is in Excel.
DuckDB’s strength shines here—you don’t need to ETL everything into one database first. Just ATTACH different sources:
# Attach: Shopify orders (CSV)
con.execute("ATTACH 'shopify_orders.csv' AS shopify (READ_ONLY)")
# Attach: Logistics data (JSON)
con.execute("ATTACH 'logistics.json' AS log (READ_ONLY, TYPE JSON)")
# Attach: Financial data (Excel)
con.execute("ATTACH 'finance.xlsx' AS fin (READ_ONLY)")
# Cross-source query: find SKUs with late shipping AND high refund rates
con.execute("""
SELECT
s.sku,
s.product_name,
s.order_count,
AVG(l.transit_days) AS avg_transit,
SUM(CASE WHEN f.status = 'refunded' THEN 1 ELSE 0 END) AS refund_count
FROM shopify.orders s
LEFT JOIN log.packages l ON s.tracking_number = l.tracking_id
LEFT JOIN fin.refunds r ON s.order_id = r.order_id
GROUP BY s.sku, s.product_name
HAVING avg_transit > 7 AND refund_count > 5
ORDER BY refund_count DESC
""").fetchdf()
ATTACH is one of DuckDB’s most underrated features. It lets you query CSV, JSON, Excel, Parquet, PostgreSQL, MySQL, and more—in a single query—without any ETL preprocessing.
8. Comparison with Traditional Monitoring Tools
| Feature | DuckDB + Python | Grafana + Prometheus | Commercial SaaS (Datadog) |
|---|---|---|---|
| Data source access | Direct CSV/JSON/Excel read | Requires Exporter agents | API integration, complex config |
| Anomaly detection | Custom Python logic | Alert rule configuration | Built-in AI anomaly detection |
| Push notifications | Telegram Bot API | Slack/PagerDuty | Multi-channel |
| Deployment cost | $0 (local/VPS) | Self-hosted infrastructure | $20-100/node/month |
| Learning curve | Python + SQL | High | Medium |
| Customization | Fully controllable | Medium | Low |
| Best for | SMBs, indie developers | Large infra teams | Enterprise |
9. Monetization Strategies
This system isn’t just a personal tool—it can become a revenue stream:
🟢 Low-Cost Approach ($0-5,000 startup)
- Model: Deploy this system for 10 e-commerce sellers at $299/month, annual plan $2,999
- Steps:
- Template the code so clients only replace data source paths
- Deploy on cheap cloud VPS (e.g., Alibaba Cloud ECS at ~$7/month)
- Separate Telegram group per client with independent config
- Expected monthly revenue: $2,990-5,000
- Best for: Individual developers with 1-2 client connections
🟡 Medium-Cost Approach ($5,000-50,000 startup)
- Model: Data product subscription. Package monitoring results into daily briefing reports pushed via Telegram channel, priced at $99/month
- Steps:
- Select a specific industry (e.g., cross-border e-commerce, stocks)
- Build a universal monitoring pipeline that auto-generates industry analysis reports
- Drive traffic via social media, monetize through Telegram paid channel
- Expected monthly revenue: $5,000-20,000 (100-200 subscribers)
- Best for: Content creators with existing industry audience
🔴 High-Cost Approach ($50,000+ startup)
- Model: Embed as a value-added service in your consulting/agency offerings. Charge $500-2,000/month per client for “data health monitoring”
- Steps:
- Add data monitoring module to your existing consulting services
- Monthly maintenance fee on top of core service
- Periodic threshold and metric optimization
- Expected monthly revenue: $10,000-50,000 (depends on client count)
- Best for: Freelancers or small studios with existing client base
Core principle: You’re not selling code—you’re selling “peace of mind, no more waking up to data disasters at midnight.”
10. Summary
| Component | Technology | Cost |
|---|---|---|
| Data querying | DuckDB (Python API) | Free |
| Data storage | Single .duckdb file | Free |
| Anomaly detection | Python logic + SQL window functions | Free |
| Push notifications | Telegram Bot API | Free |
| Scheduling | Linux cron / cloud VPS | Free |
| Total cost | $0 |
Compared to commercial monitoring tools (Grafana + PagerDuty, thousands to tens of thousands annually), this approach is functionally competitive at zero cost.
Remember: The essence of monitoring isn’t technology—it’s the awareness to catch problems before they cascade. DuckDB just makes it trivially simple.
📖 Full runnable code (including multi-source ATTACH examples, Telegram template, and cron configuration guide) is available at duckdblab.org, with complete step-by-step deployment instructions.
💡 Want to systematically learn DuckDB for monitoring, automation, and data products? duckdblab.org has a complete tutorial series.