Guide
How to find JavaScript errors on a site you don't control
A client's site, a competitor's checkout, a page your tag manager touches: you can't add an error tracker to it, but you can still see what breaks. Here's how, and what each method misses.
By Roger Campos · Last updated: September 2026
TL;DR
To find JavaScript errors on a site you don't control, load it in a browser and listen to the console: by hand in DevTools, or from code with headless Chrome capturing console.error, console.warn, uncaught exceptions and unhandled promise rejections. A load-time capture catches what breaks on arrival; errors behind a click or a login need a script that performs them, or real-user monitoring.
Free plan, no credit card. 1,000 credits a month.
The premise
Every JavaScript error happens in a browser you can own
Error trackers like Sentry need a snippet on the site. A client's site, a vendor's checkout or a page your tag manager touches won't let you add one. You don't need it: the errors happen in the visitor's browser, and you can be the visitor.
Load the page in a browser you control and listen to its console, and you see what any visitor would see — the errors the page's own code logs, and the exceptions nothing caught. That works on any public page, needs no access to the code, and leaves no trace on the site.
What it can't see is anything that doesn't run in that one visit: server-side errors, code paths behind a login or a click you didn't make, and the long tail of browsers and extensions your real visitors bring. Keep that boundary in mind; it decides which method below fits.
By hand
Method 1: DevTools, for one page right now
- 1Open the page in Chrome, then DevTools: F12, or Cmd+Option+J on a Mac to land on the Console.
- 2Tick Preserve log so messages survive redirects, then reload — errors during load are the ones you most want, and they happen before you opened the panel.
- 3Filter to Errors and Warnings. Click a message's source link to jump to the line; if the file is minified, the
{}button pretty-prints it. - 4Check the Network panel too, filtered to failed requests. A blocked script or a 404ed chunk is often the cause of the error you're reading.
It's the fastest way to understand one error. It doesn't scale past a handful of pages, and it only tells you about today.
From code
Method 2: capture the console with headless Chrome
Automate the same thing and you can check hundreds of pages, on a schedule, and diff the results. Two events matter: console messages at the error and warning level, and uncaught exceptions, which Puppeteer calls pageerror.
import puppeteer from "puppeteer";
const browser = await puppeteer.launch();
const page = await browser.newPage();
const messages = [];
page.on("console", (msg) => {
if (["error", "warn"].includes(msg.type())) messages.push({ type: msg.type(), text: msg.text() });
});
page.on("pageerror", (err) => messages.push({ type: "exception", text: err.message }));
await page.goto("https://example.com", { waitUntil: "networkidle2", timeout: 30_000 });
await new Promise((r) => setTimeout(r, 2000)); // let late scripts report
console.log(JSON.stringify(messages, null, 2));
await browser.close();Two practical notes. Chrome logs some messages itself — a failed resource load, a mixed-content or CSP violation — which arrive through the same console event; decide whether you want those or only what the page's code logged. And networkidle2 plus a short wait is a compromise: errors from scripts that run on a timer, or after the first interaction, need longer or a scripted interaction to appear.
Reading the output
What you'll see, and what's worth fixing
| Kind | Looks like | Usually means |
|---|---|---|
| Uncaught exception | TypeError: Cannot read properties of undefined | Code that broke. Something on the page probably doesn't work. |
| Unhandled promise rejection | Uncaught (in promise) Error: Request failed | A failed fetch or async step nobody handled — often missing content. |
| console.error from the page | Hydration failed because the server HTML didn't match | The code noticed a problem and said so. Read it; it's often specific. |
| console.warn | Deprecated API, cookie attribute, third-party notice | Rarely urgent; watch for new ones. |
| Third-party noise | Errors from an ad, analytics or chat script | Not your bug, but it can still break your page. |
- Load the page more than once. Ads, A/B tests and consent state vary per visit, and race conditions fail intermittently. An error in three of three loads is a bug; one in five may be a third party.
- Group by message, not by occurrence. Strip numbers and ids from messages and count distinct ones — fifty pages with the same error is one fix.
- Diff against yesterday. For monitoring, the useful signal is a message that wasn't there before a deploy, not the steady background.
- Minified names are normal.
t is not a functionon a site without public source maps is as specific as it gets from outside; the page and the timing are your clues.
Limits
What a load-time capture misses
- Errors behind interactions. A broken "Add to cart" throws when clicked. Capture it with a scripted flow — Playwright can click, type and assert — or with real-user monitoring on your own site.
- Errors behind a login. An anonymous visit sees the anonymous page.
- Other browsers. Headless Chrome finds Chrome's errors. Safari-only failures need WebKit, which Playwright can drive.
- Embedded frames. An ad or a video player in an iframe logs to its own console. Most capture setups only listen to the top page, which is usually what you want — but it means a broken embed can be invisible.
- Server errors. A 500 from an API shows up only if the page's code reacts to it.
With URLpipe
The console of any page, as JSON
URLpipe's JavaScript error checker and the /console endpoint run Method 2 for you. They load the page in real Chrome, record console.error, console.warn, uncaught exceptions and unhandled promise rejections, wait briefly after the network settles so late scripts can report, and return them as a JSON array of {type, text} — an empty array when the page is clean. It costs 1 credit a page.
To be precise about the boundaries: it records what the page's code logs or throws, not console.log, and not the messages Chrome itself writes about failed resource loads — check those with the rendered HTML and your own network tooling. It listens to the top page, not to embedded frames. And for errors that arrive on a timer, page_options.delay waits up to 10 more seconds; see page options.
curl -X POST https://urlpipe.dev/console \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/checkout", "sync": true, "page_options": {"delay": 3000}}'
# e.g. [{"type": "exception", "text": "Uncaught TypeError: Cannot read properties of undefined (reading 'price')"}]Run it on a schedule over your clients' key pages, store the results, and alert on new messages — that's a JavaScript error monitor for sites you don't control, in a cron job.
FAQ
Frequently asked questions
How do I see JavaScript errors on a website?
Can I find errors on a site without access to its code?
What's the difference between an error and an exception in the console?
Why do I see different errors each time I load the page?
Does a console capture catch failed network requests?
Try it yourself
Free tools for this
No signup — run these on a real page right now, then call the same endpoint from your code.
- Check any website for JavaScript errors
Paste a link and see the console errors, warnings and uncaught exceptions logged while the page loads in a real browser — no DevTools, no local setup.
Try it free - Get the rendered HTML of any URL
Paste a link and get the page's HTML after JavaScript has run and redirects have been followed — the DOM a real browser sees, not the empty shell curl returns.
Try it free
Put this into practice.
Each of the eight kinds of data URLpipe returns has a free, no-signup tool — try the ideas from this guide on a real page, then grab an API key to run them from your code. 1,000 credits a month, no card.