The cost of too many dev tools: build a dashboard to visualize unused licenses and overlapping features
Build a small FastAPI + React dashboard to ingest billing and usage CSVs, find unused seats, and surface overlapping tool features for consolidation.
Hook: Why the tools you bought are quietly draining your budget
If your procurement bill looks healthy but engineering productivity feels worse, you probably have too many dev tools. Every unused license, overlapping feature, and duplicated integration adds friction and cost. This guide walks you through building a small, practical web dashboard that ingests billing and usage CSVs, finds unused seats, and surfaces tool overlap so your team can make consolidation decisions backed by data.
What you'll get — fast
In this article you'll get a step‑by‑step blueprint (Python backend + React frontend) to:
- Ingest billing and usage CSVs from vendors (Stripe, SaaS portals, internal HR/IDP reports).
- Compute unused seats and estimate savings.
- Detect tool overlap using feature lists and lightweight semantic matching.
- Render an actionable dashboard with charts, heatmaps and exportable reports.
Examples are pragmatic and suited for production hardening in 2026: FastAPI (Python), pandas, SQLite/Postgres, and a React (Vite) frontend using Chart libraries. We'll highlight security, data privacy, licensing, and automation hooks (SCIM/Okta/Slack).
Architecture overview
Keep the architecture simple to start; you can iterate to a microservices model later.
- Frontend: React (Vite) — file upload, charts, tables, export.
- Backend: FastAPI — CSV parsing, data normalization, analysis endpoints.
- Storage: SQLite for prototyping; Postgres for production.
- Data science libs: pandas + scikit‑learn (TF‑IDF) or RapidFuzz for fuzzy matches; possibility to use embeddings (sentence‑transformers) for advanced semantic overlap in 2026.
- Auth & Security: OAuth2/JWT + HTTPS + encrypted storage.
Prerequisites
- Python 3.11+ and Node 18+ (2026 LTS).
- pip, npm/yarn, Docker (optional).
- Basic familiarity with pandas and React.
Sample CSV schemas
Real vendor exports vary. Standardize on simple canonical schemas early to reduce parsing complexity.
Billing CSV (billing.csv)
vendor,product,plan,licenses_purchased,monthly_cost,currency,account_id
Slack,Slack Enterprise,Standard,120,2400,USD,acct_001
GitHub,GitHub Team,Team,80,1600,USD,acct_002
Usage CSV (usage.csv)
account_id,user_email,last_active_at,active_days_last_90
acct_001,jane@company.com,2026-01-10,75
acct_001,bob@company.com,2025-10-01,0
acct_002,alice@company.com,2026-01-12,80
Step 1 — Backend: project layout & environment
Create a small FastAPI project. Use venv or pipenv and pin dependencies. For prototyping we'll use SQLite and pandas. In production switch to Postgres and managed secrets.
project/
backend/
app.py
models.py
analyzer.py
requirements.txt
frontend/
(Vite + React app)
Dockerfile
docker-compose.yml
Step 2 — CSV ingestion and normalization (Python)
Use pandas to normalize vendor CSVs into canonical tables. Validate columns and cast numeric fields to avoid silent errors.
# analyzer.py (simplified)
import pandas as pd
from datetime import datetime, timedelta
def load_billing(path):
df = pd.read_csv(path)
expected = ['vendor','product','plan','licenses_purchased','monthly_cost','currency','account_id']
assert set(expected).issubset(df.columns), 'billing CSV missing columns'
df['licenses_purchased'] = df['licenses_purchased'].astype(int)
df['monthly_cost'] = df['monthly_cost'].astype(float)
return df
def load_usage(path):
df = pd.read_csv(path, parse_dates=['last_active_at'])
expected = ['account_id','user_email','last_active_at','active_days_last_90']
assert set(expected).issubset(df.columns)
return df
def compute_active_counts(usage_df, active_threshold_days=30):
cutoff = datetime.utcnow() - timedelta(days=active_threshold_days)
active = usage_df[usage_df['last_active_at'] >= cutoff]
counts = active.groupby('account_id').size().rename('active_user_count').reset_index()
return counts
Note: pick thresholds (30/90 days) based on team policy. Keep them configurable.
Step 3 — Calculate unused seats and savings
Join billing and usage to compute unused seats and theoretical monthly savings.
def compute_unused_seats(billing_df, usage_df, threshold_days=30):
active_counts = compute_active_counts(usage_df, active_threshold_days=threshold_days)
merged = billing_df.merge(active_counts, on='account_id', how='left').fillna(0)
merged['unused_seats'] = merged['licenses_purchased'] - merged['active_user_count']
merged['unused_seats'] = merged['unused_seats'].apply(lambda x: max(int(x),0))
merged['potential_monthly_saving'] = (merged['unused_seats'] / merged['licenses_purchased']).fillna(0) * merged['monthly_cost']
return merged
Interpretation rules:
- Only count unused seats if > 5% and > 2 seats to avoid noise.
- Flag accounts for review before automated actions.
Step 4 — Detecting tool overlap (features + semantic similarity)
A practical approach is to maintain a short feature list per tool and compute pairwise similarity. In 2026 you can optionally use vector embeddings for richer semantics — but TF‑IDF + cosine is lightweight and effective.
# feature_overlap.py
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
def compute_overlap(tools_features):
# tools_features: dict {tool_name: 'comma separated features'}
names = list(tools_features.keys())
docs = [tools_features[n] for n in names]
vec = TfidfVectorizer().fit_transform(docs)
sim = cosine_similarity(vec)
# return as list of tuples
pairs = []
for i in range(len(names)):
for j in range(i+1, len(names)):
pairs.append({'a': names[i], 'b': names[j], 'score': float(sim[i,j])})
return sorted(pairs, key=lambda x: x['score'], reverse=True)
Example tool features map (start small):
tools_features = {
'Jira': 'issue tracking, workflows, sprints, backlog, kanban',
'Linear': 'issue tracking, sprints, kanban, integrations',
'Confluence': 'wiki, docs, knowledge base, pages',
'Notion': 'docs, wiki, notes, kanban, databases'
}
Highlight pairs with score > 0.45 (tune threshold per data). Use human review to confirm before consolidating.
Step 5 — FastAPI endpoints
Create small endpoints for upload and reports. Protect them with OAuth2 in production.
from fastapi import FastAPI, UploadFile, File
import tempfile
from analyzer import load_billing, load_usage, compute_unused_seats
app = FastAPI()
@app.post('/upload')
async def upload_files(billing: UploadFile = File(...), usage: UploadFile = File(...)):
with tempfile.NamedTemporaryFile(delete=False) as bfile:
bfile.write(await billing.read())
with tempfile.NamedTemporaryFile(delete=False) as ufile:
ufile.write(await usage.read())
billing_df = load_billing(bfile.name)
usage_df = load_usage(ufile.name)
report = compute_unused_seats(billing_df, usage_df)
return report.to_dict(orient='records')
Return JSON arrays for the frontend. For large teams stream results or use pagination.
Step 6 — Frontend: React + Vite minimal UI
Create a Vite React app. The minimal UI has:
- File upload form for billing.csv and usage.csv
- Summary cards (total monthly spend, potential savings)
- Table of unused seats and export button
- Tool overlap heatmap
// src/App.jsx (simplified)
import React, {useState} from 'react';
export default function App(){
const [report, setReport] = useState([])
const [files, setFiles] = useState({})
const onChange = (e) => setFiles({...files, [e.target.name]: e.target.files[0]})
const submit = async () => {
const fd = new FormData();
fd.append('billing', files.billing)
fd.append('usage', files.usage)
const res = await fetch('/upload', {method: 'POST', body: fd})
const json = await res.json()
setReport(json)
}
const totalSaving = report.reduce((s,r) => s + (r.potential_monthly_saving||0), 0)
return (
License Usage Dashboard
Potential monthly saving: ${totalSaving.toFixed(2)}
Vendor Product Licenses Active Users Unused Seats Potential Saving
{report.map((r,i)=> (
{r.vendor} {r.product} {r.licenses_purchased} {r.active_user_count} {r.unused_seats} ${r.potential_monthly_saving.toFixed(2)}
))}
)
}
For heatmaps and charts, use Recharts or Chart.js. In 2026 consider using React Server Components for faster data flows if integrating with large datasets.
Step 7 — UX and actionability
Make the data actionable — dashboards are only useful if they trigger decisions.
- Add tags: business critical, team owned, vendor contract end date.
- Provide recommended actions per row: reclaim seat, move to shared pool, schedule vendor review.
- Export CSV / PDF for procurement and finance.
- Integrate with Slack/Teams for approval flows before automated cancellations.
Step 8 — Automation & governance
After human review, automate routine tasks:
- Use SCIM or vendor APIs to deactivate accounts for unused seats (with audit logs).
- Integrate with your identity provider (Okta/OneLogin) to reclaim licenses when users are offboarded.
- Schedule monthly reports and alerts for newly unused licenses.
Tip: don't auto‑cancel subscriptions. Instead, create a ticket or approval workflow to avoid service disruptions.
Security, privacy & license considerations (must‑do in 2026)
CSV files can contain PII. Treat them as sensitive:
- Encrypt at rest and in transit; use AWS KMS/GCP KMS for keys.
- Mask or hash emails before storing long‑term.
- Use strong access controls and audit logs for CSV uploads and reports.
- Rate limit uploads and validate file types to avoid abuse.
Licensing: check each vendor's contract before programmatically revoking seats or exporting usage to third parties. Keep legal and procurement in the loop.
Tuning thresholds and reducing false positives
Avoid noisy alerts. Apply sensible heuristics:
- Only display unused seat rows where unused_seats > 5% AND > 2 seats.
- For paid add‑ons (like extra storage), use financial impact thresholds (e.g., > $100/month).
- Group small vendors to avoid chasing low impact items.
2026 trends & why this matters now
Late 2025 and early 2026 saw renewed focus on FinOps and AI‑driven procurement. Vendors introduced feature bundles and fine‑grained usage telemetry, enabling better license reclamation. Meanwhile, embeddings and LLMs improved semantic matching for feature overlap detection — but most teams still benefit from lightweight TF‑IDF and rules first.
Consolidation is trending: organizations prefer fewer, deeper integrations over many niche tools — lowering cognitive load and cost.
Practical takeaway: an internal dashboard like this acts as FinOps telemetry for engineering — actionable and low friction.
Testing, deployment & observability
Start with Docker for repeatable builds. Add GitHub Actions for CI that runs linters and unit tests for analysis functions.
# Dockerfile (frontend + backend separate images)
FROM python:3.11-slim
WORKDIR /app
COPY backend/requirements.txt ./
RUN pip install -r requirements.txt
COPY backend/ .
CMD ["uvicorn","app:app","--host","0.0.0.0","--port","8000"]
Observability:
- Log ingestion events and analysis results.
- Monitor processing time for large CSVs.
- Alert on parsing failures or data anomalies.
Advanced strategies (next steps)
- Use embeddings (OpenAI or open models with sentence‑transformers) to compute semantic overlap for feature descriptions and vendor docs.
- Apply anomaly detection on usage time series to catch sudden drops in seat activity.
- Integrate procurement API to schedule renewals and set renewal thresholds.
- Provide role‑based views: engineering, procurement, finance.
Common pitfalls and how to avoid them
- Ignoring contract terms — always check auto‑renew windows and minimum term penalties before canceling.
- Acting on raw counts without human review. Always include a reconciliation step.
- Overfitting overlap detection — validate with actual team interviews or surveys.
Real‑world example (case study)
One mid‑sized engineering org (200 engineers) used a dashboard like this in early 2026 and found:
- 15% of Slack seats were unused based on a 60‑day threshold — reclaimed 18 seats and saved $360/month.
- Detected 3 high‑overlap tool pairs (Notion vs Confluence, Linear vs Jira) and consolidated to reduce tool sprawl.
- Automated deprovisioning via SCIM for inactive contractors, reducing provisioning errors by 40%.
These actionable insights paid back the engineering time invested in a single quarter.
Wrap up — actionable checklist
- Collect billing & usage CSVs; standardize to canonical schema.
- Build ingestion + analysis endpoints with FastAPI and pandas.
- Compute unused seats with thresholds and surface potential savings.
- Maintain a small feature list per tool and compute pairwise overlap (TF‑IDF or embeddings).
- Provide reports and human approval workflows before any automated changes.
- Harden with encryption, RBAC, and logging; integrate with identity provider.
Call to action
Ready to stop paying for idle tools? Clone the starter repo, run the demo, and adapt thresholds to your policies. If you want, share anonymized CSVs and we’ll help prototype an overlap matrix for your stack. Contribute back with feature lists and playbooks to help other teams reduce tool sprawl in 2026.
Start now: spin up the FastAPI demo, upload billing and usage CSVs, and get a first‑pass savings estimate in under 10 minutes.
Related Reading
- Smartwatch Hacks for Pastry Chefs: Use Wearables to Speed Up Dessert Prep
- Gadget-Ready Gifts: Lithuanian Jewelry and Textile Picks That Pair with Smartwatches
- Personalization at Scale for Campus Clubs (2026): Preference‑First Outreach Playbook
- Are Custom Food Tech Products Worth It? Lessons from 3D-Scanning and Placebo Gadgets
- Crowdfunding and Consumer Protection in Bangladesh: Do Platforms Need Stronger Rules After the Rourke Refund Furore?
Related Topics
Unknown
Contributor
Senior editor and content strategist. Writing about technology, design, and the future of digital media. Follow along for deep dives into the industry's moving parts.
Up Next
More stories handpicked for you
Prototype a location‑aware dining micro app: integrate Maps/Waze, user prefs and a recommendation LLM
Securely connecting desktop AI to cloud services: token handling patterns and refresh strategies
Curated list: Open micro app templates for every use case (chat, maps, scheduling, ops)
Edge AI debugging on Pi: capture, visualize and compare model traces from AI HAT+ 2
Micro apps at scale: governance templates for IT to allow safe user‑built apps
From Our Network
Trending stories across our publication group