Skip to main content
Modern web applications make extensive API calls via XHR and Fetch. This recipe demonstrates how to use bdg to monitor, filter, and analyze API traffic in real-time.

Scenario

You’re investigating API behavior for a web application that:
  • Makes authenticated API calls to https://api.example.com
  • Uses JWT tokens for authentication
  • Implements retry logic for failed requests
  • Has CORS issues on some endpoints
You need to monitor all API traffic, inspect request/response headers, and identify failing requests.

Workflow

1

Start session and navigate to the app

Launch bdg and load the application. Network collection is enabled by default.
bdg https://app.example.com/dashboard
Wait for the session to start and the page to load.
2

Filter for API requests only

Use the API preset to show only XHR and Fetch requests.
# Show all API calls
bdg network list --preset api

# Or filter explicitly
bdg network list --type XHR,Fetch
Expected output:
NETWORK REQUESTS (API only)

[0] GET /api/user → 200 OK (145ms)
    Size: 1.2 KB | Type: Fetch

[1] GET /api/dashboard/stats → 200 OK (234ms)
    Size: 3.4 KB | Type: XHR

[2] POST /api/events → 201 Created (89ms)
    Size: 567 B | Type: Fetch
3

Monitor API calls in real-time

Stream network requests as they happen using follow mode.
# Watch API calls live
bdg network list --preset api --follow
Leave this running in one terminal while interacting with the app in another terminal or browser.
4

Find failing API requests

Filter for error status codes to identify issues.
# Show all 4xx and 5xx errors
bdg network list --filter "status-code:>=400"

# Show only 401 Unauthorized (auth issues)
bdg network list --filter "status-code:401"

# Show server errors only
bdg network list --filter "status-code:>=500"

# Combine with API filter
bdg network list --preset api --filter "status-code:>=400"
Expected output:
NETWORK REQUESTS (errors)

[0] GET /api/protected/resource → 401 Unauthorized (67ms)
    Size: 234 B | Type: Fetch

[1] POST /api/data/submit → 422 Unprocessable Entity (112ms)
    Size: 456 B | Type: XHR
5

Inspect authentication headers

Check request and response headers for authentication issues.
# Get request ID from the failed request
REQUEST_ID=$(bdg network list --filter "status-code:401" --json | jq -r '.data.requests[0].requestId')

# Inspect headers
bdg network headers $REQUEST_ID
Expected output:
URL: https://api.example.com/protected/resource

Response Headers:
─────────────────────────────────────────────────────
access-control-allow-origin: https://app.example.com
content-type: application/json
www-authenticate: Bearer realm="API"

Request Headers:
─────────────────────────────────────────────────────
authorization: Bearer eyJhbGc...
content-type: application/json

Request ID: A1B2C3D4.567
Check if the authorization header is present and properly formatted.
6

Filter API calls by domain

If the app calls multiple APIs, filter by domain to focus on one.
# Show only calls to main API
bdg network list --filter "domain:api.example.com"

# Exclude CDN requests
bdg network list --filter "!domain:cdn.*"

# Show calls to any subdomain
bdg network list --filter "domain:*.example.com"
7

Inspect CORS headers

Check CORS headers on failing cross-origin requests.
# Find requests with CORS-related headers
bdg network list --filter "has-response-header:access-control-allow-origin"

# Inspect full CORS headers
bdg network headers $REQUEST_ID | grep -i "access-control"
Expected output:
access-control-allow-credentials: true
access-control-allow-headers: Content-Type, Authorization
access-control-allow-methods: GET, POST, PUT, DELETE
access-control-allow-origin: https://app.example.com
Common CORS issues:
  • Missing access-control-allow-origin header
  • Wildcard * origin with credentials
  • Missing method in access-control-allow-methods
8

Track retry attempts

If the app retries failed requests, identify the pattern.
# Show duplicate requests to same URL
bdg network list --json | jq -r '[.data.requests[] | select(.url | contains("/api/retry-test"))] | group_by(.url) | .[] | {url: .[0].url, attempts: length, statuses: [.[].status]}'
Expected output:
{
  "url": "https://api.example.com/api/retry-test",
  "attempts": 3,
  "statuses": [500, 500, 200]
}
This shows 2 failed attempts (500) followed by success (200).
9

Export API traffic as HAR file

Export all network data for analysis in external tools.
# Export while session is running
bdg network har api-debug-$(date +%Y%m%d-%H%M%S).har

# Or stop and export final state
bdg stop
bdg network har final-api-capture.har
Import the HAR file into Chrome DevTools or online HAR viewers for detailed analysis.
10

Analyze request/response bodies

Get full request and response details including bodies.
# Get request ID for failed POST
REQUEST_ID=$(bdg network list --filter "method:POST status-code:422" --json | jq -r '.data.requests[0].requestId')

