AEO scoring tools — including our own — can carry a systematic language bias that makes non-English content appear weaker than it actually is. We discovered this when running AEOCrawler against a Swedish SaaS website: every page scored 0 on DirectAnswer and 0 on QueryCoverage, despite containing well-structured, direct-answer content. The root cause was that all pattern-matching expressions in these algorithms used English-only verbs and phrases. Swedish pages could never match patterns like is|are|provides|offers, no matter how perfectly the content was written. After adding multilingual pattern support, Unicode-aware matching, and fixing the content, infrastructure, server, and data-format issues we uncovered along the way, the site's average AEO score rose from 38.9 to 65.9 — a 69% improvement over five optimization rounds — with DirectAnswer scores jumping from 0 to an average of 84 and StructuredData from 30 to 100 across all 9 pages analyzed.
This case study documents the full investigation across five rounds of optimization: what we found, why it matters beyond Swedish, what we changed in AEOCrawler, and how each round revealed a different category of invisible scoring problem.
The Starting Point: 38.9 Average on a Swedish SaaS Site
The site under analysis was IntelInvoice, a Swedish invoicing system for small businesses. We ran AEOCrawler's full 9-algorithm scoring framework across 9 landing pages. The results looked plausible at first glance — 38.9 average is close to the median we found in our 500-page study — but the dimension-level breakdown revealed a pattern that should have been immediately suspicious:
| Page | AEO Score | DirectAnswer | QueryCoverage | ContentFreshness |
|---|---|---|---|---|
| /fortnox-alternativ | 50.1 | 0 | 0 | 100 |
| /pricing | 49.5 | 0 | 5 | 100 |
| /svensk-fakturering | 47.3 | 0 | 0 | 85 |
| /tidrapportering-fakturering | 45.3 | 0 | 0 | 85 |
| /visma-alternativ | 43.3 | 0 | 0 | 100 |
| / (homepage) | 42.7 | 0 | 0 | 100 |
| /integrationer/ | 35.3 | 0 | 0 | 100 |
| /fakturering-konsult | 18.2 | 0 | 0 | 50 |
| /fakturering-hantverkare | 18.2 | 0 | 0 | 50 |
| Average | 38.9 | 0 | 0.6 | 85 |
DirectAnswer = 0 on every single page. Not low — zero. And QueryCoverage was effectively zero as well. That is not a content quality problem. That is a measurement problem.
Round 1: Infrastructure — Pages Behind a Login Wall
Before investigating the scoring anomaly, we found a separate issue: two pages (/fakturering-konsult and /fakturering-hantverkare) scored 18.2 because they were returning HTTP 307 redirects to the login page. The crawler was analyzing 12 words of login form text instead of the actual content.
The cause was a missing entry in the Next.js middleware's PUBLIC_PATHS list. These two industry-specific landing pages had never been added as public routes.
After adding the pages to PUBLIC_PATHS and rebuilding with full Next.js page components and JSON-LD structured data, those two pages jumped from 18.2 to ~49 — proving the content was solid once the crawler could actually reach it.
But DirectAnswer remained 0 across all 9 pages. The infrastructure fix did not explain the scoring failure.
The Investigation: Why DirectAnswer Scored Zero on Valid Content
The site's homepage contained this text in its first paragraph:
"IntelInvoice är ett AI-drivet faktureringssystem för svenska företag."
In English, that translates to: "IntelInvoice is an AI-powered invoicing system for Swedish businesses." This is a textbook definition pattern — Subject + copula verb + description — exactly the structure that DirectAnswer is designed to detect and reward.
We opened the DirectAnswer algorithm source code and found the answer immediately.
Pattern 1: Definition Detection (35 points)
The algorithm uses a regex to detect definition patterns in the first 200 words of page content:
/\b[\w][\w\s\-\']{0,120}\b\s+(is|are|allows|enables|provides|
refers to|means|called|offers|delivers|helps)\s+/i
Every verb is English. The Swedish copula verb är (equivalent of is) is not in the pattern. Neither are erbjuder (offers), ger (provides), hjälper (helps), or any other Swedish verb.
Pattern 2: Explicit Answers (25 points)
/\b(Yes|No|The answer|The short answer|In short|
Simply put|You can|To [a-z]+,)\s+/i
English answer starters only. Swedish equivalents — Ja, Nej, Svaret är, Kort sagt, Du kan — do not match.
Pattern 3: Step-by-Step Content (15 points)
/\b(first|step|begin|start|follow these|to get started|
getting started|here's how|in this guide|learn how)\b/i
English instructional markers only. Först (first), steg (step), börja (begin), kom igång (get started) — none of them match.
The Systematic Ceiling
With patterns 1, 2, and 4 requiring English verbs and phrases, Swedish pages could only score on pattern 3 (title-word matching, max ~5 points each) and pattern 5 (code references, 10 points). The maximum achievable DirectAnswer score for any Swedish page was approximately 25 out of 100 — and most pages would score far less.
Since DirectAnswer carries a 20% weight in the overall AEO score, this created a systematic ceiling of approximately 15–20 points that Swedish-language content could never overcome, regardless of how well-structured it was.
The Same Bias in QueryCoverage
The investigation revealed identical patterns in the QueryCoverage algorithm:
Question header detection:
/^(what|how|why|when|where|who|which|can|does|is|are|should|will)\b/i
Swedish question words — vad, hur, varför, när, var, vem, vilken, kan, gör — were not included.
FAQ section detection:
/\b(FAQ|frequently asked|common questions|questions and answers)\b/i
The Swedish equivalents vanliga frågor and frågor och svar did not match.
Intent-type matching:
'what' => '/\b(what is|what are|definition|meaning|refers to)\b/i',
'how' => '/\b(how to|how do|step|guide|tutorial|instructions)\b/i',
Again — exclusively English.
A page with the heading "Hur fungerar IntelInvoice?" (How does IntelInvoice work?) matched zero intent types. A page with "Vanliga frågor" (Frequently asked questions) as a heading triggered no FAQ detection.
What This Means Beyond Swedish
This is not a Swedish-specific problem. Any language that does not share verb forms with English — which is the majority of the world's languages — would be affected by the same pattern.
Consider these examples:
| Language | Definition verb | Matches English is? |
|---|---|---|
| Swedish | är | No |
| German | ist | No |
| French | est | No |
| Spanish | es | No |
| Dutch | is | Yes (coincidence) |
| Portuguese | é | No |
| Italian | è | No |
| Finnish | on | No |
| Polish | jest | No |
| Japanese | です (desu) | No |
For 9 out of 10 languages in that table, the definition pattern would fail entirely. The Dutch is happens to match the English pattern by coincidence — not by design.
The broader implication: any AEO scoring tool that relies on English-language regex patterns will systematically underreport content quality for non-English websites. The scores will look plausible — 38.9 is not an obviously broken number — but they will be systematically incorrect. And the users will interpret low scores as "my content needs improvement" rather than "the tool cannot read my language."
The Fix: AEOCrawler v1.9.1
We updated both algorithms to support multilingual pattern matching. Here is what changed.
DirectAnswer — 4 Pattern Blocks Updated
Pattern 1 — Definition verbs (+10 Swedish verbs):
Added: är|erbjuder|ger|hjälper|möjliggör|tillåter|innebär|
kallas|levererar|tillhandahåller
Pattern 2 — Explicit answers (+7 Swedish phrases):
Added: Ja|Nej|Svaret är|Kort sagt|Du kan|Enkelt uttryckt|
Det korta svaret
Pattern 3 — Title-word filters (+11 Swedish function words):
Added: och|för|med|från|den|det|att|vad|hur|som|till
Pattern 4 — Step-by-step markers (+9 Swedish instructional words):
Added: först|steg|börja|starta|följ dessa|kom igång|
så här|lär dig|så gör du
QueryCoverage — 5 Pattern Blocks Updated
- Question headers: +13 Swedish question words
- FAQ detection: +2 Swedish FAQ phrases
- Intent types: +20 Swedish intent terms across 6 categories
- Answer types: Swedish answer markers for definitions, examples, steps
Unicode-Aware Matching
All updated patterns switched from the /i regex flag to /iu (Unicode + case-insensitive) and replaced \w (which does not match å, ä, ö) with \p{L} (which matches any Unicode letter). This is not optional — without Unicode-aware matching, even the added Swedish words would fail to match correctly at word boundaries.
Results After the Algorithm Fix (Round 3)
We re-analyzed all 9 pages after deploying the algorithm updates:
| Page | Before | After | Change |
|---|---|---|---|
| /fortnox-alternativ | 50.1 | 62.3 | +12.2 |
| /visma-alternativ | 43.3 | 60.8 | +17.5 |
| /fakturering-konsult | 18.2 | 59.8 | +41.6 |
| /svensk-fakturering | 47.3 | 57.4 | +10.1 |
| /tidrapportering-fakturering | 45.3 | 56.4 | +11.1 |
| /fakturering-hantverkare | 18.2 | 56.0 | +37.8 |
| / (homepage) | 42.7 | 53.0 | +10.3 |
| /pricing | 49.5 | 52.2 | +2.7 |
| /integrationer/ | 35.3 | 43.2 | +7.9 |
| Average | 38.9 | 55.7 | +16.8 |
Every page went from DirectAnswer 0 to a positive score. The content had been there all along — the measurement tool simply could not see it. But two pages still lagged behind: the homepage (53.0) and the integrations page (43.2).
Round 4: The Server Layer — Nginx Overrides Hiding New Content
With the algorithm fixed, we focused on the two underperforming pages. We had added a FAQ section and FAQPage JSON-LD to the homepage. We had rebuilt the integrations page as a full Next.js page with 6 integration cards, a step-by-step workflow section, and 6 FAQ items. We deployed. We ran the scan.
Nothing changed.
The homepage still showed no FAQ. The integrations page still returned the old static HTML. We checked the Nginx configuration and discovered a third class of problem:
# Root landing page — static HTML
location = / {
root /var/www/intelinvoice;
try_files /index.html =404;
}
# Integration pages
location /integrationer/ {
root /var/www/intelinvoice;
index index.html;
}
Nginx was intercepting requests to / and /integrationer/ and serving old static HTML files before the request ever reached the Next.js application. We could build the most content-rich Next.js page imaginable — if Nginx serves a different file first, it does not matter.
This is an insidious failure mode because it is invisible in local development. Locally, Next.js serves everything. The Nginx overrides only exist on the production server.
After removing the static HTML overrides and letting all marketing routes proxy to Next.js:
| Page | Round 3 | Round 4 | Change |
|---|---|---|---|
| / (homepage) | 53.0 | 59.0 | +6.0 |
| /integrationer/ | 43.2 | 54.5 | +11.3 |
Round 5: The Data Format — JSON-LD @graph Parsing
With the server layer fixed, we turned our attention to the remaining weak dimension: StructuredData. Every page had proper JSON-LD with Article, FAQPage, and BreadcrumbList schemas — verified by inspecting the raw HTML — yet the StructuredData algorithm scored them at 30 out of 100. The recommendation engine reported "Schema incomplete ( found)" with an empty type list, and suggested adding Article and FAQPage schemas that were already present.
The issue was in the StructuredData algorithm itself. It parsed JSON-LD blocks and checked $schema['@type'] directly on the decoded object. But all of these pages used the @graph format — the standard way to include multiple schema types in a single JSON-LD block:
{
"@context": "https://schema.org",
"@graph": [
{ "@type": "Article", "headline": "..." },
{ "@type": "FAQPage", "mainEntity": [...] },
{ "@type": "BreadcrumbList", "itemListElement": [...] }
]
}
The root object has no @type — the types are nested inside the @graph array. The algorithm found the JSON-LD block (30 points for presence) but never traversed into @graph to find the actual schema types. It could not see Article, FAQPage, or BreadcrumbList — all three were invisible.
A second issue compounded the problem: the recognized types list included FAQ but not FAQPage. Even if the algorithm had found the type, it would not have matched.
We fixed both issues in AEOCrawler v1.9.2:
- @graph traversal — When a JSON-LD block contains
@graph, iterate through all items in the array and evaluate each one individually - Expanded type recognition — Added
FAQPage,BreadcrumbList,WebSite, andSoftwareApplicationto the recognized types list with appropriate required-property definitions
The impact was immediate and universal:
| Page | SD Before | SD After | Change |
|---|---|---|---|
| / (homepage) | 50 | 100 | +50 |
| /fortnox-alternativ | 30 | 100 | +70 |
| /visma-alternativ | 30 | 100 | +70 |
| /svensk-fakturering | 30 | 100 | +70 |
| /integrationer | 30 | 100 | +70 |
| /fakturering-konsult | 30 | 100 | +70 |
| /fakturering-hantverkare | 30 | 100 | +70 |
| /tidrapportering-fakturering | 30 | 100 | +70 |
| /pricing | 30 | 100 | +70 |
This was the same class of problem as the language bias: a tooling error producing plausible scores. SD=30 looked like "the page has some structured data but it's incomplete." In reality, the structured data was complete — the tool could not read the format.
Final Results: Five Rounds of Optimization
| Page | Original | Round 2 | Round 3 | Round 4 | Round 5 | Total Change |
|---|---|---|---|---|---|---|
| /fortnox-alternativ | 50.1 | 51.2 | 62.3 | 62.3 | 70.7 | +20.6 |
| /visma-alternativ | 43.3 | 46.3 | 60.8 | 60.0 | 68.4 | +25.1 |
| /fakturering-konsult | 18.2 | 49.3 | 59.8 | 59.8 | 68.2 | +50.0 |
| / (homepage) | 42.7 | 47.0 | 53.0 | 59.0 | 67.4 | +24.7 |
| /svensk-fakturering | 47.3 | 47.3 | 57.4 | 57.4 | 65.8 | +18.5 |
| /tidrapportering-fakturering | 45.3 | 47.6 | 56.4 | 56.4 | 64.8 | +19.5 |
| /fakturering-hantverkare | 18.2 | 49.5 | 56.0 | 56.0 | 64.4 | +46.2 |
| /integrationer | 35.3 | 35.3 | 43.2 | 54.5 | 62.9 | +27.6 |
| /pricing | 49.5 | 36.9 | 52.2 | 52.2 | 60.6 | +11.1 |
| Average | 38.9 | 45.6 | 55.7 | 57.5 | 65.9 | +27.0 |
Two dimension transformations stand out across the five rounds:
DirectAnswer: 0 → 84 average (Rounds 2–3, algorithm fix)
| Page | DA Before | DA After |
|---|---|---|
| /fortnox-alternativ | 0 | 100 |
| /visma-alternativ | 0 | 95 |
| /tidrapportering-fakturering | 0 | 90 |
| / (homepage) | 0 | 85 |
| /svensk-fakturering | 0 | 85 |
| /fakturering-konsult | 0 | 80 |
| /pricing | 0 | 75 |
| /integrationer | 0 | 75 |
| /fakturering-hantverkare | 0 | 70 |
| Average | 0 | 84 |
StructuredData: 30 → 100 on all pages (Round 5, @graph parsing fix)
All 9 pages now score above 60. All 9 pages have maximum StructuredData scores. The weakest page went from 18.2 to 60.6 — a 233% improvement.
Five Types of AEO Problems
This case study illustrates that AEO score issues fall into five distinct categories, and the correct response is different for each:
| Type | What It Is | Example | Fix |
|---|---|---|---|
| Infrastructure | Content is not reachable | Pages behind login, broken redirects, noindex | Fix the access — no content changes needed |
| Content | Content is reachable but poorly structured | Missing FAQ section, no JSON-LD, no direct answer | Restructure and add missing elements |
| Tooling (language) | Content is fine, measurement is wrong | English-only regex, missing Unicode support | Fix the tool — the content was never the problem |
| Server layer | New content deployed but not served | Nginx static overrides, CDN cache, reverse proxy bypasses | Fix the server config — the code was never the problem |
| Tooling (data format) | Structured data exists but is not parsed | @graph JSON-LD format not traversed, type names not recognized | Fix the parser — the schema was never the problem |
The danger of tooling problems is that they produce plausible scores. A score of 38.9 looks reasonable. It does not scream "this tool is broken." The only way to detect a tooling problem is to examine dimension-level scores and ask: "Does a pattern of zeros make sense given what I know about the content?" The @graph parsing issue was even more subtle: SD=30 looked like "some structured data but incomplete" when in reality it was "complete structured data in a format the parser does not understand."
The danger of server-layer problems is that they are invisible in local development. You deploy a page, verify it works locally, and assume it is live. But a web server configuration from months ago silently serves an older version.
Lessons for AEO Practitioners
1. Check dimension-level scores, not just the composite
An overall score of 38 could mean "all dimensions are weak" or it could mean "three dimensions are scoring zero because of a systematic error." Only the dimension breakdown reveals which.
2. Be suspicious of universal zeros
If one page scores 0 on DirectAnswer, maybe the content genuinely lacks a definition pattern. If every page scores 0 on DirectAnswer — especially pages you know contain definitions — the tool is failing, not the content.
3. Test your AEO tools in your language
If you run any AEO scoring tool on non-English content, verify that the tool can actually parse your language. Ask: Does it detect my definition patterns? Does it find my FAQ sections? Does it count my question headers? If not, the tool's scores are not measuring what you think they are measuring.
4. Unicode is not optional
Tools that use \w for word matching will fail on accented characters (é, ö, ñ, ü) and completely break on non-Latin scripts (Chinese, Arabic, Japanese, Korean). The \p{L} Unicode category and the u regex flag are necessary, not nice-to-have.
5. Distinguish content fixes from tool fixes
When a score is low, the instinct is to "improve the content." But if the tool is wrong, content changes waste effort. The sequence should be: verify the tool reads the content correctly → then evaluate whether the content needs improvement.
6. Verify your production environment, not just your code
We deployed a complete Next.js page with FAQ sections, JSON-LD schemas, and rich content — and it made zero difference because Nginx was serving an old HTML file. Always verify what the production URL returns, not just what your build output contains. The command curl -s https://yoursite.com | grep 'expected-text' would have caught this in seconds.
7. Validate your tool against known-good data
The @graph parsing bug affected every page that used the standard multi-schema JSON-LD format. We only caught it because we knew the structured data was present (we had just built it) and the score did not reflect that. If you add structured data and the score does not change, inspect the tool's parsing — do not assume the schema is wrong.
What We Changed in AEOCrawler
AEOCrawler v1.9.1 (released 2026-05-27) added full Swedish language support in both DirectAnswer and QueryCoverage algorithms. The architecture is designed for incremental language additions — each language adds its own verb lists, phrase lists, and function-word filters to the existing pattern blocks.
AEOCrawler v1.9.2 (released 2026-06-05) fixed the StructuredData algorithm to properly traverse JSON-LD @graph arrays and expanded the recognized schema type list to include FAQPage, BreadcrumbList, WebSite, and SoftwareApplication. This fix affects all pages analyzed by AEOCrawler — not just Swedish content.
We recognize that Swedish is only the beginning. The same language bias exists for every non-English language, and we are building toward broader multilingual support. If you are analyzing content in a language other than English and notice systematic zeros in DirectAnswer or QueryCoverage, contact us — your data helps us prioritize which languages to add next.
The full AEO scoring framework documentation has been updated to reflect the multilingual patterns and StructuredData improvements.
Timeline
| Date | Round | Actions | Average AEO |
|---|---|---|---|
| 2026-05-26 | Baseline | First AEO analysis, 9 pages | 38.9 |
| 2026-05-26 | Round 2 | Fixed middleware access (PUBLIC_PATHS), created Next.js pages, added JSON-LD and direct-answer text | 45.6 |
| 2026-05-27 | Round 3 | Algorithm fix (Swedish regex in DirectAnswer + QueryCoverage), pricing page FAQ + dateModified | 55.7 |
| 2026-06-03 | Round 4 | Homepage FAQ section, new integrations Next.js page, removed Nginx static-HTML overrides | 57.5 |
| 2026-06-05 | Round 5 | StructuredData @graph parsing fix, expanded recognized schema types (v1.9.2) | 65.9 |
| 2026-06-07 | Verified | Full re-scan confirms all scores stable; this article scores 83.6 | — |
Frequently Asked Questions
Does this language bias affect all AEO tools, or just AEOCrawler?
Any AEO tool that uses pattern matching — regular expressions, keyword detection, or rule-based content analysis — is likely to have some degree of English-language bias unless multilingual support was deliberately built in. Tools that use LLM-based analysis (sending content to an AI model for evaluation) are less affected, since language models understand multiple languages natively. However, even LLM-based tools may use regex preprocessing steps that introduce bias.
Which AEOCrawler algorithms were affected?
Three of the nine algorithms had bugs exposed by this case study. DirectAnswer (20% weight) and QueryCoverage (10% weight) had English-only regex patterns — together accounting for 30% of the total AEO score. StructuredData (12% weight) had a separate issue: it could not parse JSON-LD blocks using the @graph array format, which is the standard way to include multiple schema types. The other six algorithms — CitationPotential, EntityClarity, SemanticCoverage, Conciseness, Readability, and ContentFreshness — use language-independent signals and were not affected.
What languages does AEOCrawler support after v1.9.1?
AEOCrawler v1.9.1 fully supports English and Swedish in DirectAnswer and QueryCoverage. All other algorithms work across any language. Additional language support for German, French, Spanish, and Dutch is planned. The architecture uses modular language packs — adding a new language requires defining its definition verbs, answer phrases, question words, and instructional markers.
How can I tell if my AEO scores are affected by language bias?
Check your DirectAnswer and QueryCoverage dimension scores. If your content is written in a non-English language and these two dimensions consistently score near zero while other dimensions score normally, the tool may not be parsing your language correctly. A direct answer pattern like "[Subject] [verb] [description]" in the first 200 words should produce a non-zero DirectAnswer score. If it does not, the tool's pattern matching likely does not include your language's verbs.
Does fixing the tool bias improve actual AI citation performance?
Fixing tool bias improves the accuracy of the measurement — it makes the score reflect the content's actual readiness for AI citation. It does not, by itself, change how AI engines treat the content. However, accurate measurement enables accurate prioritization: you stop wasting effort "fixing" content that was already well-structured, and instead focus on the pages and dimensions that genuinely need improvement.
What was the @graph JSON-LD parsing bug?
JSON-LD structured data can be written in two formats: a flat format where the root object has a @type directly, or a @graph format where multiple schema types are wrapped in an array. The @graph format is the standard way to include Article, FAQPage, and BreadcrumbList in a single JSON-LD block. AEOCrawler's StructuredData algorithm only checked the root-level @type and never traversed into the @graph array. Pages with @graph-formatted JSON-LD received only 30 points (for JSON-LD presence) instead of the full score for their complete schemas. This affected all websites using the @graph format, regardless of language.
Is there a performance difference in AEO scoring for non-English content?
At the AI engine level (ChatGPT, Perplexity, Google AI Overviews), non-English content generally has lower citation rates than English content — but this reflects the smaller corpus of non-English web content and lower query volume in those languages, not a structural bias in the content itself. At the AEO scoring tool level, the bias we discovered was entirely artificial — a measurement error, not a reflection of content quality.



