You've Never Actually Seen Your Own Site
Quick answer: you have opened your site thousands of times and not once as a stranger. Your browser is logged in, your cache is warm, your DNS is resolved, your TLS session is remembered, and you…
Quick answer: you have opened your site thousands of times and not once as a stranger. Your browser is logged in, your cache is warm, your DNS is resolved, your TLS session is remembered, and you click the three links you always click. A first-time visitor gets none of that, and the problems that only appear in their session are invisible from where you're sitting. Seeing your site the way they do takes a deliberately ignorant view: something that has never visited before and knows nothing about you.
This isn't a lecture about testing discipline. It's a structural problem. The developer who built a site is the single worst-positioned person to evaluate it, because every mechanism that makes the web fast for repeat visitors is also a mechanism that hides breakage from the person who visits most.
Your view is the unreliable one
Run through what's actually different about your browser session compared to someone arriving from a search result.
You're logged in. If your app has any authenticated state, you may go weeks without rendering the logged-out version. The marketing page, the empty state, the signup flow: all of it is code you ship and rarely look at.
Your cache is warm. Your fonts, your JS bundle, your hero image are all sitting on disk. Your first paint isn't a first paint. If you've got a service worker, it's worse: you may be looking at a version of the site you shipped two deploys ago and not know it.
Your DNS is resolved. Your resolver and your OS have your domain cached, often for hours. A record that's stale, misconfigured, or pointing at something you decommissioned can resolve perfectly for you and fail for someone whose resolver has to ask fresh.
Your browser remembers your TLS and your HSTS. Once a browser has seen a valid Strict-Transport-Security header, it upgrades every later request automatically. That means a missing HSTS header is invisible to you specifically because you've been there before. The visitor who hasn't gets one unprotected request over plain HTTP before anything upgrades.
You're often not even on production. Localhost and deploy previews frequently run without the response headers production sends. A Content-Security-Policy that breaks a third-party widget won't break it on your machine, because on your machine there is no CSP.
You know where to click. You don't use your own navigation. You type the URL of the page you're working on. The broken link in the footer has been broken for five months and you have never once had a reason to click it.
Each of these is individually reasonable. Together they add up to a viewing position that is systematically biased toward everything working.
Most of what breaks happens before your code runs
Here's the part that catches frontend developers off guard. When a stranger's browser goes to your site, a sequence of things happens before a single line of your JavaScript executes, and you have no visibility into any of it from the browser you're using.
The browser has to resolve your domain. Then it negotiates a TLS connection, which means checking your certificate is valid, trusted, and not expired, and agreeing on a cipher. Then it makes a request and reads the response headers, and those headers decide what your page is even allowed to do: whether scripts from other origins can run, whether the page can be framed by someone else, whether the connection gets forced to HTTPS, how much referrer information leaks.
Only after all that does your HTML get parsed and your app boot up.
Every step in that chain can be broken while your React code is flawless. A certificate expires on a schedule nobody set a reminder for. A cipher configuration goes stale. A Content-Security-Policy header was never set, so there's nothing stopping an injected script from doing whatever it wants in a visitor's browser. X-Frame-Options is missing, so your real site can be loaded invisibly inside someone else's page. None of that produces a console error in your tab. None of it fails a component test.
And it goes further out than the page. Your DNS records govern whether someone can send email pretending to be your domain, whether a certificate authority you've never heard of can issue a cert for you, and whether a subdomain you spun up for a demo two years ago still points at a service you no longer control.
That last one is worth sitting with. A dangling CNAME, a DNS record still pointing at a deprovisioned service, is a real takeover path, and it produces exactly zero symptoms until someone claims the other end.
What a stranger sees that you don't
Now flip to the things that are in your page but still hidden from you.
Cold-cache performance. Largest Contentful Paint, Cumulative Layout Shift, and Total Blocking Time all look dramatically better on a warm cache. Layout shift in particular is a first-load phenomenon: fonts swapping, images without dimensions pushing content down, an ad slot or embed appearing late. On your machine, cached, it barely moves. On a stranger's first visit, on a mid-range phone, it's the difference between a usable page and one that fights back.
The logged-out path. Every route a new visitor can reach, in the state they reach it. This is where missing meta descriptions, duplicate H1s, and absent canonical tags live, because those pages are the ones you view least and search engines view most.
Secrets in the bundle. An API key that got imported into client-side code is invisible in the rendered UI and perfectly readable in the shipped JavaScript. You don't read your own bundle. Anyone curious can.
Actual broken links. Not the nav you use. The footer, the old blog post, the pricing page link that pointed somewhere you renamed.
How to get an outside view
The fix is conceptually simple: you need a view that has no memory of you. There are a few ways to get one, with different amounts of effort.
The cheap manual version is a private window with DevTools open, cache disabled, throttled to a slow connection, logged out. That's genuinely useful and you should do it more often than you do. What it won't show you is anything above the page: your TLS configuration, your DNS records, your email authentication, your certificate expiry. A browser tab can't audit those, because a browser tab isn't asking those questions.
The systematic version is to have something scan the site from the outside, with no session, no cache, and no assumptions. That's the specific gap FlawPilot fills. You give it a URL and it looks at your site as a stranger would, across security, performance, infrastructure, and SEO: response headers, TLS version and cipher strength, certificate validity and expiry, DNS and email records, exposed ports, Core Web Vitals on a cold load, and the on-page SEO of the pages you never open. It takes about two minutes and doesn't need a login, which matters here, because requiring an account would defeat the entire point of an unprivileged view.
The output isn't the interesting part. The interesting part is that it's a list of things you could not have found from your own browser, no matter how carefully you looked.
What to do with the gap
Once you can see the outside view, most of what it surfaces is cheap to fix. Response headers are a configuration block, usually a handful of lines in your framework config or your CDN settings, and they're the highest ratio of safety to effort available to a frontend developer. Here's the general shape, as a starting point rather than a finished policy:
// Illustrative only. Tune these to your app, especially the CSP.
const securityHeaders = [
{ key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains' },
{ key: 'X-Frame-Options', value: 'SAMEORIGIN' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
{ key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
{ key: 'Content-Security-Policy', value: "default-src 'self'" },
];The CSP line is the one that needs real thought. A policy that's too strict breaks your analytics and your embeds, so it's worth rolling out in report-only mode first and reading what it would have blocked before you enforce it. The other five are close to safe defaults for most sites.
Certificate expiry and DNS records need a different habit, not a code change. These are the failures that arrive without a commit, so they need something watching on a schedule rather than a fix you ship once.
Frequently asked questions
Final Thoughts
The uncomfortable thing about this whole category of problem is that effort doesn't help. You can be careful, test thoroughly, review every PR, and still miss all of it, because the tools you're being careful with are all running inside the same privileged session.
What breaks the loop isn't more diligence. It's a second viewpoint that doesn't share your assumptions, hasn't been to your site before, and isn't invested in it working.
Look at your site from the outside once. The gap between what you thought you were shipping and what a stranger actually receives is usually smaller than a disaster and larger than nothing, and it's almost always made of things that take an afternoon to fix.
How FlawPilot helps
FlawPilot finds security and quality issues in your AI-built app and shows you how to fix them. It checks your deployed site across security, performance, infrastructure, and SEO, and scans your source code for vulnerabilities, hardcoded secrets, and vulnerable dependencies.
Every finding is prioritized and explained in plain English, with the actual fix: the configuration change, DNS record, security header, or code change needed. For supported findings, AI-powered guidance adds step-by-step instructions and suggested code fixes.
Connect your Git provider to scan your repository alongside your live site, so application findings, code vulnerabilities, secrets, and dependency issues all land in one place.
It fits your existing workflow too: a REST API for scores and findings, an embeddable security badge, and an MCP server so tools like Claude, Cursor, or ChatGPT can read your findings and help you work through them.
The boundaries are clear: the public website scan reads only publicly accessible signals, with no agent or credentials required, and source-code scanning is opt-in and read-only. Fixes are never applied or merged without your review.
Verify your AI-generated app is production-ready.
117 security checks in 60 seconds - free, no account needed.
Scan one page
Enter a URL - no account, no install.
Run a Site Health check
Requires a free accountCrawls every page we can reach and scores each one, so a slow template deep in the site stops hiding behind a healthy homepage.
Scan your source code
Requires a free accountConnect a Git provider to check for vulnerabilities, secrets, and risky dependencies.