Technical Audit — northwind.app
Generated June 24, 2026 at 11:30 AM PDT · seed https://northwind.app/ · secrets redacted
Methodology & scope
Passive, unauthenticated review of the public website at https://northwind.app/ — seen the way a normal visitor's browser sees it. No logins, no private areas, and nothing was changed. This is an anonymized sample on fictional data.
Residual: Screenshots are not text-redacted. Secret-shaped strings are stripped from captured text (headers, HTML, scanner output) before analysis, but page screenshots are sent to the vision model as raw pixels. A secret rendered visibly on a page — for example an API key shown in an admin panel — is not removed and reaches the model. Treat captured screenshots as sensitive.
How to read this
This is a home inspection, not a report card. We surface everything we find and rank it by seriousness — but not every item is a must-fix, and clearing every flag is not the goal. Some findings (and the B/C grades that reflect them) are reasonable trade-offs for your stage: a deliberate business decision, something sensibly deferred until you need it, or a path that doesn't run in production. Chasing an A in every area — or zero findings — usually means over-engineering, or papering over a real choice. Work the serious items first; accept the trade-offs that fit where you are. A healthy result is no unaddressed serious issues — not straight A's.
Coverage summary
46 checks across 5 areas: 32 passed, 9 flagged, 5 not determined.
| Area | Passed | Flagged | Not determined |
|---|
| Turning visitors into customers | 0 | 1 | 1 |
| Being found | 10 | 2 | 2 |
| Speed & experience | 6 | 0 | 0 |
| Trust & safety | 14 | 5 | 0 |
| Growth & operations | 2 | 1 | 2 |
Verified clean
These checks ran and found no issues:
- Being found — Page has a title
- Being found — Meta description present
- Being found — Canonical URL set
- Being found — Structured data for search (Schema.org)
- Being found — +6 more verified clean
- Speed & experience — Page declares its language
- Speed & experience — Works well on phones (mobile viewport)
- Speed & experience — Clear heading structure
- Speed & experience — Links and buttons have descriptive labels
- Speed & experience — +2 more verified clean
- Trust & safety — Secure connection (HTTPS)
- Trust & safety — Modern encryption (TLS 1.3)
- Trust & safety — Certificate not expiring soon
- Trust & safety — Cookies set securely
- Trust & safety — +10 more verified clean
- Growth & operations — Privacy policy present
- Growth & operations — Behind a content-delivery and filtering service
Findings
SEO
Your page's words and links are only built after it loads in a browser
- Severity: high
- Confidence: high
- Business impact: New customers find you mainly through search. Because your page is assembled inside each visitor's browser, search engines often see an almost-empty page — so the wording that should rank for what you do, and the links to your other pages, are invisible to them.
- Detail: The served HTML body is an empty app shell; the headings, copy, and the internal link graph are injected by the page's script after load. A review of the raw page found no main heading, no body copy, and no in-page links — they appear only once the script has run.
- Fix: Deliver the home and main marketing pages with their text and links already in the page's source (pre-render or server-render them), so search engines and link-discovery tools see real content immediately.
- Evidence:
- https://northwind.app/ —
served page source
Your search-result description is longer than search engines will show
- Severity: low
- Confidence: high
- Business impact: The summary under your title in search results gets cut off, so the trailing part of your pitch never reaches the people deciding whether to click.
- Detail: The page's description is 167 characters; results typically show only the first ~155-160, truncating the closing call to action.
- Fix: Tighten the description to about 150 characters so it shows in full.
- Evidence:
- https://northwind.app/ —
page description
AI Readiness & Trust
AI answer assistants see a blank page where your selling points should be
- Severity: high
- Confidence: high
- Business impact: More and more people ask an AI assistant for a recommendation instead of searching. Those assistants read the plain page and don't run your page's code, so they can't see what makes you different — and describe you only generically, if at all.
- Detail: The plain page contains none of the visible product copy (it measured zero readable words before the page's code runs, versus ~700 after); the value proposition, use cases, and pricing all exist only after load.
- Fix: Deliver the marketing copy in the page's source so assistants that don't run page code can still read your value proposition, use cases, and pricing.
- Evidence:
- https://northwind.app/ —
plain page content
Your business description is already machine-readable — a real strength
- Severity: info
- Confidence: high
- Business impact: Even though the page body is hidden from AI crawlers, you do publish a clean, structured description of your business and product up front, so assistants can still identify you accurately. This is the main thing keeping you discoverable today.
- Detail: A well-formed structured-data block describes the organization and the product (category, platform, and a free-during-beta offer) and is readable without running any page code.
- Fix: Keep this in the page source, and add a frequently-asked-questions block so assistants have ready-made answers to quote.
- Evidence:
- https://northwind.app/ —
structured data block
Performance
Your site loads fast, with room to spare
- Severity: info
- Confidence: high
- Business impact: Fast pages keep visitors engaged and help your search ranking. Yours load well inside the thresholds that matter, so speed is working for you, not against you.
- Detail: On the home page the main content appears in about 0.4s on desktop and 0.5s on mobile — roughly five times faster than the 'good' threshold — with negligible layout shift, served from a content-delivery network.
- Fix: No action needed. Keep the lean build as you add pages.
- Evidence:
- https://northwind.app/ —
home page load timings
On phones, the page keeps working in the background longer after it appears
- Severity: low
- Confidence: high
- Business impact: The page looks ready quickly, but on slower phones it keeps doing work behind the scenes for a while after — the part of the experience that can feel sluggish to tap. Worth watching as the app grows.
- Detail: Total mobile load is several times the desktop figure, driven by running the page's script and a third-party measurement tag on a slower phone processor, well after the main content has painted.
- Fix: Split the page's code so less runs up front, and load the measurement tag after the page is interactive.
- Evidence:
- https://northwind.app/ —
mobile load timings
Accessibility
Your before/after demo tells people apart using color only
- Severity: medium
- Confidence: high
- Business impact: The correction examples are the heart of your pitch — they show the tool fixing real text. They mark the 'before' and 'after' with red and green only, so roughly one in twelve men (who have red-green color blindness), plus anyone on a phone in bright sun, can't tell which side is the fix — turning your strongest proof into confusion.
- Detail: The before/after pairs are distinguished by text color alone, with no second cue such as a strike-through, an arrow, or a label a screen reader can announce.
- Fix: Add a non-color cue to each pair — strike through the original, mark the fix with an arrow or checkmark, and add a label assistive tools can read.
- Evidence:
- https://northwind.app/ —
before/after correction examples
Some of your lightest gray text may be hard to read
- Severity: low
- Confidence: low
- Business impact: Hard-to-read low-contrast text is the most common accessibility complaint, and it disproportionately affects older visitors and anyone on a phone outdoors — a meaningful slice of a broad consumer audience.
- Detail: Contrast couldn't be measured automatically this run. The muted off-white palette uses several light-gray secondary labels that are the pairing most likely to fall under the readability threshold.
- Fix: Check the light-gray-on-off-white text with a contrast checker and darken any that fall short.
- Evidence:
- https://northwind.app/ —
muted secondary labels
The accessibility basics are strong across the board
- Severity: info
- Confidence: high
- Business impact: The things that most often shut out screen-reader and keyboard users are all handled, so the page is broadly usable today and not exposed to the common accessibility-complaint patterns.
- Detail: Every image carries descriptive text, every interactive control is labelled (including icon-only ones), the page declares its language, the heading order is clean with a single top heading, and a 'skip to content' link is the first focusable element.
- Fix: No action needed — keep these as the page grows.
- Evidence:
- https://northwind.app/ —
rendered page
Security
A private access key is sitting in your page's public code
- Severity: critical
- Confidence: high
- CWE: CWE-798
- Business impact: A secret key that's meant to stay on your servers was bundled into the code every visitor's browser downloads, so anyone can copy it. Whoever does can run up charges on your account or reach data it unlocks. This is the single most urgent thing to fix — today.
- Detail: A secret-shaped credential was found embedded in the page's published script bundle, which is served publicly to every visitor. The value has been redacted from this report.
- Fix: Treat the key as compromised: revoke and rotate it immediately, then move it to a server-side setting that never ships to the browser.
- Cost impact: $40,000
- Evidence:
- https://northwind.app/static/js/app.js —
published script bundle
Anyone can send email pretending to be your business
- Severity: high
- Confidence: high
- CWE: CWE-290
- Business impact: Your domain publishes none of the three standard protections that prove an email really came from you. For a paid product that emails sign-up and billing notices, that invites convincing scams aimed at your customers and pushes your own real emails into spam. It's the highest-value, lowest-effort fix here.
- Detail: None of the three email-authentication records (sender policy, message signing, and the handling rule for fakes) are published for the domain, so receiving mail servers can't verify any message claiming to be from you.
- Fix: Publish all three email-authentication records and turn on message signing at your email provider, starting in a monitor-only mode and tightening to reject.
- Evidence:
- northwind.app —
domain email records
Visitor tracking starts before anyone agrees to it
- Severity: medium
- Confidence: high
- Business impact: Your analytics begins watching visitors the moment the page opens, with no consent prompt. For the European and UK visitors a tool like this attracts, that can break privacy law and expose you to complaints and fines.
- Detail: Tracking scripts load on page open with no consent banner present; two tracking requests fire before any choice is offered.
- Fix: Add a consent prompt and hold all non-essential tracking until visitors agree, defaulting to off in regions that require it.
- Evidence:
- https://northwind.app/ —
page header
A page-protection rule is set the weaker of the two ways
- Severity: low
- Confidence: high
- CWE: CWE-693
- Business impact: You do have a strong rule limiting which code can run on your pages — a real plus — but it's delivered in the weaker form, which browsers only partly enforce and which can't report attempted abuse.
- Detail: The content-security rule is delivered inside the page markup rather than as a response header, so several of its directives are ignored and violations can't be collected.
- Fix: Serve the same rule as a response header at your content-delivery edge.
- Evidence:
- https://northwind.app/ —
response headers
Your pages quietly announce what they're hosted on
- Severity: info
- Confidence: high
- CWE: CWE-200
- Business impact: A response label names your hosting platform. There's no direct risk, but it gives someone probing for weaknesses a small head start.
- Detail: A response header discloses the hosting platform. No version numbers or error details are exposed beyond the platform name.
- Fix: Optionally strip the hosting label at your content-delivery edge.
- Evidence:
- https://northwind.app/ —
response headers
Content & Presentation
Nothing on the page shows that other people trust you
- Severity: medium
- Confidence: high
- Business impact: You're asking first-time visitors to install a tool that reads what they type, yet the page shows no reviews, ratings, install counts, or recognizable names. With nothing to vouch for you, more visitors hesitate and leave at the exact moment they're deciding whether to sign up.
- Detail: The visible page contains no testimonials, star ratings, install or user counts, press mentions, or trust logos — only first-party privacy reassurances.
- Fix: Add concrete proof near the sign-up button: a store rating and install count, two or three short attributed quotes, or a 'trusted by N writers' figure. Even a beta-signup count helps.
- Evidence:
- https://northwind.app/ —
landing page
Your pricing promises a discount but never says from what
- Severity: low
- Confidence: low
- Business impact: Saying beta users get 'a discount' with no reference price means visitors can't tell what they're locking in by signing up now, which softens the urgency the offer is meant to create.
- Detail: The pricing section lists a single free beta tier and promises a future discount, with no indicative future price or 'normally $X' anchor.
- Fix: Once paid pricing is decided, add an indicative anchor (for example 'will be $X/mo — beta users lock in Y% off') while keeping the honest framing.
- Evidence:
- https://northwind.app/#pricing —
pricing section
Tech & Analytics
Your analytics runs without asking permission
- Severity: medium
- Confidence: high
- Business impact: Your visitor analytics starts setting tracking cookies the moment the page loads. For the European and UK visitors a writing tool attracts, that needs consent first — and without it your own measurement will also degrade as the rules tighten.
- Detail: The analytics tag loads on page open with no preceding consent step and no consent-management tool present; a privacy review confirmed tracking fires before any choice is offered.
- Fix: Default analytics to off until a visitor agrees, add a lightweight region-aware consent prompt, and turn tracking on only when they accept.
- Evidence:
- https://northwind.app/ —
page header
You use only the outside services you actually need
- Severity: info
- Confidence: high
- Business impact: Every external service on the page maps to a real job — sign-in, payments, and measurement — with no ad trackers, social pixels, or session-recording tools bolted on. That keeps both privacy risk and page weight low.
- Detail: The distinct third parties are a sign-in provider, a payments provider, a measurement tag, and your own service; no advertising, social, or session-replay trackers were detected, and no exposed keys were found among the loaded scripts.
- Fix: No action needed. Keep new vendors behind the same disciplined gate.
- Evidence:
- https://northwind.app/ —
loaded third-party scripts
Operations Map & Automation/AI
northwind.app runs on a lean managed stack, so the heavy lifting — sign-in, hosting, payments — is already automated. But three concrete gaps still create manual load: account emails that may not arrive, no automatic alarm when the writing service is down, and billing for paid plans that isn't set up to run itself.
Site map
graph TD
home["/"]
download["/download"]
pricing["/#pricing"]
faq["/faq"]
contact["/contact"]
home --> download
home --> pricing
home --> faq
home --> contact
Customer journey
graph LR
visit[Visit home] --> install[Install extension]
install --> signin[Sign in]
signin --> write[Use the writing tool]
write --> upgrade[Upgrade to paid]
Business process (inferred)
graph TD
signup[Sign-up] --> email[Automatic account email]
email --> active[Active user]
active --> support[Support inbox]
Automation & AI opportunities
Your automatic account emails may not reach customers
- Severity: high
- Confidence: high
- Business impact: Sign-up confirmations and password resets are sent automatically from your domain — but because the domain has no email-authentication protection, those messages are easily faked and routinely land in spam. Every one that goes missing becomes a support ticket at the worst possible moment: a new customer trying to get started.
- Detail: The sign-in service sends verification and reset email from the domain, which publishes no sender policy, message signing, or anti-fraud rule, so the messages can't be authenticated by receiving servers.
- Fix: Publish the three email-authentication records and route account email through an authenticated sender so messages are verified and retried automatically.
- Evidence:
- northwind.app —
domain email records
Nothing tells you automatically when the writing service is down
- Severity: medium
- Confidence: high
- Business impact: The core writing feature has no health check and no status page, so an outage is discovered the hard way — through a wave of 'is it broken?' emails — instead of an automatic alert. That means slower fixes and more support load during exactly the moments that hurt most.
- Detail: No health endpoint or public status page was detected for the writing service, and no automated uptime monitoring or on-call signal is visible from the public surface.
- Fix: Add a simple health check and automatic alerting that pages you on errors or latency, and stand up a public status page.
- Evidence:
- https://api.northwind.app/ —
writing service surface
Billing for paid plans isn't set up to run on its own yet
- Severity: medium
- Confidence: medium
- Business impact: Your pricing promises beta users a discount when paid plans launch, but granting those discounts, chasing failed payments, and handling cancellations by hand would turn launch day into a recurring manual chore instead of a one-time setup.
- Detail: Checkout is integrated, but no recurring-billing lifecycle (plans, discount codes, self-serve plan changes, failed-payment retries) is wired up ahead of the beta-to-paid switch.
- Fix: Model the plans in your payment provider's billing tools, issue a coupon for the beta discount, enable a self-serve customer portal, and turn on automatic retries for failed cards.
- Evidence:
- https://northwind.app/#pricing —
pricing section
Operational signals
- TLS certificate: 120 days until expiry.
- HSTS: enabled.
- HTTPS redirect: HTTP is upgraded to HTTPS.
- Health/status endpoints: none detected.
- CDN/WAF: content-delivery-network.
- Rate limiting: no signals observed.
Questions for your team
- What uptime do you commit to, and how do you measure it?
- How often are backups taken, and when did you last test a restore?
- Who is on call, and what is the escalation path after hours?
- What is your plan when the writing service goes down?
Performance metrics
https://northwind.app/ (source: cdp)
| Metric | Value |
|---|
| cls | 0.0235 |
| fcp_ms | 216 |
| lcp_ms | 412 |
| load_ms | 268 |
| ttfb_ms | 122.9 |
https://northwind.app/ (mobile) (source: cdp)
| Metric | Value |
|---|
| cls | 0 |
| fcp_ms | 336 |
| lcp_ms | 512 |
| load_ms | 1330.5 |
| ttfb_ms | 124.6 |
Scanner appendix
Values shown as [REDACTED:…] were secret-shaped and removed before analysis.
seo
| Key | Value |
|---|
| canonical | https://northwind.app/ |
| h1_count | 0 |
| hreflang | [] |
| images | {'total': 0, 'with_alt': 0, 'missing_alt': 0, 'alt_coverage': 1.0} |
| json_ld | {'count': 1, 'types': []} |
| meta_description | {'text': 'Write with confidence — grammar correction, tone adjustments, and clear rewriting. Available as a browser extension and Google Docs add-on.', 'length': 167} |
| open_graph | {'og:title': 'Northwind — Grammar & Writing Assistant', 'og:image': 'https://northwind.app/og-image.png'} |
| site_files | {'robots_txt_present': True, 'sitemap_present': True, 'sitemap_urls': ['https://northwind.app/sitemap.xml']} |
| title | {'text': 'Northwind — Grammar & Writing Assistant for Chrome & Google Docs', 'length': 56} |
| twitter | {'twitter:card': 'summary_large_image'} |
ai_readiness
| Key | Value |
|---|
| ai_crawlers | {'robots_present': True, 'blanket_disallow_all': False, 'blocked': [], 'allowed': ['answer-engines']} |
| ai_metadata_leak | {'present': False, 'markers': []} |
| available | true |
| content_extractability | {'raw_text_words': 0, 'rendered_text_words': 699, 'ratio': 0.0, 'js_dependent': True, 'threshold': 0.3} |
| llms_txt | {'present': False, 'full_present': False} |
| overt_ai_marketing | {'count': 0, 'phrases': [], 'prominent': False} |
| structured_data | {'present': True, 'count': 1, 'types': ['Organization', 'WebApplication'], 'aeo_relevant_types': ['Organization', 'WebApplication', 'Offer']} |
| url | https://northwind.app/ |
a11y
| Key | Value |
|---|
| available | true |
| form_controls | {'total': 0, 'unlabeled': 0, 'unlabeled_samples': []} |
| headings | {'h1_count': 1, 'order': [1, 2, 2, 2, 3, 3], 'single_h1': True, 'skipped_levels': [], 'well_structured': True} |
| html_lang | {'present': True, 'value': 'en'} |
| images | {'total': 10, 'with_alt': 10, 'missing_alt': 0, 'alt_coverage': 1.0, 'missing_samples': []} |
| interactive_names | {'total': 27, 'unnamed': 0, 'unnamed_samples': []} |
| source | rendered |
| title | {'present': True, 'text': 'Northwind — Grammar & Writing Assistant'} |
| url | https://northwind.app/ |
| viewport | {'present': True, 'content': 'width=device-width, initial-scale=1'} |
headers
| Key | Value |
|---|
| leakage | [{'header': 'server', 'value': '[REDACTED:server-banner]'}] |
| meta_csp_present | true |
| missing | ['content-security-policy'] |
| security_headers | {'content-security-policy': {'present': False, 'value': None}, 'strict-transport-security': {'present': True, 'value': 'max-age=63072000; includeSubDomains; preload'}, 'x-frame-options': {'present': True, 'value': 'SAMEORIGIN'}, 'x-content-type-options': {'present': True, 'value': 'nosniff', 'nosniff': True}, 'referrer-policy': {'present': True, 'value': 'strict-origin-when-cross-origin'}, 'permissions-policy': {'present': True, 'value': 'geolocation=()'}} |
dns_email
| Key | Value |
|---|
| dkim | {'present': False} |
| dmarc | {'present': False, 'policy': None} |
| domain | northwind.app |
| spf | {'present': False, 'records': []} |
| subdomain_takeover | {'findings': []} |
cookies_tls
| Key | Value |
|---|
| insecure_cookies | [] |
| mixed_content | [] |
| tls | {'protocol': 'TLSv1.3', 'not_after': 'Oct 20 23:59:59 2026 GMT', 'days_until_expiry': 120, 'expired': False, 'deprecated_protocol': False} |
js_cve
| Key | Value |
|---|
| libraries_scanned | 3 |
| vulnerabilities | [] |
privacy
| Key | Value |
|---|
| cookie_consent_present | false |
| findings | 1 items (see bundle/scanners/privacy.json) |
| privacy_policy_present | true |
exposed_secrets
| Key | Value |
|---|
| count | 1 |
| exposed_secrets | [{'kind': 'service_key', 'value': '[REDACTED:service-key]', 'url': 'https://northwind.app/static/js/app.js'}] |
| scripts_scanned | 1 |
ops_signals
| Key | Value |
|---|
| cdn_waf | {'vendors': ['content-delivery-network'], 'evidence': {'cache-status': '[present]'}} |
| health_endpoints | {'status_page': False, 'health_endpoint': False, 'found_paths': []} |
| hsts | {'present': True, 'max_age': 63072000, 'include_subdomains': True, 'preload': True} |
| questions | ['What uptime do you commit to, and how do you measure it?', 'How often are backups taken, and when did you last test a restore?', 'Who is on call, and what is the escalation path after hours?', 'What is your plan when the writing service goes down?'] |
| rate_limiting | {'retry_after': None, 'rate_limit_headers': []} |
| redirect | {'hops': 1, 'https_upgrade': True, 'final_is_https': True, 'final_status': 200, 'chain': ['http://northwind.app/']} |
| tls | {'protocol': 'TLSv1.3', 'not_after': 'Oct 20 23:59:59 2026 GMT', 'days_until_expiry': 120, 'expired': False, 'expiring_soon': False, 'deprecated_protocol': False} |
Ticket-ready backlog
- ☐ [P0] Revoke the exposed service key and move it server-side — Security · impact: critical · effort: low. The key ships to every visitor; treat it as compromised and rotate now.
- ☐ [P0] Publish email-authentication records — Security · impact: high · effort: low. No sender policy, signing, or anti-fraud rule is published for the domain.
- ☐ [P1] Pre-render the marketing pages so their content is in the source — SEO · impact: high · effort: medium. Search and AI crawlers see an empty shell until the page's code runs.
- ☐ [P1] Add social proof near the primary call to action — Content & Presentation · impact: medium · effort: low. The page offers no third-party credibility signals.
- ☐ [P1] Gate analytics and tracking behind consent — Tech & Analytics · impact: medium · effort: low. Tracking fires before any consent step for EU/UK visitors.
- ☐ [P2] Add health checks, alerting, and a public status page — Operations Map & Automation/AI · impact: medium · effort: medium. An outage is currently discovered through support email.
Tool coverage
10 of 10 scanners produced results.
Ran: a11y, ai_readiness, cookies_tls, dns_email, exposed_secrets, headers, js_cve, ops_signals, privacy, seo.
Limitations & coverage
These dimensions did not complete a full analysis:
- Market & Competitive Research:
skipped_disabled (disabled for this run) — Skipped: market and competitive research was turned off for this run. It needs a web-research backend; re-running with it enabled covers competitors and positioning. - Business Growth:
skipped_disabled (disabled for this run) — Skipped: the growth-experiments review was turned off for this run. Re-running with it enabled looks at the sign-up funnel and conversion levers in depth.