A site reports 94% of pages indexed and everyone moves on. Break that number down by market and it reads US 99%, Germany 61%, Japan 12%. Nothing on any one page was wrong. The German canonical pointed at the English original, the Japanese folder was behind an IP redirect Googlebot never got past, and the site-wide average covered both. That’s the shape of almost every international finding I’ve written up in the last few years: the fault sits between two markets, and a single-market audit walks each room, reports it clean, and never looks at the wiring between floors.
An international SEO audit checks whether Google understands which page belongs to which country and language, market by market. Most guides ranking for this term stop at the hreflang tag. The tag is where the problems start, not where they live. What follows is how I run the audit, in the order the trade-offs bite, with the tool filters, Search Console statuses and document limits named, because a check you can’t reproduce isn’t a check.
International SEO audit scope: website, country, language, intent
A regular SEO audit asks what’s wrong with a site. An international audit asks a harder question: does Google understand which page belongs to which user, in which country, in which language? The object under review changes. You’re checking the intersection of Website × Country × Language × Intent, and the failures hide in the gaps between those four, where a single-market audit never looks.
| A regular audit checks | An international audit adds |
|---|---|
| Crawlability & indexation — site-wide | Indexation and crawl per locale — market by market |
| One keyword set — home market | Native demand per market — researched locally |
| Site-wide Core Web Vitals — one average | Performance by geography — per region |
| One backlink profile — domain-level | Authority per country — by referring market |
| Duplicate content — within the site | Duplicates across countries — cross-locale |
| Canonical tags — in isolation | Canonical × hreflang × indexability — as one unit |
| Structured data — valid or not | Schema per locale — language, currency, entity |
One distinction has to be settled before any of the checks make sense: multilingual, multiregional, or both. A Swiss site in German, French and Italian, all serving one country, is multilingual. A German-language site serving Germany, Austria and Switzerland is multiregional — same language, three markets, three different SERPs. Plenty of sites are both at once, and that’s the point where hreflang stops being a tag you add and becomes an architecture you maintain.
THE FOUR TARGETING SIGNALS
Underneath every check sits one question: what tells Google which country and language a page is for? Four signals, unequal in weight. The URL (a ccTLD like example.de states a country by itself; a subdirectory states nothing until something else does). Hreflang, built for the job: it names language and region and ties the set together. The language of the content itself. And server or CDN geography, which nudges rather than declares. There used to be a fifth, Search Console’s country-targeting setting. Google removed it in September 2022 along with the International Targeting report, the only built-in hreflang error report, saying manual country targeting had little value for the ecosystem. Several guides still in the top ten tell you to open that report. It doesn’t exist. There is no manual override anymore and no place inside Google’s own tools that validates your hreflang; the validation is a crawl you run yourself. When the four remaining signals agree, targeting is clean. Most international failures are two of them disagreeing.
Market validation: demand, local SERP and competitors per country
The most expensive failure in international SEO happens before a page exists: translating a site into a language whose market never asked for it. Validating demand costs a week. Translating, localizing and then maintaining a dead locale costs years. So the audit starts away from the site.
For each country on the table I trace one chain: what people search, with what intent, on which SERP, against which local competitors, and where the gap sits that you could realistically own. Break the chain anywhere and that market drops to the back of the queue. A German SERP packed with entrenched local brands carrying local link profiles is a different investment case from a Dutch SERP where half the page is thin translations nobody localized. Same ambition, two different fights.
The question everyone asks here is how many markets at once, and the answer is fewer than you’d like. For most teams the ceiling is one new market per cycle, two when the language is shared. Every locale you open is permanent: its own keyword research, its own content to keep at parity, its own link profile built from nothing. Ten half-maintained locales lose to three maintained ones, and the wreck of ignoring this shows up in audit after audit as a hreflang cluster referencing eight languages, six of which nobody has touched since launch day.
Before committing to a market I take its raw keyword export and cluster it to see how many pages of demand it holds. The exports mislead on their own: a German export of 1,400 keywords typically collapses into 30 to 40 intents, and a “market” that looked like a site turns out to be four pages of content. That’s an answer too, and cheaper to hear now than after the translation invoice.
URL architecture: subdirectory, subdomain or ccTLD
Every guide lists the options — example.de, example.com/de/, de.example.com, plus locale variants like /de-de/ and /en-gb/ — and most stop there, as if listing them were the same as deciding. It isn’t.
A ccTLD (example.de) buys the cleanest country signal and charges the highest rent for it, and the rent is the part nobody costs out loud. Each country domain is a separate site in Google’s eyes, starting from nothing and earning its own links. Since Google’s July 2026 rewrite of its crawl-budget guidance it’s also a separate crawl allowance: the limit is set per hostname, every host starts on a conservative default and grows only as the server proves it can take more, so three ccTLDs are three cold starts on crawl as well as on authority. The question isn’t “is a ccTLD good for Germany” — it obviously is — but whether you can fund a from-scratch link profile and sit through a from-scratch crawl ramp for every market you’re about to spin one up in. I’ve watched a company launch example.de, example.fr and example.it in one quarter and sit invisible across all three for a year: one domain’s authority divided into three newborns, none of them fed. I only sign off on a ccTLD when the market is a decade-long commitment, when a local legal entity forces it, or when the business can resource link-building per country.
A subdirectory (example.com/de/) consolidates authority. Every link to any locale strengthens all of them, geo-targeting comes from hreflang and content rather than the domain, and you keep one CMS, one crawl allowance, one migration when things change. For most companies expanding past their first market this is the default, and the burden of proof sits on anyone arguing against it.
Because a subdirectory carries no geo-signal in the URL, and Search Console no longer lets you assign one, the check is what Google is inferring. I create a URL-prefix property per locale folder, open the Performance report with the Country dimension, and read which market Google is serving each folder to, which is not always the one on the label. A /de/ folder getting 60% of its impressions from Austria and Switzerland isn’t broken, but it’s telling you something about the hreflang set.
A subdomain (de.example.com) is the option I flag more often than any other, because it’s almost always chosen by accident. Google’s public line is that it treats subdomains and subdirectories the same. What I see across audits is that authority consolidates worse on a subdomain than on a folder, the geo-signal stays weaker than a ccTLD, and under the per-hostname crawl rule a subdomain is its own cold start too. It collects the downside of each and the upside of neither. The tell, when I audit one, is that nobody can explain why it exists: the defensible reasons are all organizational, not search — separate infrastructure per country, separate teams, an acquisition you haven’t merged yet. If one of those is true, live with it. If none is, someone picked the weakest structure because the dev set it up that way.
THE TEST I APPLY
Default to a subdirectory, and only move to a subdomain when you can name the specific piece of infrastructure that makes a subdirectory impossible: a separate platform you can’t route under one domain, a CDN or CMS boundary that won’t bend, a team that owns its own stack. If you can’t name it in one sentence, you don’t have that constraint, and you’re on a subdirectory. “It depends on your needs” fails here because it never says which need decides.
One failure mode I flag every time it appears: mixed structures. A ccTLD for Germany, a subdirectory for France, a legacy subdomain for Japan. Each choice was locally sensible the day someone made it, and together they split authority three ways, triple the maintenance, and make every future decision harder than it needed to be. Consistency beats optimality.
Hreflang audit: ISO codes, return links, x-default and canonical conflicts
What is hreflang? An annotation that tells search engines which language and region a page variant is for, so a searcher in Austria gets /de-at/ instead of /de-de/. That’s the tag. What Google evaluates is the cluster — the complete set of alternate URLs that all have to agree with each other — and one broken member drags down the whole set. A hreflang audit that checks tags in isolation misses that, and with the Search Console report gone the only way to see the cluster is to crawl it.
Codes first, because they break most often. Language is ISO 639-1, region is ISO 3166-1 alpha-2, in that order: en-GB is valid, en-UK is not, and en-UK shows up in production constantly because UK feels right to whoever typed it. A region on its own (hreflang="GB") is invalid; a language on its own (hreflang="de") is fine. Script goes between them as an ISO 15924 code — zh-Hant, zh-Hans-SG — and a Chinese site that ships zh-TW and zh-CN without the script is telling Google about regions when the difference it cares about is the writing system.
Then the structure. Every page references itself. Every reference is reciprocated: Google’s documentation says one-way annotations may be ignored, and in practice they are. An x-default catches everyone who matches nothing, and it should point at the selector page, not at the English version by habit. Then the targets: each alternate URL returns 200, never a redirect, never a 404, never a soft error page dressed as a 200, and never a page carrying noindex. A noindexed member is the one people miss; Google drops it from the cluster, and the members that referenced it lose their return link.
Where the annotations live matters more than most guides admit. Google accepts three placements: a <link rel="alternate" hreflang="de-AT" href="…"> in the head, an HTTP Link: header (the only option for PDFs and other non-HTML files), and xhtml:link entries in the XML sitemap. On a site with twelve locales the head version means twelve link tags on every page, maintained by whoever touches the template. Past a handful of locales the sitemap is the placement that stays correct, because it’s generated rather than hand-edited, and it’s what I recommend on nearly every site that has grown past three markets.
The crawl is Screaming Frog with hreflang extraction on, and the Hreflang tab does the cluster reading for you. Each filter is one of the failures above:
Non-200 Hreflang URLs— targets that redirect or 404Unlinked Hreflang URLs— alternates the crawler found only in annotations, never in a link, which usually means orphansMissing Return Links— the reciprocity failureInconsistent Language & Region Return Links— page A says B isfr-FR, B says it’sfr-CANon-Canonical Return LinksandNot Using Canonical— annotations pointing at URLs that canonicalize elsewhereNoindex Return Links— the noindexed memberIncorrect Language & Region Codes—en-UKlives hereMissing Self Reference,Missing X-Default,Outside <head>
Export the lot from Reports → Hreflang, and read the counts per template rather than per URL, because a broken cluster on a product template is one bug repeated ten thousand times and one fix.
The subtle killers live at the intersection with canonicals, and this is where most audits pass a site that’s broken. Hreflang pointing at a non-canonical URL. A canonical pointing across markets, telling Google the German page is a copy of the English one, while hreflang insists it’s an alternate. When those two signals contradict each other Google resolves the conflict for you, and it resolves it by ignoring your hreflang. So I check that triangle — hreflang, canonical, indexability — as one unit, because a clean result on any one leg tells you nothing.
Then the incomplete clusters. Fourteen pages exist in English, nine in German, and the hreflang set references all fourteen pairs regardless. Those five phantom members don’t sit there harmlessly. They poison the annotations of the nine that exist.
Indexation and crawl budget per locale: Search Console statuses and server logs
I don’t trust the aggregate. I slice indexation by market — submitted versus indexed, the exclusion reasons, and whether the excluded pages cluster in one language — because that clustering is the diagnosis. Random gaps across locales point to crawl budget. An entire locale missing points to a structural block.
| Locale | Indexed | Dominant exclusion |
|---|---|---|
| United States | 99% | — |
| Germany | 61% | Duplicate, Google chose different canonical than user |
| Japan | 12% | Discovered – currently not indexed |
| Site-wide average | 94% | hides all three |
Cross-country duplicates are the usual structural block. Google finds the /en-us/ and /en-gb/ pages nearly identical, picks one as canonical, and drops the other. The drop shows up as Duplicate, Google chose different canonical than user, and when that reason clusters in one locale, that locale is being folded into another. The fix isn’t padding out unique content for its own sake. It’s either localization that changes the page — terms, prices, currency, examples — or a complete hreflang cluster telling Google the overlap is intentional.
The Japan row is a different failure, and Search Console can’t show you why, because the Crawl stats report works at the property level and won’t split by folder. That’s where server logs come in. Segment verified Googlebot hits by locale prefix and the picture usually explains the status: the crawler spends its allowance on the home-market templates it already knows and reaches the new locale a few hundred requests a month, which on a 20,000-URL folder is a refresh cycle measured in quarters. Under the July 2026 rule that allowance is shared across all of Google’s crawlers on the hostname, so a heavy AdsBot run against the home market is spending the Japanese folder’s crawl too. The Discovered – currently not indexed pile in one locale is that number, seen from the other side.
Two self-inflicted wounds earn their own checks. Redirecting users by IP to “their” version also redirects Googlebot, which Google’s documentation says crawls primarily from US addresses, so it never sees the other locales at all. Geo-blocking, where the German site only answers to German IPs, does the same thing more bluntly. Both look like UX decisions in a meeting and turn out to be indexation decisions in production. The test: fetch each locale’s key pages with a US IP and no cookies, and see what comes back.
Localization: slugs, metadata, currency and information gain per market
There’s a ladder, and each rung costs more than the last: machine translation, human translation, localization, local search behavior. Most international sites stop at rung two and then wonder why the competitors sitting on rung four outrank them.
Same language doesn’t mean same market. A US travel site expanding to the UK translates nothing, and still “vacation rentals” has to become “holiday lettings” or the pages target demand that doesn’t exist there. Currency, date formats, units, the legal wording in commercial claims, which trust signals convince a local buyer: all of it is market work no translator was briefed to do. URL slugs and metadata get skipped even by teams that localize their body copy, so /en/seo-services/ ends up with a German page behind an English slug, an English title tag, sometimes an English meta description showing in the German SERP. Those are ranking surfaces. They localize or they leak.
Translation preserves your words and throws away your differentiation, because content uniqueness is relative to a SERP and every market has its own. A page can be original against the US top ten and add nothing against the German one, because the German competitors already cover its every point. This is measurable, so I measure it: an information-gain run scores the localized page against the corpus of the target market’s SERP, not the home market’s, and the number that comes back is how much the page adds where it has to compete. The pattern I see most is a flagship guide scoring in the sixties at home and in the twenties abroad, because the home version was written against a SERP the market never sees. This check is the one thing in the audit I couldn’t do by hand, and the reason the tooling exists.
Keyword research per market: native terms, local SERP and intent
A translated keyword list fails along a predictable chain: English keyword → translation → native search term → local SERP → intent, and every arrow is a place to lose the market. Sometimes the dictionary gets lucky. “Car insurance” into German is “Autoversicherung,” which happens to be what people search. Often it doesn’t. “Attorney” becomes “Rechtsanwalt,” which carries a fraction of the volume; the demand sits under “Anwalt” and then splits by specialty in a way the US market doesn’t — “Anwalt Arbeitsrecht,” “Anwalt Familienrecht,” “Fachanwalt für Mietrecht” — so a page built for the translated head term is built for a query nobody types and misses the five that everyone does.
Research starts from native terms, never from your existing list run through translation. Autocomplete in the target language, the terms local competitors rank for, volumes pulled with the country switched, because the same string carries different demand in different countries and a US volume tells you nothing about Spain.
Then read the SERP itself. It’s Google telling you for free what it believes the intent is. One phrase, three countries, three result pages: the US shows guides and an AI Overview, Germany shows service providers and a map pack, France leads with two marketplaces. Ignore that and you optimize a page type the market’s SERP doesn’t rank.
Core Web Vitals by region: CrUX, CDN and server geography
A site-wide Core Web Vitals score is an average, and averages hide the markets you’re failing. A site served from Frankfurt posts a green LCP overall while Tokyo waits six seconds for the same page, and the Japanese locale’s rankings reflect Tokyo, not the flattering global number. I read performance per region: real-user metrics split by country where the data exists, synthetic tests from in-market locations where it doesn’t. The Chrome UX Report that feeds Google’s field data only holds numbers for URLs with enough traffic, so a small locale usually has no per-URL data at all and inherits the origin’s figures, which is how a failing Japanese template hides behind a passing German one. The CrUX API takes a country filter; the PageSpeed Insights front end doesn’t, and most reports are built from the front end.
The findings are unglamorous. No CDN edge near the market. Images shipped at full weight across an ocean. A JavaScript-only locale switcher that renders fine for a human and leaves the crawler on the default language. Server geography whispers into geo-signals too: it won’t override hreflang, but a “German” site served from Ohio with no European presence is slower for its users and less coherent to a crawler. Fix the delivery and both problems close together.
Backlink profile by country: referring domains per market
The question that decides rankings in a new market: does this site have authority in that market, or authority in general? Domain-level metrics say yes; the country breakdown says otherwise. A profile of five thousand referring domains that’s 92% American is a strong US site and a weak German one, and German rankings are contested by the sites German publications link to, not by your domain rating. Authority localizes the same way content does. Funding translation while skipping the local links is buying half a market entry and expecting a whole one.
I break the backlink profile down by the country of the referring domain and set it against the competitors that rank in that market. The distribution usually settles the argument at a glance. From there it’s ordinary link work aimed locally: local publications, industry directories, partners and PR inside the target market.
THE LANGUAGE SELECTOR EVERYONE GETS WRONG
Small section, constant finding. The selector should be crawlable links, one per locale, with an <a href> underneath whatever the JavaScript does on top. Auto-detection can suggest but never force, because a forced redirect traps users and crawlers alike on one version. A flag is a country, not a language, so a flag-only selector tells a Spanish speaker in the US nothing useful. And the cross-market internal links people forget entirely — the German article linking back to its English original — pass signals your hreflang alone doesn’t.
Structured data per locale: inLanguage, priceCurrency, Organization
The general technical audit checks that schema is present, valid and matches the page. The international one adds a question the validators can’t answer: does the markup on the German page describe a German page?
Usually it doesn’t. The JSON-LD is generated once by the template and never localized, so /de/ ships an Article with an English headline field, a Product whose Offer carries priceCurrency: "USD" under a price shown in euros, and an Organization whose sameAs points at the US LinkedIn page. Each of those is markup contradicting the visible page, which is the thing Google’s structured-data policies are written against, and it’s contradicting the hreflang as well: the tag says this is the German version, the entity data says it’s American.
The checks are short. inLanguage on Article and WebPage matches the locale. priceCurrency matches the currency on the page. Organization is either one global entity with a per-locale ContactPoint carrying availableLanguage and areaServed, or a LocalBusiness per market with a local address — and not, as I find on most sites, the US entity pasted onto every locale. Author Person markup, if it exists, links to a profile the local reader can read. Run the Rich Results Test per locale, not once on the home market, because a template error in the localized string handling shows up only where the strings were localized.
Localized markup matters more now than it did, for a plain reason: AI Overviews and AI Mode read entity data to decide what a page is about, and they do it per language. A German page whose entity layer says “American company, USD” is a weaker candidate for a German answer than its content deserves.
Bing, Yandex, Baidu and Naver: hreflang and content-language outside Google
Everything above assumes the engine reading your signals is Google. In four markets that assumption costs you. Yandex reads hreflang from the HTML head and recommends x-default, so the cluster work carries over. Bing treats hreflang as a weak signal — its own engineers have said content-language matters more to it — so a site that dropped the <meta http-equiv="content-language"> tag years ago because Google ignores it is under-signaling the second engine in the US and, through Yahoo, in Japan. Baidu and Naver don’t read hreflang at all: Baidu goes by content-language, in-country hosting and a Chinese-language site, and Naver expects registration in its own Webmaster Tools and weights its own platforms above the open web. If China or Korea is on the market list, the hreflang cluster is irrelevant there, and the audit for that locale is a different document.
Compliance: consent walls, geo-restrictions and the 451 status
This isn’t legal advice. It’s the short list of places where a compliance decision becomes a search decision without anyone noticing. A consent wall configured for the EU that renders the page only after a click: Googlebot doesn’t click “accept,” so whatever sits behind the wall doesn’t exist for it, and the tell in Search Console is a locale whose pages sit in Crawled – currently not indexed while the URL Inspection screenshot shows the banner and nothing else. Commercial claims carrying legal wording that varies by market — pricing-display rules in Germany, financial-product language in the UK, health claims almost everywhere — where the compliant copy sometimes changes the target keyword. Content that legally can’t ship to some markets, where the geo-restriction mechanic you pick (block, redirect, serve a variant) lands differently on indexation; a 451 status keeps the URL out of that market’s index without dragging the others. My job in the audit isn’t to interpret the regulations. It’s to make sure the compliance plumbing isn’t strangling the site’s own search presence, which happens more often than either the lawyers or the SEOs expect.
Reporting per locale: Search Console country filter, positions and AI Overviews by market
“Organic traffic grew 20%” is a sentence built to hide everything worth knowing. Decompose the same quarter — US +32%, UK +11%, Germany −18%, France +4%, Japan −41% — and there are questions. Germany dropped after which change? Did Japan break, or did it never work? Aggregates report; breakdowns diagnose. Every metric, from impressions and position to CTR and conversions, gets carried down to the locale level, and Search Console gets read filtered by country rather than as one blurred total.
Positions get tracked per locale, because a keyword’s “position” is a different number in every country. And AI visibility gets tracked per market, because the AI surfaces arrived market by market and still behave that way. AI Overviews reached the US in May 2024 and most of the EU through 2025; France was the last major European market without them, and Google told French publishers on June 29, 2026 that AI Overviews and AI Mode would be live there by September 23. A French locale audited in spring 2026 and again this autumn is being audited against two different SERPs. Search Console now folds AI Mode into the Performance report, and its August 2026 documentation says each follow-up inside an AI Mode conversation counts as a new query with its own impressions and position — so a locale’s impression growth this year may be conversation depth, not reach. What I can’t tell you yet is how citation rates differ between languages for the same site, because the report doesn’t split AI surfaces by language and I don’t have a large enough multi-locale sample to say it myself.
International SEO audit checklist: ten checks and where to read each one
Ten places to look, where I read each one, and the status or filter that surfaces the failure. None of the rows is an audit on its own; the audit is the reading across them.
| Check | Where I read it | What surfaces the failure |
|---|---|---|
| Market demand | Native keyword export, clustered to intents; local SERP by hand | 1,400 keywords collapsing into 30 intents |
| URL architecture | Crawl segmented by host and folder; GSC Performance → Country per locale property | Mixed structures; a folder served to the wrong country |
| Hreflang cluster | Screaming Frog Hreflang tab, Reports → Hreflang | Missing Return Links, Non-Canonical Return Links, Incorrect Language & Region Codes |
| Indexation per locale | GSC Pages report per locale property; bulk index check per folder | Duplicate, Google chose different canonical than user clustering in one language |
| Crawl per locale | Verified Googlebot hits in logs, segmented by locale prefix | Discovered – currently not indexed piling up in one folder |
| Geo-redirect / geo-block | Fetch each locale from a US IP, no cookies | Every locale returning the home-market page |
| Localization depth | Information-gain run against the target market’s SERP corpus | Sixties at home, twenties abroad |
| Performance by region | CrUX API with country filter; in-market synthetic tests | Origin-level fallback masking a failing locale template |
| Authority per country | Referring domains by country vs the ranking local competitors | 92% of links from a market you’re not entering |
| Schema per locale | Rich Results Test per locale; JSON-LD diff across templates | priceCurrency or inLanguage disagreeing with the page |
Look down that table and the same fault keeps surfacing. Almost none of these failures live inside a page. They live between markets: the canonical that contradicts the hreflang, the locale that fell out of the index while the average looked fine, the page that was original at home and redundant abroad, the entity data that never got translated, the authority that never crossed the border.
A normal audit walks the rooms and reports each one clean. The building is still miswired between floors.
What I’d expect to change first: by 2028 the per-locale information-gain read stops being a tooling curiosity and becomes the standard localization check, because “translated” and “competitive” have stopped meaning the same thing in every market I look at, and the AI surfaces, now live language by language, will make the gap visible to clients before it’s visible in rankings. If you want the single-market foundation this builds on — crawl, render, index, the technical layer read as one path — that’s our SEO audit.