# View full details
bdg details network $REQUEST_ID
Expected output:
{
  "url": "https://api.example.com/api/data/submit",
  "method": "POST",
  "status": 422,
  "requestHeaders": {
    "content-type": "application/json"
  },
  "requestBody": {
    "name": "",
    "email": "invalid-email"
  },
  "responseBody": {
    "errors": {
      "name": "Name is required",
      "email": "Invalid email format"
    }
  }
}

Filtering Patterns

Find large API responses

# Show API calls returning more than 1MB
bdg network list --preset api --filter "larger-than:1MB"

Track authentication refresh flow

# Show token refresh requests
bdg network list --filter "domain:api.* method:POST" --json | jq '[.data.requests[] | select(.url | contains("/auth/refresh"))]'

Monitor WebSocket connections

# Show WebSocket handshakes
bdg network list --filter "scheme:wss"

Find cached vs fresh API calls

# Show cached responses
bdg network list --preset cached

# Show non-cached API calls
bdg network list --preset api --filter "!is:from-cache"

Common API Issues

Symptom: API calls fail with 401 after user has been idle.Investigation:
# Check authorization header
bdg network headers $REQUEST_ID | grep -i authorization

# Decode JWT (if not signed)
bdg network list --json | jq -r '.data.requests[0].requestHeaders.authorization' | sed 's/Bearer //' | cut -d'.' -f2 | base64 -d 2>/dev/null | jq '.exp'
Compare exp (expiration) timestamp with current time.
Symptom: API calls fail after rapid requests.Investigation:
# Find rate limit headers
bdg network headers $REQUEST_ID | grep -i "rate-limit\|retry-after"

# Count requests in last minute
bdg network list --json | jq '[.data.requests[] | select(.wallTime > (now - 60))] | length'
Symptom: OPTIONS requests fail before actual API call.Investigation:
# Show OPTIONS requests
bdg network list --filter "method:OPTIONS"

# Check if preflight succeeded
bdg network list --filter "method:OPTIONS status-code:>=400"

# Inspect CORS headers
bdg network headers $REQUEST_ID | grep -i "access-control"
Symptom: API calls take too long.Investigation:
# Export HAR and analyze timing
bdg network har timing-analysis.har

# Extract timing data via JSON
bdg network list --json | jq '.data.requests[] | {url, duration: .timing.duration}' | sort -k2 -nr | head -10

Advanced Techniques

Correlate API calls with user actions

Run commands in sequence and track which API calls they trigger:
# Clear existing data
bdg stop && bdg https://app.example.com

# Perform action
bdg dom click "#refresh-button"

# Wait for network to settle
sleep 2

# Show API calls after action
bdg network list --preset api --last 5

Monitor API calls during form submission

# Fill form
bdg dom fill "#username" "testuser"
bdg dom fill "#password" "testpass"

# Submit and watch network
bdg dom submit "#login-form"

# Check for auth API calls
bdg network list --filter "domain:api.* method:POST" --last 3

Export API call summary

bdg network list --preset api --json | jq '{
  total: (.data.requests | length),
  by_status: (.data.requests | group_by(.status) | map({status: .[0].status, count: length})),
  by_method: (.data.requests | group_by(.method) | map({method: .[0].method, count: length}))
}'
Expected output:
{
  "total": 24,
  "by_status": [
    {"status": 200, "count": 20},
    {"status": 401, "count": 2},
    {"status": 422, "count": 2}
  ],
  "by_method": [
    {"method": "GET", "count": 18},
    {"method": "POST", "count": 6}
  ]
}

Automation Example

Script to monitor API health:
#!/bin/bash
# api-health-check.sh

URL="https://app.example.com"
THRESHOLD_4XX=5
THRESHOLD_5XX=1

echo "Starting API health check for $URL"
bdg $URL

# Wait for initial load
sleep 5

# Count errors
ERRORS_4XX=$(bdg network list --filter "status-code:>=400 status-code:<500" --json | jq '.data.requests | length')
ERRORS_5XX=$(bdg network list --filter "status-code:>=500" --json | jq '.data.requests | length')

echo "4xx errors: $ERRORS_4XX (threshold: $THRESHOLD_4XX)"
echo "5xx errors: $ERRORS_5XX (threshold: $THRESHOLD_5XX)"

if [ $ERRORS_5XX -gt $THRESHOLD_5XX ]; then
  echo "❌ CRITICAL: Too many 5xx errors"
  bdg network list --filter "status-code:>=500"
  exit 1
elif [ $ERRORS_4XX -gt $THRESHOLD_4XX ]; then
  echo "⚠️  WARNING: High rate of 4xx errors"
  bdg network list --filter "status-code:>=400 status-code:<500"
  exit 1
else
  echo "✓ API health check passed"
fi

bdg stop

Next Steps

Network List Command

Learn all network filtering options

HAR Export

Export network data in HAR format

Headers Inspection

Inspect HTTP request/response headers

Debugging SPAs

Correlate API calls with console errors

Build docs developers (and LLMs) love