Features
- API latency breakdown showing processing time vs network/waiting time
- Percentage split visualization with color-coded bar chart
- Performance bottleneck detection (network time thresholds)
- Per-message timing read from the statusline JSON, formatted to two decimals via bc
- Color-coded performance status (green <1s, yellow 1-5s, red >5s network time)
- Visual ratio bar (blue = API processing, orange = network overhead)
- Helps identify network issues vs API performance problems
- Lightweight bash with bc for floating-point calculations
Use Cases
- Performance debugging for slow Claude Code responses
- Identifying network/waiting time vs API processing delays
- Troubleshooting VPN/proxy latency that inflates network time
- Spotting when network overhead, not API time, dominates a response
Requirements
- Claude Code CLI installed and configured
- Bash shell available (bash 4.0+ recommended for arithmetic operations)
- jq command-line JSON processor (jq 1.6+ recommended for safe extraction with // defaults)
- bc calculator (bc 1.07+ recommended for floating point calculations, optional - script falls back to integer math)
- Terminal with ANSI color code support (256-color mode recommended for ratio bar visualization)
- Write access to /tmp directory (optional, for P95 latency tracking if using enhanced version)
Configuration
{
"statusLine": {
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/statuslines/api-latency-breakdown.sh"
}
}
Examples
Enhanced Latency Breakdown with P95 Tracking
Extended version with percentile latency tracking and historical comparison
#!/usr/bin/env bash
# Enhanced API Latency Breakdown with P95 Tracking
input=$(cat)
total_duration_ms=$(echo "$input" | jq -r '.cost.total_duration_ms // 0')
api_duration_ms=$(echo "$input" | jq -r '.cost.total_api_duration_ms // 0')
network_time=$((total_duration_ms - api_duration_ms))
if [ $network_time -lt 0 ]; then
network_time=0
fi
# Store latency history in /tmp
HIST_FILE="/tmp/claude_latency_history.txt"
echo "$network_time" >> "$HIST_FILE"
# Calculate P95 if we have enough samples (last 20 measurements)
if [ -f "$HIST_FILE" ] && [ $(wc -l < "$HIST_FILE") -ge 20 ]; then
p95_network=$(sort -n "$HIST_FILE" | tail -n 20 | awk 'BEGIN{c=0} {a[c++]=$1} END{print a[int(c*0.95)]}')
p95_display=$(echo "scale=2; $p95_network / 1000" | bc 2>/dev/null || echo "$((p95_network / 1000))")
p95_info=" | P95: ${p95_display}s"
else
p95_info=""
fi
api_seconds=$(echo "scale=2; $api_duration_ms / 1000" | bc 2>/dev/null || echo "$((api_duration_ms / 1000))")
network_seconds=$(echo "scale=2; $network_time / 1000" | bc 2>/dev/null || echo "$((network_time / 1000))")
if [ $total_duration_ms -gt 0 ]; then
api_percentage=$(( (api_duration_ms * 100) / total_duration_ms ))
network_percentage=$(( 100 - api_percentage ))
else
api_percentage=0
network_percentage=0
fi
if [ $network_time -lt 1000 ]; then
PERF_COLOR="\033[38;5;46m"
PERF_STATUS="✓ FAST"
elif [ $network_time -lt 5000 ]; then
PERF_COLOR="\033[38;5;226m"
PERF_STATUS="⚠ SLOW"
else
PERF_COLOR="\033[38;5;196m"
PERF_STATUS="✗ BOTTLENECK"
fi
RESET="\033[0m"
API_BAR="\033[48;5;75m"
NET_BAR="\033[48;5;214m"
api_chars=$((api_percentage / 5))
net_chars=$((network_percentage / 5))
api_bar=$(printf "${API_BAR} %.0s" $(seq 1 $api_chars))${RESET}
net_bar=$(printf "${NET_BAR} %.0s" $(seq 1 $net_chars))${RESET}
echo -e "${PERF_COLOR}${PERF_STATUS}${RESET} | API: ${api_seconds}s (${api_percentage}%) | Network: ${network_seconds}s (${network_percentage}%)${p95_info} | ${api_bar}${net_bar}"
Latency Breakdown with Custom Thresholds
Configurable performance thresholds for different network environments
#!/usr/bin/env bash
# API Latency Breakdown with Custom Thresholds
# Configure via environment variables
FAST_THRESHOLD=${LATENCY_FAST_THRESHOLD:-1000} # Default: 1 second
SLOW_THRESHOLD=${LATENCY_SLOW_THRESHOLD:-5000} # Default: 5 seconds
input=$(cat)
total_duration_ms=$(echo "$input" | jq -r '.cost.total_duration_ms // 0')
api_duration_ms=$(echo "$input" | jq -r '.cost.total_api_duration_ms // 0')
network_time=$((total_duration_ms - api_duration_ms))
if [ $network_time -lt 0 ]; then
network_time=0
fi
api_seconds=$(echo "scale=2; $api_duration_ms / 1000" | bc 2>/dev/null || echo "$((api_duration_ms / 1000))")
network_seconds=$(echo "scale=2; $network_time / 1000" | bc 2>/dev/null || echo "$((network_time / 1000))")
if [ $total_duration_ms -gt 0 ]; then
api_percentage=$(( (api_duration_ms * 100) / total_duration_ms ))
network_percentage=$(( 100 - api_percentage ))
else
api_percentage=0
network_percentage=0
fi
# Custom thresholds
if [ $network_time -lt $FAST_THRESHOLD ]; then
PERF_COLOR="\033[38;5;46m"
PERF_STATUS="✓ FAST"
elif [ $network_time -lt $SLOW_THRESHOLD ]; then
PERF_COLOR="\033[38;5;226m"
PERF_STATUS="⚠ SLOW"
else
PERF_COLOR="\033[38;5;196m"
PERF_STATUS="✗ BOTTLENECK"
fi
RESET="\033[0m"
API_BAR="\033[48;5;75m"
NET_BAR="\033[48;5;214m"
api_chars=$((api_percentage / 5))
net_chars=$((network_percentage / 5))
api_bar=$(printf "${API_BAR} %.0s" $(seq 1 $api_chars))${RESET}
net_bar=$(printf "${NET_BAR} %.0s" $(seq 1 $net_chars))${RESET}
echo -e "${PERF_COLOR}${PERF_STATUS}${RESET} | API: ${api_seconds}s (${api_percentage}%) | Network: ${network_seconds}s (${network_percentage}%) | ${api_bar}${net_bar}"
API Latency Breakdown Installation Example
Complete setup script with bc installation check
#!/bin/bash
# Installation script for API Latency Breakdown
mkdir -p .claude/statuslines
# Check for bc (required for floating point calculations)
if ! command -v bc &> /dev/null; then
echo "Installing bc for floating point calculations..."
if [[ "$OSTYPE" == "darwin"* ]]; then
brew install bc
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
sudo apt-get install -y bc || sudo yum install -y bc
else
echo "Please install bc manually: https://www.gnu.org/software/bc/"
fi
fi
cat > .claude/statuslines/api-latency-breakdown.sh << 'SCRIPT_EOF'
#!/usr/bin/env bash
# Paste the full statusline script from the primary example above before running this installer.
SCRIPT_EOF
chmod +x .claude/statuslines/api-latency-breakdown.sh
# Add to settings.json
if [ ! -f .claude/settings.json ]; then
echo '{"statusLine":{"type":"command","command":"$CLAUDE_PROJECT_DIR/.claude/statuslines/api-latency-breakdown.sh"}}' > .claude/settings.json
else
jq '.statusLine = {"type":"command","command":"$CLAUDE_PROJECT_DIR/.claude/statuslines/api-latency-breakdown.sh"}' .claude/settings.json > .claude/settings.json.tmp
mv .claude/settings.json.tmp .claude/settings.json
fi
echo "API Latency Breakdown installed successfully!"
echo "Note: bc is required for floating point calculations. If not installed, script will use integer math."
Troubleshooting
Network time showing negative or zero despite slow responses
Verify both cost.total_duration_ms and cost.total_api_duration_ms fields exist: echo '$input' | jq .cost. Negative protection caps network_time at 0. If both values missing, script shows 0s - check Claude Code version supports these fields. Verify JSON structure: jq '.cost | keys' to see available fields.
API percentage always showing 100% with no network time
This indicates total_duration_ms equals total_api_duration_ms (no measurable network overhead). Verify calculations: network_time = total - API. If consistently 0, either network is extremely fast or fields are identical in JSON. Check actual JSON values: echo '$input' | jq '.cost.total_duration_ms, .cost.total_api_duration_ms'. Test with known slow network to verify detection works.
Performance status showing BOTTLENECK incorrectly
Thresholds: <1s green (FAST), 1-5s yellow (SLOW), >5s red (BOTTLENECK). Adjust thresholds in script if your network baseline differs. VPN users may see higher normal latency. Modify: network_time -lt 5000 to higher value for VPN environments. Use custom thresholds version: export LATENCY_FAST_THRESHOLD=2000 LATENCY_SLOW_THRESHOLD=10000.
Ratio bar not displaying or showing as empty
Bar uses ANSI background colors (\033[48;5;Xm). Ensure terminal supports 256-color mode: tput colors (should return 256). If bars show as spaces only, verify ANSI escape codes working: echo -e '\033[48;5;75m BLUE \033[0m'. Check terminal emulator color support settings. Verify echo -e flag is used for escape sequence interpretation.
bc: command not found when calculating percentages
Install bc: brew install bc (macOS), apt install bc (Linux), or download from https://www.gnu.org/software/bc/. Alternative: use integer math only: api_percentage=$((api_duration_ms * 100 / total_duration_ms)) - removes decimal precision but works without bc. Script includes fallback to integer math if bc unavailable. Verify bc installation: which bc.
Floating point seconds showing as integers (no decimals)
This indicates bc is not working or fallback to integer math is active. Check bc installation: bc --version. Verify bc command in script: echo 'scale=2; 1234 / 1000' | bc (should return 1.34). If bc fails, script uses integer division: $((api_duration_ms / 1000)) which truncates decimals. Install bc for decimal precision.
Percentage calculations showing incorrect values
Verify integer division is working correctly: echo $((100 * 50 / 100)) (should be 50). Check total_duration_ms > 0 before division. Test calculation: api_percentage=$((api_duration_ms * 100 / total_duration_ms)). Ensure values are numeric: echo "$api_duration_ms" | grep -E '^[0-9]+$'. Check for integer overflow if values are very large.
Statusline output showing raw ANSI codes instead of colors
Verify echo -e flag is used for escape sequence interpretation. Check terminal supports ANSI colors: echo -e '\033[38;5;46mGreen\033[0m'. Some terminals require explicit color support enabled. Check TERM environment variable: echo $TERM (should include 'xterm' or '256color'). Verify terminal emulator settings for color support.