{"course":{"slug":"building-apps-with-ai","title":"Building Apps with AI","url":"https://addaly.com/learn/building-apps-with-ai","level":"beginner","track":"build"},"lesson":{"slug":"knowing-it-broke-before-users-tell-you","title":"Knowing it broke before users tell you","url":"https://addaly.com/learn/building-apps-with-ai/knowing-it-broke-before-users-tell-you","position":80,"of":87,"minutes":8,"answer":"Error tracking catches what throws, uptime pings catch what is down, and a report button catches what is wrong: three different failures.","keyIdea":"Error tracking catches what throws, uptime pings catch what is down, and a report button catches what is wrong: three different failures, and a shipped app needs all three because each is blind to the other two."},"body":{"format":"markdown","text":"## Three kinds of broken\n\nThe deploy lesson said to find the logs and get told about errors. This lesson is about what \"told\" has to cover, because there are three different ways an app is broken and each needs a different watcher.\n\n**It throws.** A route crashes, a page fails to render, a promise rejects. Something in the code raised an error.\n\n**It is down.** Nothing answers, or the answer is a host's error page. The code may be fine; the process, the database or the DNS is not.\n\n**It is wrong.** Every request succeeds and the result is incorrect. The date is off by one, the total is wrong, the email went to the wrong person. No error, no outage, and the most expensive of the three because it runs quietly for weeks.\n\n## What throws: error tracking\n\nSentry's free tier covers a few thousand events a month, which is more than a small app should produce. Alternatives with free tiers exist (LaunchDarkly's observability tools, which took over Highlight in 2025, and GlitchTip, which also runs on your own server) and every host has a basic error log. Whichever, the setup is a few lines and three settings that matter.\n\n> Figure: Three watchers, because each is blind to the others. A two by two grid, rows The site answers and Nothing answers, columns Something threw and Nothing threw: The site answers and Something threw: Error tracker; The site answers and Nothing threw: Report button; Nothing answers and Something threw: Uptime monitor; Nothing answers and Nothing threw: Uptime monitor. The bottom row is one watcher twice, and that is the point: nothing answering looks identical whether or not your code threw. The top right is the expensive one, because it runs quietly for weeks.\n\nUpload source maps at build time, so that a stack trace names your file and line rather than a position in a minified bundle. Without them, the tracker tells you something failed at column 48,213 of `main.js`.\n\nAttach the request id and the user's id (the id, never the email) to every event, so that a report can be joined to a person's complaint.\n\nCheck the scrubbing. Trackers can send request bodies and headers by default; a body containing a note's full text is then in a third party's storage. Sentry already strips authorisation headers, cookies and fields named like passwords or tokens, and keeps server-side scrubbing on by default; leave it on, confirm the same on any other tracker, and add rules for your own sensitive fields, such as a note's text.\n\nThen the alert: a new type of error, first seen, emails you. Not every error: a known flaky one at 3am is noise you will learn to ignore, and then you will ignore the real one. Alert on *new* and on *rate*, and look at the rest weekly.\n\n## What is down: the monitor\n\nThe health route from the shipping block, pinged every minute or five by a free service, with an alert when it fails twice in a row. Two in a row, not one: a single failed ping is usually the monitor's network, and an alert that fires on it teaches you to ignore alerts.\n\nMake the health route check what matters: a trivial query against the database, so that a paused database (the previous lesson) reads as down rather than as up-with-errors. Return the commit sha, so that the monitor's history doubles as a record of which version was live when.\n\n## What is wrong: the report button\n\nNothing automatic catches the wrong date. A person does, and the question is whether they can tell you in a way you can act on. A \"report a problem\" link on every page, opening a small form that captures, with consent, the page URL, the browser, the last few console messages and a screenshot, and sends them with the user's id to a table you read. Twenty lines of client code and one route. Addaly's own site carries one on every page for this reason.\n\nThe alternative is an email address in the footer, which the deploy lesson suggested and which is better than nothing and worse than a form: the email says \"it didn't work\" and the form says which page, which browser, and what the console printed.\n\nRead the reports. A report table nobody looks at is an apology form.\n\n## The one metric worth a glance\n\nBeyond errors and uptime, one number: how many of the key action succeeded today. Bookings created, notes saved, whatever the app is for. A count per day in a simple query, and a look at it each morning. A drop with no errors is the wrong-answer bug from the check above, or a broken button, or a change in who is visiting. It is the cheapest early warning there is, and the generated app has no such number until you ask.\n\n## What not to build yet\n\nDashboards with twelve charts, distributed tracing, log aggregation across services, alerting hierarchies. The cloud course covers them for the day the app has a team. A single-person app needs an error tracker with scrubbing and source maps, a two-strike uptime ping, a report button, and one daily number. That set costs nothing and it is the difference between learning about a problem from a tool and learning about it from a tweet."},"check":{"question":"An app has error tracking with alerts, and an uptime monitor on its health route. Users report that bookings made on the last day of any month are saved with the wrong date. Neither tool ever alerted. Why not?","options":[{"text":"The tools were misconfigured and were not receiving events from the booking route, which is common when a route is added after the tracker was set up and nobody re-checks the integration.","correct":false,"tempting":"They may well have been receiving everything; a booking saved with the wrong date raises no error and returns a 200, so there was no event to send."},{"text":"Date bugs only occur in the browser, where error tracking does not run.","correct":false,"tempting":"Error tracking runs in browsers too; the point is that no error was thrown anywhere, not where it would have been caught."},{"text":"A wrong answer is not an exception and not an outage; the code ran to completion and returned success, so nothing either tool watches for occurred.","correct":true},{"text":"The alerts were sent but went to a spam folder.","correct":false,"tempting":"Explains a missed alert, not the absence of one; there was nothing to alert on."}]},"prev":{"slug":"the-free-tiers-and-where-they-end","title":"The free tiers, and exactly where they end","url":"https://addaly.com/learn/building-apps-with-ai/the-free-tiers-and-where-they-end"},"next":{"slug":"the-first-user-complaint","title":"The first user complaint","url":"https://addaly.com/learn/building-apps-with-ai/the-first-user-complaint"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'Knowing it broke before users tell you', in Building Apps with AI. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/building-apps-with-ai/knowing-it-broke-before-users-tell-you (Accessed: 13 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"Knowing it broke before users tell you","courseTitle":"Building Apps with AI","module":{"index":9,"slug":"what-it-costs-and-where-this-stops","title":"What it costs, running it, and where this stops"},"answer":null,"keyIdea":"Error tracking catches what throws, uptime pings catch what is down, and a report button catches what is wrong: three different failures, and a shipped app needs all three because each is blind to the other two.","hero":{"kind":"figure","figure":{"t":"figure","label":"Figure","figure":{"cols":["Something threw","Nothing threw"],"rows":["The site answers","Nothing answers"],"type":"matrix","cells":[["Error tracker","Report button"],["Uptime monitor","Uptime monitor"]],"title":"Three watchers, because each is blind to the others","caption":"The bottom row is one watcher twice, and that is the point: nothing answering looks identical whether or not your code threw. The top right is the expensive one, because it runs quietly for weeks.","cellLabels":[["a route crashed","worked, but wrong"],["the process is gone","DNS or the host"]]},"alt":"Figure: Three watchers, because each is blind to the others. A two by two grid, rows The site answers and Nothing answers, columns Something threw and Nothing threw: The site answers and Something threw: Error tracker; The site answers and Nothing threw: Report button; Nothing answers and Something threw: Uptime monitor; Nothing answers and Nothing threw: Uptime monitor. The bottom row is one watcher twice, and that is the point: nothing answering looks identical whether or not your code threw. The top right is the expensive one, because it runs quietly for weeks."}},"blocks":[{"t":"h2","id":"three-kinds-of-broken","runs":[{"text":"Three kinds of broken"}]},{"t":"p","runs":[{"text":"The deploy lesson said to find the logs and get told about errors. This lesson is about what “told” has to cover, because there are three different ways an app is broken and each needs a different watcher."}]},{"t":"p","runs":[{"text":"It throws.","b":true},{"text":" A route crashes, a page fails to render, a promise rejects. Something in the code raised an error."}]},{"t":"p","runs":[{"text":"It is down.","b":true},{"text":" Nothing answers, or the answer is a host’s error page. The code may be fine; the process, the database or the DNS is not."}]},{"t":"p","runs":[{"text":"It is wrong.","b":true},{"text":" Every request succeeds and the result is incorrect. The date is off by one, the total is wrong, the email went to the wrong person. No error, no outage, and the most expensive of the three because it runs quietly for weeks."}]},{"t":"h2","id":"what-throws-error-tracking","runs":[{"text":"What throws: error tracking"}]},{"t":"p","runs":[{"text":"Sentry’s free tier covers a few thousand events a month, which is more than a small app should produce. Alternatives with free tiers exist (LaunchDarkly’s observability tools, which took over Highlight in 2025, and GlitchTip, which also runs on your own server) and every host has a basic error log. Whichever, the setup is a few lines and three settings that matter."}]},{"t":"p","runs":[{"text":"Upload source maps at build time, so that a stack trace names your file and line rather than a position in a minified bundle. Without them, the tracker tells you something failed at column 48,213 of "},{"text":"main.js","code":true},{"text":"."}]},{"t":"p","runs":[{"text":"Attach the request id and the user’s id (the id, never the email) to every event, so that a report can be joined to a person’s complaint."}]},{"t":"p","runs":[{"text":"Check the scrubbing. Trackers can send request bodies and headers by default; a body containing a note’s full text is then in a third party’s storage. Sentry already strips authorisation headers, cookies and fields named like passwords or tokens, and keeps server-side scrubbing on by default; leave it on, confirm the same on any other tracker, and add rules for your own sensitive fields, such as a note’s text."}]},{"t":"p","runs":[{"text":"Then the alert: a new type of error, first seen, emails you. Not every error: a known flaky one at 3am is noise you will learn to ignore, and then you will ignore the real one. Alert on "},{"text":"new","i":true},{"text":" and on "},{"text":"rate","i":true},{"text":", and look at the rest weekly."}]},{"t":"h2","id":"what-is-down-the-monitor","runs":[{"text":"What is down: the monitor"}]},{"t":"p","runs":[{"text":"The health route from the shipping block, pinged every minute or five by a free service, with an alert when it fails twice in a row. Two in a row, not one: a single failed ping is usually the monitor’s network, and an alert that fires on it teaches you to ignore alerts."}]},{"t":"p","runs":[{"text":"Make the health route check what matters: a trivial query against the database, so that a paused database (the previous lesson) reads as down rather than as up-with-errors. Return the commit sha, so that the monitor’s history doubles as a record of which version was live when."}]},{"t":"h2","id":"what-is-wrong-the-report-button","runs":[{"text":"What is wrong: the report button"}]},{"t":"p","runs":[{"text":"Nothing automatic catches the wrong date. A person does, and the question is whether they can tell you in a way you can act on. A “report a problem” link on every page, opening a small form that captures, with consent, the page URL, the browser, the last few console messages and a screenshot, and sends them with the user’s id to a table you read. Twenty lines of client code and one route. Addaly’s own site carries one on every page for this reason."}]},{"t":"p","runs":[{"text":"The alternative is an email address in the footer, which the deploy lesson suggested and which is better than nothing and worse than a form: the email says “it didn’t work” and the form says which page, which browser, and what the console printed."}]},{"t":"p","runs":[{"text":"Read the reports. A report table nobody looks at is an apology form."}]},{"t":"h2","id":"the-one-metric-worth-a-glance","runs":[{"text":"The one metric worth a glance"}]},{"t":"p","runs":[{"text":"Beyond errors and uptime, one number: how many of the key action succeeded today. Bookings created, notes saved, whatever the app is for. A count per day in a simple query, and a look at it each morning. A drop with no errors is the wrong-answer bug from the check above, or a broken button, or a change in who is visiting. It is the cheapest early warning there is, and the generated app has no such number until you ask."}]},{"t":"h2","id":"what-not-to-build-yet","runs":[{"text":"What not to build yet"}]},{"t":"p","runs":[{"text":"Dashboards with twelve charts, distributed tracing, log aggregation across services, alerting hierarchies. The cloud course covers them for the day the app has a team. A single-person app needs an error tracker with scrubbing and source maps, a two-strike uptime ping, a report button, and one daily number. That set costs nothing and it is the difference between learning about a problem from a tool and learning about it from a tweet."}]}],"check":{"question":[{"text":"An app has error tracking with alerts, and an uptime monitor on its health route. Users report that bookings made on the last day of any month are saved with the wrong date. Neither tool ever alerted. Why not?"}],"options":[{"text":[{"text":"The tools were misconfigured and were not receiving events from the booking route, which is common when a route is added after the tracker was set up and nobody re-checks the integration."}],"correct":false,"tempting":[{"text":"They may well have been receiving everything; a booking saved with the wrong date raises no error and returns a 200, so there was no event to send."}]},{"text":[{"text":"Date bugs only occur in the browser, where error tracking does not run."}],"correct":false,"tempting":[{"text":"Error tracking runs in browsers too; the point is that no error was thrown anywhere, not where it would have been caught."}]},{"text":[{"text":"A wrong answer is not an exception and not an outage; the code ran to completion and returned success, so nothing either tool watches for occurred."}],"correct":true,"tempting":null},{"text":[{"text":"The alerts were sent but went to a spam folder."}],"correct":false,"tempting":[{"text":"Explains a missed alert, not the absence of one; there was nothing to alert on."}]}],"order":[1,3,2,0],"why":null},"prev":{"slug":"the-free-tiers-and-where-they-end","title":"The free tiers, and exactly where they end","minutes":8},"next":{"slug":"the-first-user-complaint","title":"The first user complaint","minutes":8}}}