Systems Library / Sales Automation / How to Build a Sales Pipeline Velocity Dashboard
Sales Automation crm pipeline

How to Build a Sales Pipeline Velocity Dashboard

Track deal velocity metrics in real-time to identify pipeline bottlenecks.

Jay Banlasan

Jay Banlasan

The AI Systems Guy

Pipeline velocity tells you how fast deals move through your funnel. This sales pipeline velocity dashboard shows it in real time with the metrics that matter. I use this to spot bottlenecks the moment they form, not weeks later when revenue is already gone.

What You Need Before Starting

Step 1: Calculate Velocity Metrics

Pipeline velocity has four components: number of deals, average deal value, win rate, and average sales cycle length.

def calculate_velocity(deals_df):
    won = deals_df[deals_df["status"] == "won"]
    total = len(deals_df)
    metrics = {
        "deal_count": total,
        "avg_value": deals_df["amount"].mean(),
        "win_rate": len(won) / max(total, 1),
        "avg_cycle_days": deals_df["cycle_days"].mean(),
    }
    metrics["velocity"] = (
        metrics["deal_count"] * metrics["avg_value"] * metrics["win_rate"]
    ) / max(metrics["avg_cycle_days"], 1)
    return metrics

Step 2: Track by Stage

Break velocity down by stage. This shows exactly where deals get stuck.

def velocity_by_stage(deals_df, stages):
    stage_metrics = {}
    for stage in stages:
        stage_deals = deals_df[deals_df["current_stage"] == stage]
        stage_metrics[stage] = {
            "count": len(stage_deals),
            "avg_days": stage_deals["days_in_stage"].mean(),
            "total_value": stage_deals["amount"].sum(),
        }
    return stage_metrics

Step 3: Build the Dashboard API

Serve the data through a simple Flask API. The frontend fetches fresh numbers every time.

from flask import Flask, jsonify
from datetime import datetime

app = Flask(__name__)

@app.route("/api/velocity")
def get_velocity():
    deals = fetch_deals_from_crm()
    velocity = calculate_velocity(deals)
    by_stage = velocity_by_stage(
        deals, ["discovery", "demo", "proposal", "negotiation"]
    )
    return jsonify({
        "overall": velocity,
        "by_stage": by_stage,
        "updated_at": datetime.now().isoformat(),
    })

Step 4: Store Daily Snapshots

Save daily snapshots so you can show velocity trends over time.

import sqlite3

def save_daily_snapshot(velocity_data):
    conn = sqlite3.connect("velocity.db")
    conn.execute("""
        INSERT INTO daily_velocity
        (date, deal_count, avg_value, win_rate, cycle_days, velocity)
        VALUES (?, ?, ?, ?, ?, ?)
    """, (
        datetime.now().date().isoformat(),
        velocity_data["deal_count"],
        velocity_data["avg_value"],
        velocity_data["win_rate"],
        velocity_data["avg_cycle_days"],
        velocity_data["velocity"],
    ))
    conn.commit()

Step 5: Set Up Velocity Alerts

When velocity drops below your 30-day average, send an alert immediately.

def check_velocity_alert(current, historical_avg):
    if current["velocity"] < historical_avg * 0.8:
        send_alert(
            f"Pipeline velocity dropped to ${current['velocity']:,.0f}/day "
            f"(benchmark: ${historical_avg:,.0f}/day)"
        )

What to Build Next

Segment velocity by rep, territory, or product line. The overall number hides problems. The segmented view reveals them.

Related Reading

Want this system built for your business?

Get a free assessment. We will map every system your business needs and show you the ROI.

Get Your Free Assessment

Related Systems