Skip to main content

Frontend Error Tracking

Capturing, analyzing, and debugging JavaScript errors using devtool-mcp's proxy.

Overview

The proxy automatically captures:

  • Uncaught exceptions - window.onerror
  • Unhandled promise rejections - unhandledrejection events
  • Custom errors - Via window.__devtool.error()

All errors include stack traces, source locations, and page context.

Viewing Captured Errors

Query Error Logs

proxylog {proxy_id: "app", types: ["error"]}
{
entries: [
{
type: "error",
timestamp: "2024-01-15T10:32:15Z",
message: "Cannot read property 'map' of undefined",
source: "http://localhost:8080/static/js/main.js",
line: 142,
column: 23,
stack: "TypeError: Cannot read property 'map' of undefined\n at UserList (main.js:142:23)\n at renderWithHooks...",
url: "http://localhost:8080/users",
userAgent: "Mozilla/5.0..."
}
]
}

Filter by Time

// Errors in the last 5 minutes
proxylog {proxy_id: "app", types: ["error"], since: "5m"}

// Errors in a specific window
proxylog {proxy_id: "app", types: ["error"], since: "2024-01-15T10:00:00Z", until: "2024-01-15T11:00:00Z"}

Get Error Statistics

proxylog {proxy_id: "app", action: "stats"}
{
by_type: {
http: 1500,
error: 12,
performance: 45
}
}

Correlating Errors with Traffic

Find What API Calls Preceded an Error

// Get error timestamp
proxylog {proxy_id: "app", types: ["error"]}
→ Error at 10:32:15 on /users page

// Check API calls around that time
proxylog {
proxy_id: "app",
types: ["http"],
url_pattern: "/api",
since: "2024-01-15T10:32:00Z",
until: "2024-01-15T10:32:20Z"
}
{
entries: [
{url: "/api/users", status: 500, response_body: "{\"error\": \"...\"}", timestamp: "10:32:14"}
]
}

The API returned 500, causing the subsequent JavaScript error.

Use Page Sessions

// Get page session that had errors
currentpage {proxy_id: "app"}
{sessions: [{id: "page-1", error_count: 2, url: "/users"}]}

// Get full context
currentpage {proxy_id: "app", action: "get", session_id: "page-1"}
{
resources: [
{url: "/api/users", status: 500}
],
errors: [
{message: "Cannot read property 'map'..."}
],
performance: {...}
}

Debugging Specific Errors

Inspect Error Location

// From error log, we know the component is UserList at line 142
// Inspect the component in the browser

proxy {action: "exec", id: "app", code: "window.__devtool.inspect('.user-list')"}
{
element: {tag: "div", classes: ["user-list"]},
visibility: {visible: true},
// Check if element rendered at all
}

Check Application State

// What's in localStorage/sessionStorage?
proxy {action: "exec", id: "app", code: "window.__devtool.captureState(['localStorage', 'sessionStorage'])"}

// Check for cached data
{
localStorage: {users: null}, // Expected to have user data
sessionStorage: {}
}

Reproduce the Error

// Wait for the problematic component
proxy {action: "exec", id: "app", code: "window.__devtool.waitForElement('.user-list', 10000)"}

// If it never appears, the error prevented rendering

Custom Error Logging

Log from Application Code

// In your application code
try {
await fetchUsers();
} catch (error) {
window.__devtool?.error('Failed to fetch users', {
error: error.message,
stack: error.stack,
userId: currentUser.id
});
}

Query Custom Logs

proxylog {proxy_id: "app", types: ["custom"]}
{
entries: [
{
level: "error",
message: "Failed to fetch users",
data: {error: "Network error", userId: 123},
timestamp: "..."
}
]
}

Error Monitoring Patterns

Real-Time Error Watch

// Check for new errors periodically
proxylog {proxy_id: "app", types: ["error"], since: "1m"}

Error Grouping

proxy {action: "exec", id: "app", code: `
// Group errors by message (simplified)
const logs = await fetch('/__devtool_api/errors').then(r => r.json());
const grouped = {};

logs.forEach(err => {
const key = err.message.replace(/\\d+/g, 'N'); // Normalize numbers
grouped[key] = grouped[key] || {count: 0, examples: []};
grouped[key].count++;
if (grouped[key].examples.length < 3) {
grouped[key].examples.push(err);
}
});

grouped
`}

Error Rate Tracking

// Check error count
proxylog {proxy_id: "app", action: "stats"}
{by_type: {error: 12}}

// Compare to traffic
// If 12 errors in 1500 requests = 0.8% error rate

Handling Specific Error Types

Uncaught Exceptions

proxylog {proxy_id: "app", types: ["error"]}
{
message: "TypeError: Cannot read property 'x' of undefined",
source: "main.js",
line: 100
}

Debug approach:

  1. Check the source file and line
  2. Inspect variables at that location
  3. Check API responses that might have returned unexpected data

Promise Rejections

{
message: "Unhandled Promise Rejection: NetworkError",
source: "api.js",
line: 45
}

Debug approach:

  1. Check network logs for failed requests
  2. Add .catch() handlers to promises
  3. Check if network was available

Syntax Errors

{
message: "SyntaxError: Unexpected token '<'",
source: "app.js",
line: 1
}

This usually means:

  • JS file returned HTML (404 page)
  • Build error produced invalid JS
  • Script src is wrong

Check:

proxylog {proxy_id: "app", types: ["http"], url_pattern: "app.js"}
→ Check Content-Type and response body

Creating Error Reports

Capture Error Context

// When error is reported:

// 1. Screenshot
proxy {action: "exec", id: "app", code: "window.__devtool.screenshot('error-state')"}

// 2. DOM state
proxy {action: "exec", id: "app", code: "window.__devtool.captureDOM()"}

// 3. Application state
proxy {action: "exec", id: "app", code: "window.__devtool.captureState(['localStorage'])"}

// 4. Recent network
proxy {action: "exec", id: "app", code: "window.__devtool.captureNetwork()"}

// 5. Error details
proxylog {proxy_id: "app", types: ["error"], limit: 5}

Automated Error Report

proxy {action: "exec", id: "app", code: `
const report = {
timestamp: new Date().toISOString(),
url: window.location.href,
userAgent: navigator.userAgent,
viewport: {
width: window.innerWidth,
height: window.innerHeight
},
state: window.__devtool.captureState(['localStorage']),
recentErrors: [], // Would need API call to get these
screenshot: await window.__devtool.screenshot('error-report')
};

JSON.stringify(report, null, 2)
`}

Integration with Error Tracking Services

Send to External Service

// In your app, forward errors
window.addEventListener('error', (event) => {
// Log to devtool
window.__devtool?.log(event.message, 'error', {
source: event.filename,
line: event.lineno
});

// Also send to Sentry/Datadog/etc
Sentry.captureException(event.error);
});

Compare with Production

// Proxy captures same data as production error tracking
// Use for debugging before errors reach production

Best Practices

  1. Always check errors first - Many bugs start with JS errors
  2. Correlate with API calls - Errors often caused by bad data
  3. Use page sessions - See full context of error
  4. Capture state - localStorage, DOM, network
  5. Screenshot - Visual state at error time
  6. Check console too - Some errors only in console

Common Error Patterns

ErrorLikely CauseDebug Steps
undefined is not a functionMethod on nullCheck API response
Cannot read property XNull referenceTrace data flow
Network ErrorCORS, offline, 500Check HTTP logs
Unexpected token <HTML instead of JSCheck Content-Type
Script error.Cross-origin scriptCheck CORS headers

See Also