As a team that audits other people's sites, we put our own through the same process. Here are the 8 issues we found, why they matter and how you can check for them on your site.
In short: When we put kodakod.com through a technical SEO audit, we found eight issues: unpublished posts in the sitemap, Turkish titles on English pages, a duplicated brand name, orphan category pages, a breadcrumb that didn't match its schema, numbers that only arrived through JavaScript, wrongly protected staging sites and a 404 page that sent visitors to the wrong language. None of them were content problems; all of them came down to how the site was coded. Below we go through each finding, what Google's official documentation says about it and how to check for it on your own site.
This article starts with a confession: we built kodakod.com ourselves, and when we put it through a technical SEO audit, we found some of the very mistakes we look for on other people's sites.
A bit of context: the site is bilingual. Turkish pages are served without a prefix and English pages under /en/. It's made up of blog, service, portfolio and legal pages, all fed from an admin panel. We ran the audit in more than forty steps, covering crawling, indexing, meta tags, structured data, multilingual setup and internal linking. The eight findings below are the ones you're most likely to run into on your own site.
1. Unpublished posts were in the sitemap
We can give blog posts a future publish date. The problem: posts whose date hadn't arrived yet appeared in the listing, the sitemap and the RSS feed, and their URLs opened. We were telling Google "this page is ready" when it wasn't.
The fix was to remove not-yet-published content from every surface and return a real 404 to direct requests for it.
Google's sitemap guide is clear on the rule: list only the canonical URLs you want to see in search results, as fully qualified (absolute) URLs. The same guide reminds you that a sitemap is only a hint, not a guarantee, and that the <lastmod> value is used only if it's consistently accurate. In other words, wrong URLs also erode how much your sitemap can be trusted.
On your site: If you have a scheduled post, open your sitemap.xml and look for its URL. If it's there, you have the same problem.
2. Turkish titles on English pages
This finding took the most time. Some English pages, such as the homepage and the legal pages, had a Turkish <title> and meta description. The cause was a classic one: their titles were written into the template in Turkish and printed untranslated on the English version. English pages with no description of their own also fell back to the Turkish default. The page was in English, but the text Google would show in search results was in Turkish.
We moved title and description localization to a single place, so a page can no longer skip translation. We also wrote a small scan script that looks for Turkish characters and words on English pages, and we run it whenever something looks off.
On multilingual sites there's an hreflang side to this as well. According to Google's documentation on localized versions, each language version must list itself as well as all the other versions; if two pages don't point to each other, the tags are ignored. The same document says Google doesn't use hreflang or the HTML lang attribute to detect a page's language; it uses its own algorithms. So even with perfect tags, a Turkish title on an English page means the problem isn't solved.
On your site: Search Google for site:yoursite.com/en and look at the result titles. Even one title in the wrong language points to a broken translation chain.
3. The brand name twice in the title
On service and blog pages, titles came out as "Page name | Kodakod | Kodakod". The brand suffix was added both by the page template and in the content. It looks minor, but the space a title gets in search results is limited, and the repeated brand name was wasting part of it.
A note here on the often-quoted "titles must stay under 60 characters" rule: Google's title link documentation sets no length limit on the <title> element; titles are truncated in search results as needed, typically to fit the device width. The same document advises avoiding repeated or boilerplate text in titles and suggests using your site name just once, at the beginning or end. The practical takeaway: put the important words first and the brand name once at the end.
On your site: List every page title with a crawler and count the brand mentions.
4. Category pages nobody linked to
We had category and tag pages, and they were in the sitemap. But the category cards on the site didn't link to those pages; they linked to a section on the same page (#category). The result was orphan pages that couldn't be reached from anywhere inside the site.
Google's documentation on links says Google uses links both to find new pages to crawl and as a signal of a page's relevance, and that every page you care about should have a link from at least one other page on your site. Google can also only reliably follow a link if it's an <a> element with an href attribute. Listing a page only in the sitemap, with no internal links to it, means that signal is missing entirely.
We pointed the cards to the real URLs.
5. The visible breadcrumb and the schema breadcrumb didn't match
The "Home › Blog › Post" line at the top of the page and the BreadcrumbList structured data written for Google were generated in two separate places. They started out identical, but when one changed, the other didn't follow.
Google's structured data guidelines are explicit: markup must be a true representation of the page content, and you shouldn't mark up content that readers can't see. Markup that violates these guidelines may not be shown as a rich result even if its syntax is correct, and in serious cases a manual action can remove rich result eligibility.
We now generate both from a single component. Across fourteen page types they come from the same source.
6. The initial HTML said "0 projects"
The counters on our About page (completed projects, customer satisfaction score) counted up from zero with JavaScript after the page loaded. A nice animation for visitors. But in the page's initial HTML, every one of those numbers was zero. A crawler that doesn't run JavaScript, and some of the crawlers behind today's AI tools work that way, read "0+ completed projects" and "0/5 customer satisfaction" on our page. Visitors using screen readers heard the same zeros.
We now write the real values into the HTML on the server; the animation is just decoration.
Googlebot can run JavaScript, but Google's JavaScript SEO basics also notes that not all bots can, and that server-side or pre-rendering is still a great idea because it makes a site faster for users and crawlers alike. The rule is simple: if information matters, it belongs in the initial HTML.
On your site: Right-click your page and choose "View page source". If your key numbers and copy aren't there, they only arrive through JavaScript.
7. Non-production sites were protected only by robots.txt
In our non-production environments, robots.txt blocked the whole site from crawlers. Most teams think that's enough. It isn't: robots.txt blocks crawling, not indexing. Google's robots.txt documentation says so plainly: robots.txt is not a mechanism for keeping a page out of Google, and if other pages link to a URL, Google can index it without ever visiting the page.
Our first response was to add a noindex tag to every page in non-production environments. But that setup has a trap of its own, and we should be upfront about it: adding noindex alongside a robots.txt block doesn't work. According to Google's noindex documentation, the page must not be blocked by robots.txt for the rule to take effect; if it is blocked, the crawler never opens the page and never sees the noindex. Google also doesn't support noindex rules written inside robots.txt.
For a staging site, the right order is:
- Access protection is the most reliable: Put the environment behind a password, an IP allowlist or authentication. Google's robots.txt documentation also points to noindex or password protection for keeping a page out of Google. If a crawler can't reach the content, there's nothing to index.
- If you can't add access protection, use noindex: Send a noindex meta tag or an X-Robots-Tag header with every response, and do not block those URLs in robots.txt; Google needs to be able to see the tag.
- robots.txt on its own is not protection: It's for managing crawl load, not for privacy.
8. The English 404 page led to the Turkish homepage
Our error page correctly returned a real 404 status code; that part was solid. But it had a single "Home" link, and it always went to the Turkish homepage. A visitor who hit a broken link on an English URL was either dropped onto a Turkish page or left the site. There was no path to services, the blog or contact.
We added home, services, blog and contact links to the 404 page, in the visitor's language. Error pages tend to be forgotten, yet they're the last chance to keep a visitor who arrived through a broken link.
One caution: pages that show a "not found" message but return a 200 status are reported by Google as "soft 404s". For single-page apps that route with JavaScript in particular, Google's same guide recommends redirecting to a URL where the server returns a 404, or adding noindex to the error page.
The findings and Google's official guidance
| Finding | What Google's documentation says | Our fix |
|---|---|---|
| Unpublished posts in the sitemap | Only canonical URLs you want to appear in search belong in the sitemap. | Not-yet-published content removed from every surface; its URL returns 404. |
| Turkish title on an English page | Google detects language from the content; hreflang must be reciprocal. | Titles and descriptions generated per language from one place. |
| Brand name twice | Avoid repeated boilerplate in titles; the site name once is enough. | The brand suffix is added in one place only. |
| Orphan category pages | Every page you care about should get at least one internal link. | Cards now link to the real URLs. |
| Breadcrumb mismatch | Structured data must truly represent the visible content. | Both generated from a single component. |
| Numbers loaded with JavaScript | Not all bots can run JavaScript; server-side rendering is recommended. | Values written into the HTML on the server. |
| Staging sites | robots.txt doesn't block indexing; for noindex to be seen, the page must be crawlable. | Access protection, or noindex that isn't blocked. |
| 404 page | Error pages should return a real 404; avoid soft 404s. | 404 kept, language-aware links added. |
A short checklist
Here are the checks that come out of these eight findings, which you can run on your own site in half an hour:
- Does the sitemap contain only published URLs that return 200?
- Are titles and descriptions in each language actually in that language?
- Does each language version use hreflang to point to itself and the other versions?
- Does the brand name appear only once in each title?
- Does every page in the sitemap get at least one internal link?
- Does the visible breadcrumb match the structured data?
- Do your key copy and numbers appear in the page source?
- Are your staging sites password-protected; if not, do they have noindex, and are those pages left unblocked in robots.txt?
- Does your 404 page return a real 404 status and link to the key sections of your site, in the visitor's language?
Speed isn't on this list because it's a topic of its own. We covered page speed and Core Web Vitals in a separate article.
Common mistakes
- Treating the audit as a one-off: Most of these findings come back when a new template, a new language or a new feature is added. Tying the checks to your release process works better than an annual audit.
- Checking only the main-language pages: Our longest-running finding was on the English pages. Crawl each language as if it were a separate site.
- Mistaking a tool's warning for the problem itself: Crawling tools show the symptom; the real fix is usually in the template or the code.
The real lesson from this audit was that almost none of the findings had anything to do with content. They were all about how the site was built, in other words, the code. The same issues affect how AI assistants read your site, which is why GEO work starts from the same foundation. We've also explained how this kind of technical work should show up in an SEO proposal in our article on SEO service pricing.
If you'd like a similar audit of your site, our SEO and GEO services cover both the audit and the fixes, done by the same team.
Frequently asked questions
A technical SEO audit is the work of finding infrastructure problems that stop search engines from crawling, indexing and understanding a site correctly. It looks at crawling, indexing, titles and meta descriptions, structured data, multilingual setup and internal linking. Most findings are not about content but about how the site is coded, and the same problems also affect how AI assistants read your site.
Having an unpublished URL in the sitemap means telling the search engine that a page is ready when it is not. A sitemap should only contain URLs that are live and return a 200 status code. Content whose publish date has not arrived should be removed from listings, the sitemap and the RSS feed, and a direct request for its URL should return a real 404.
No. robots.txt blocks crawling but not indexing, so a staging URL that gets a link from somewhere can be added to the index without its content ever being read. That is why pages in non-production environments should carry a noindex tag. For Google to see that tag, the page must not be blocked by robots.txt; the most reliable approach is to protect the staging environment with a password or access restriction.
Crawlers that do not run JavaScript only read a page's initial HTML, so if key information is not there, they never see it. Some of the crawlers behind today's AI tools work this way, and visitors using screen readers can run into the same problem. To check, right-click the page and view the page source; important values should be written into the HTML on the server, with any animation kept as decoration only.
You can run a basic check in about half an hour with a few simple tests. Check that the sitemap contains only live URLs, that titles and descriptions in each language are actually written in that language, and that the brand name appears only once per title. Also confirm that every page in the sitemap gets an internal link, that the visible breadcrumb matches the structured data, that staging sites have noindex, and that the 404 page links to key sections in the visitor's language.