Open-source intelligence platform for viewing global conflicts on an interactive map. Think Palantir, but open.
OpenIntel plots political violence and protest events on a dark interactive globe. Filter by time range, event type, region, or country. Click any dot to see what happened — who was involved, how many casualties, and the original sources. Built on real conflict data from ACLED.
| Layer | Technology |
|---|---|
| Frontend | Next.js 15, React 19, TypeScript, Tailwind CSS |
| Map | MapLibre GL JS, Deck.gl, Protomaps dark basemap |
| State | Zustand (client state), SWR (server state) |
| Database | PostgreSQL 16 + PostGIS 3.4 |
| Pipeline | Python (httpx, psycopg, Pydantic) |
| Data | ACLED (Armed Conflict Location & Event Data) |
ACLED (Armed Conflict Location & Event Data Project) is a nonprofit that collects and maps political violence and protest events worldwide in real-time. They employ researchers who read local news, NGO reports, and UN sources across every country, then code each event into a structured row: what happened, who was involved, where, when, and how many people died.
Their database covers 6 event types going back to 1997 for some regions:
| Type | Color on map |
|---|---|
| Battles | Red |
| Violence against civilians | Orange |
| Explosions/Remote violence | Yellow |
| Riots | Purple |
| Protests | Blue |
| Strategic developments | Gray |
ACLED data is not fully free. Event-level data (individual rows with coordinates) requires a paid tier:
| Tier | Cost | API Access | Data Level |
|---|---|---|---|
| Open | Free | No | Aggregated counts only |
| Research | Paid | Yes | Lagged event-level data |
| Partner | Paid | Yes | Weekly disaggregated data |
| Enterprise | Paid | Yes | Unlimited, real-time |
Registering with an institutional email (university, org, company) may qualify you for Research access. Apply at developer.acleddata.com.
Alternative free sources:
- UCDP (Uppsala Conflict Data Program) — fully free and open API, covers armed conflict (not protests)
- ACLED on HDX — free but aggregated only (no coordinates)
- Node.js 18+
- pnpm
- Docker (for PostGIS)
- Python 3.11+ (for data pipeline)
pnpm installcp .env.example .env.localEdit .env.local and add:
NEXT_PUBLIC_PROTOMAPS_KEY— free key from protomaps.comACLED_EMAILandACLED_KEY— if you have Research+ tier access
docker compose up -dThis starts PostGIS on port 5433 and auto-runs SQL migrations.
With ACLED API credentials:
cd pipeline
pip install -e .
python -m src.ingest --days 30 # Recent data
python -m src.backfill --start 2020-01-01 # Historical backfillWithout credentials: The app works with the map visible, but no event data will be plotted until data is loaded into the database.
pnpm devOpen http://localhost:3000 (or the port shown in terminal).
openintel/
├── src/ # Next.js app
│ ├── app/
│ │ ├── page.tsx # Main page (map + sidebar + detail panel)
│ │ └── api/ # 8 API routes (events, geojson, filters, search, stats)
│ ├── components/
│ │ ├── map/ # MapContainer, DeckOverlay, EventPopup
│ │ ├── sidebar/ # Filters (time, event type, region, country, search)
│ │ ├── detail/ # DetailPanel, EventMeta, SourceList, FatalityBadge
│ │ └── layout/ # Header, StatsBar
│ ├── lib/
│ │ ├── db.ts # PostgreSQL connection pool
│ │ ├── queries/ # SQL query builders
│ │ └── map/ # Colors, layers, styles, constants
│ ├── stores/ # Zustand stores (filters, map, UI)
│ └── hooks/ # SWR data fetching hooks
├── pipeline/ # Python data pipeline
│ ├── src/ # ACLED client, transform, DB upsert, ingest
│ ├── sql/ # Database migrations (auto-run by Docker)
│ └── scripts/ # Shell scripts for daily/backfill runs
└── docker-compose.yml # PostGIS for local dev
| Route | Description |
|---|---|
GET /api/events |
Paginated events with filters |
GET /api/events/geojson |
GeoJSON FeatureCollection for map |
GET /api/events/[id] |
Single event detail |
GET /api/filters/countries |
Country list with event counts |
GET /api/filters/event-types |
Event type counts |
GET /api/filters/regions |
Region list |
GET /api/search?q= |
Text search across events |
GET /api/stats |
Aggregate statistics |
All routes accept filter params: dateStart, dateEnd, eventTypes, countries, regions, search.
MIT