Why estwarden?
Estonia and the Baltic states sit at a geopolitical fault line. Between NATO's eastern flank and Russia's Western Military District, the security environment shifts daily - troop rotations, hybrid operations, diplomatic signals, and infrastructure threats form a complex, fast-moving picture.
Most people don't have time to read defense ministry press releases, track OSINT Twitter accounts, or cross-reference naval movements with diplomatic rhetoric. estwarden exists to close that gap.
It's an observability tool for geopolitical risk - the same concept as monitoring your servers with Grafana, but applied to real-world security indicators. Every day at 08:00 EET, it queries multiple intelligence sources via AI, extracts structured threat indicators, assigns severity levels, and publishes the result as a dashboard, API, and Telegram briefing.
Think of it as a daily pulse check: means quiet, means something is developing, means pay attention, means immediate concern.
estwarden is automated OSINT - it augments, not replaces, professional intelligence analysis. Indicators may contain errors or miss relevant events. Use it as a starting point, not a sole source of truth.
💬 Telegram
The easiest way to stay informed. Join the public channel and receive a daily infographic briefing at 08:00 EET with the current threat level, all indicators, and a summary.
No API keys, no setup, no infrastructure. Just open Telegram.
🖥️ Bash + Cron
Poll the estwarden API from any server and act on the result. This script checks the current threat level and sends a notification if it's not GREEN.
#!/bin/bash
# estwarden daily check - add to crontab
# 0 9 * * * /usr/local/bin/estwarden-check.sh
API="https://estwarden.eu/api/latest"
NOTIFY_EMAIL="you@example.com" # or use ntfy/gotify/pushover
DATA=$(curl -sf "$API")
if [ $? -ne 0 ]; then
echo "estwarden API unreachable" | mail -s "⚠️ estwarden down" "$NOTIFY_EMAIL"
exit 1
fi
LEVEL=$(echo "$DATA" | jq -r '.threat_level')
DATE=$(echo "$DATA" | jq -r '.date')
COUNT=$(echo "$DATA" | jq '.indicators | length')
if [ "$LEVEL" != "GREEN" ]; then
SUMMARY=$(echo "$DATA" | jq -r '
.indicators[]
| select(.status != "GREEN")
| " \(.status) [\(.category)] \(.label): \(.finding)"
')
cat <<EOF | mail -s "🔴 estwarden: $LEVEL ($DATE)" "$NOTIFY_EMAIL"
Threat level: $LEVEL
Date: $DATE
Active indicators: $COUNT
Non-green indicators:
$SUMMARY
Dashboard: https://estwarden.eu
EOF
fi
Requires curl, jq, and a mail sender. Swap mail for curl to ntfy.sh, Gotify, Pushover, or any webhook.
📊 Grafana
Add estwarden to your monitoring stack using the Infinity datasource plugin (JSON/REST). This gives you threat level panels, indicator tables, and alerting - right next to your infrastructure metrics.
1. Install the Infinity datasource
grafana-cli plugins install yesoreyeram-infinity-datasource
systemctl restart grafana-server
2. Add the datasource
Go to Connections → Data sources → Add → Infinity. Name it estwarden. No auth required - the API is public.
3. Create panels
Stat panel - Current threat level:
Type: JSON
URL: https://estwarden.eu/api/latest
Method: GET
Parser: Backend
Root: (leave blank)
Columns:
threat_level → String
date → String
Table panel - All indicators:
Type: JSON
URL: https://estwarden.eu/api/latest
Method: GET
Parser: Backend
Root: indicators
Columns:
status → String
category → String
label → String
finding → String
Time series - Threat history:
Type: JSON
URL: https://estwarden.eu/api/history?days=90
Method: GET
Parser: Backend
Root: (array)
Columns:
date → Timestamp
score → Number
red_count → Number
yellow_count → Number
green_count → Number
4. Add alerting
Create an alert rule on the threat level panel: threat_level != "GREEN" → sends to your notification channel (Slack, Telegram, email, PagerDuty).
🏠 Home Assistant
Add estwarden as a REST sensor to show the Baltic threat level on your HA dashboard, trigger automations, or change your smart home behavior based on security conditions.
configuration.yaml
rest:
- resource: https://estwarden.eu/api/latest
scan_interval: 3600
sensor:
- name: "Baltic Threat Level"
value_template: "{{ value_json.threat_level }}"
icon: mdi:shield-alert
json_attributes:
- date
- summary
- name: "Baltic Threat Score"
value_template: "{{ value_json.indicators | length }}"
unit_of_measurement: "indicators"
icon: mdi:counter
- name: "Baltic Red Indicators"
value_template: >-
{{ value_json.indicators
| selectattr('status', 'eq', 'RED')
| list | count }}
icon: mdi:alert-circle
Automation example
- alias: "Baltic threat alert"
trigger:
- platform: state
entity_id: sensor.baltic_threat_level
condition:
- condition: template
value_template: "{{ trigger.to_state.state in ['ORANGE', 'RED'] }}"
action:
- service: notify.mobile_app
data:
title: "⚠️ Baltic Threat: {{ states('sensor.baltic_threat_level') }}"
message: >-
{{ state_attr('sensor.baltic_threat_level', 'summary') }}
data:
url: https://estwarden.eu
⚡ n8n
Build automated workflows that react to threat level changes. Use the HTTP Request node to poll the API and route to any action - Slack, email, database, webhook, or custom logic.
Workflow: daily check with conditional alert
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Schedule │───▶│ HTTP Request │───▶│ IF Node │───▶│ Slack │
│ (daily 9am) │ │ GET /latest │ │ level≠GREEN │ │ #security │
└──────────────┘ └──────────────┘ └──────┬───────┘ └──────────────┘
│ false
▼
(no action)
HTTP Request node config
Method: GET
URL: https://estwarden.eu/api/latest
Response Format: JSON
Authentication: None
IF node condition
{{ $json.threat_level }} is not equal to GREEN
You can extend this with a Code node to format the indicators, filter by category, or compare with yesterday's level using the /api/history endpoint.
🔗 API Reference
All endpoints return JSON. No authentication required. CORS is open.
/api/latest
Most recent report with all indicators
/api/today
Today's report (404 if not yet collected)
/api/report/{date}
Report for a specific date (YYYY-MM-DD)
/api/history?days=90
Threat level history (max 365 days)
/api/categories?days=90
Per-category breakdown over time
/api/dates
All available report dates
/health
Service health + next scheduled run
/api/metrics
Latest socioeconomic metrics (inflation, sentiment, cost of living)
Example response - /api/latest
{
"date": "2026-03-05",
"threat_level": "GREEN",
"summary": "No significant security developments...",
"indicators": [
{
"status": "GREEN",
"category": "MILITARY",
"label": "6th CAA",
"finding": "No activity in last 24h",
"source_url": "https://..."
}
]
}
Example response - /api/metrics
{
"date": "2026-03-05",
"summary": "Estonia's economy is cautiously recovering...",
"metrics": [
{
"category": "INFLATION",
"label": "CPI YoY Inflation",
"value": "4.00%",
"trend": "DOWN",
"finding": "Inflation slowed to 4.0% in early 2026",
"source_url": "https://..."
},
{
"category": "SENTIMENT",
"label": "Russian-Speaking Community Sentiment",
"value": "TENSE",
"trend": "STABLE",
"finding": "Integration tensions persist in Ida-Viru",
"source_url": "https://..."
}
]
}