How we caught 11 issues on our own homepage (and fixed 10)
Most SaaS landing pages do not run their own product. We figured we should — so the day before launch, we pointed Lintry at lintry.io and let it tell us how bad our own site really was. Eleven issues. We fixed ten in three hours. Here is exactly what came back, what we shipped, and the one issue we deliberately left for later.
The first scan
The premise was simple. We had been polishing the marketing site for weeks, telling ourselves it was production-ready. Then we ran one Lintry scan against the homepage and saw the truth.
Embarrassing? A little. Useful? Absolutely. This is exactly what we built Lintry to surface — the stuff you stop seeing when you have looked at the same page a hundred times.
The full list of issues
| Severity | Issue | Status |
|---|---|---|
| HIGH | Missing Content Security Policy (CSP) header | Fixed |
| MEDIUM | Missing X-Frame-Options header | Fixed |
| MEDIUM | Missing X-Content-Type-Options header | Fixed |
| MEDIUM | www and non-www both accessible without redirect | Fixed |
| MEDIUM | Low content volume (527 words on homepage) | Fixed |
| MEDIUM | Accessibility score 0/100 (mobile) — false positive | Fixed |
| MEDIUM | Accessibility score 0/100 (desktop) — false positive | Fixed |
| MEDIUM | No WAF or CDN detected | Deferred |
| LOW | Missing canonical tag | Fixed |
| LOW | Missing Referrer-Policy header | Fixed |
| LOW | Missing Permissions-Policy header | Fixed |
Fix one: security headers (the easy win)
Five of the eleven issues were missing security headers. Every modern browser respects these headers, and every modern site should set them. Most static-site frameworks make this trivial — we just had not done it yet.
Lintry's report told us which headers were missing and what the recommended values were. In our case, since lintry.io runs on Next.js + Vercel, the fix was a single next.config.js change:
async headers() {
return [{
source: '/:path*',
headers: [
{ key: 'Content-Security-Policy', value: '...' },
{ 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: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' },
],
}]
}Six headers, one config change, one deploy. That single PR resolved five issues at once. Score jumped from where it was to significantly higher on the next scan.
We wrote the full breakdown of how to set these up in a separate post — Adding security headers to a Next.js site in 5 minutes — if you want the copy-paste version.
Fix two: the www vs non-www duplicate
This was one of those issues every developer eventually deals with. Both www.lintry.io and lintry.io were serving the same content, with no redirect between them. Google sees this as duplicate content, which dilutes ranking signals and can split traffic between two equivalent URLs.
The fix on Vercel was a single redirects() entry in next.config.js:
async redirects() {
return [{
source: '/:path*',
has: [{ type: 'host', value: 'www.lintry.io' }],
destination: 'https://lintry.io/:path*',
permanent: true,
}]
}A 301 permanent redirect from www to the canonical version. Google treats this exactly the way you want: all link equity consolidated to one URL, no duplicate content penalty.
Fix three: canonical tag
Closely related to the www fix — Lintry flagged that we had no <link rel="canonical"> tag in our pages. This is a hint to search engines about which version of a URL to treat as authoritative. Without it, query parameters and trailing slashes can create perceived duplicate pages even within a single domain.
Next.js 13+ makes this one line in the metadata export of app/layout.js:
export const metadata = {
metadataBase: new URL('https://lintry.io'),
alternates: { canonical: '/' },
}Every page now gets a proper canonical tag automatically. Issue resolved on the next deploy.
Fix four: the content volume problem
Lintry flagged our homepage at 527 words. The recommended minimum for SEO is around 600 words. Pages with thin content tend to rank worse, even if the design is excellent — Google has a content-density signal baked into its ranking algorithm.
We could have stuffed in keywords. We did not. Instead, we added a real, useful "How Lintry works" section explaining the four-step process: enter URL, run real browser, 14+ checks in parallel, get a ranked report. Each step got a proper paragraph of explanation. Total added: about 250 words.
The trick is that the new content was actually useful to visitors. Word count is a proxy for content depth — gaming it with filler hurts you more than it helps. Solve the real problem and the metric follows.
Fix five: the accessibility false positive (a Lintry bug)
This one was on us — not the marketing site. Lintry's PageSpeed Insights integration was reporting accessibility scores of 0/100 when Google PSI had failed to complete the accessibility audit (timeout, throttling, or the URL not being reachable from Google's edge).
A real 0/100 accessibility score on a clean Next.js site is essentially impossible. So Lintry was generating two medium-severity issues based on bad data — every time a user scanned a site where PSI's accessibility category failed silently.
The fix was in performanceChecker.js:
// Treat scores below 5 as failed audits, not real low scores.
const FALSE_POSITIVE_THRESHOLD = 5
if (scores.accessibility != null &&
scores.accessibility >= FALSE_POSITIVE_THRESHOLD &&
scores.accessibility < 80) {
// ...generate issue
}We chose a threshold of 5. A legitimately bad accessibility score is almost never below 10 in practice. Returning null when PSI failed entirely, and ignoring sub-5 scores when present, eliminated the false positive for every Lintry user, not just us.
The one we did not fix: no WAF or CDN
Lintry flagged that lintry.io has no detectable Web Application Firewall or CDN. The recommendation: put Cloudflare in front. This would resolve the issue and add free DDoS protection.
We chose to defer it. Here is why:
- The site runs on Vercel's Edge Network, which technically provides CDN behavior — Lintry just does not detect it as such because we do not return Cloudflare-style headers
- Migrating DNS to Cloudflare requires nameserver changes and a 24-hour propagation window — risk we did not want one day before launch
- The issue is medium severity, not critical, and our actual attack surface is small (no logins on lintry.io itself, no forms submitting data)
We will migrate to Cloudflare 1-2 weeks after launch, once we have real traffic to protect and the freedom to deal with any DNS hiccups. Knowing about an issue and choosing when to fix it is not the same as ignoring it.
The final score
After three hours of fixes and a handful of deploys, we ran a final scan. One medium-severity issue remaining (the WAF one, by design). Estimated score around 90+.
More importantly, the audit itself was the kind of thing that would have taken hours of manual checking. Lintry told us in 60 seconds, ranked by severity, with specific fix recommendations. The same process that every Lintry customer runs on their own sites.
The lesson
Every site has issues. The only sites without flags are the ones nobody has scanned. The difference between a professional product and an unfinished one is not "perfect launch state" — it is knowing what is wrong and choosing what to ship anyway.
That is what running an audit gives you: not perfection, but informed shipping. You know what you fixed, you know what you deferred, and you know why.
"The audit itself was the kind of thing that would have taken hours of manual checking. Lintry told us in 60 seconds."
If you ship websites professionally and you have not audited the site you are reading this on, that is the next 60 seconds well spent.
See what is hiding on your homepage. Free forever plan, no credit card.
Start scanning free →