Skip to content
Back to Blog
GEO & AI

GEO Case Study: Implementation Log of Our Own Website

11 Eylül 2026
Next GEO Agency
GEO Case Study: Implementation Log of Our Own Website

If you are looking for a GEO case study, this article is its most auditable form: an implementation log that sets out which work we did on nextgeoagency.com, in what order, how we measured each piece and where we got it wrong. The results side has a first, limited count: on 16, 17 and 18 September 2026 we put thirty fixed questions to ChatGPT, Gemini and Perplexity twice each; we were mentioned by name in 12 of 179 valid answers, in 8 of those the question already contained our brand name, and in 6 our site was cited without our name. We have no measured data on traffic or conversions coming from AI sources, and no such figure has been invented for this article.

We split the log into four layers: access, identity, content and speed. After that we describe two things we deliberately did not do, four mistakes we made without noticing, and the method we use to measure the result. You can check most of the technical claims yourself from your browser or a command line.

This log mainly describes the implementation. All six clusters of the baseline measurement were taken with the method described below; they cover three engines, Google AI Overviews is not included in them, and each engine was measured with a single account. This article will be updated as the measurement is repeated.

Why our own site rather than a client's?

An agency's case study usually rests on client data that cannot be shared. The reader cannot see where the chart came from or which period was chosen. On our own site that problem does not exist: the structured data is in the page source, robots.txt sits at a publicly accessible address, and the headers the server returns can be seen with a single command.

The second reason is simpler. The main service Next GEO Agency sells is GEO, that is, visibility in generative search engines. An agency whose own site does not pass the basic checks of this work would be making a weak claim in saying it will do the same work for someone else's site. That is why the first criterion for every technical decision in the project is whether the site sets an example from the point of view of AI crawlers.

The third reason is being able to write about mistakes: describing an error in a client project exposes the client too.

Access: can bots see the page without running JavaScript?

The site is written in React, and by default React builds content in the browser, after JavaScript runs. A crawler that does not run JavaScript sees an empty box on such a page. To prevent this, every address is converted to HTML in advance during the build (static site generation). When a bot sends a request, the heading, body text and structured data arrive inside the first response.

The second leg of access is permission. In the robots.txt file, AI crawlers are listed one by one by name and all of them are explicitly allowed. The same decision also had to stay intact at the network layer. In the Cloudflare dashboard, the setting that automatically blocks AI bots, the bot policies in the search, agent and training categories, and the trap feature called AI Labyrinth were each checked on 24 August 2026: blocking off, all three policies set to allow, the trap off. The reasoning: if Cloudflare serves its own robots.txt, our file is effectively void. The general explanation of this distinction is in the guide to llms.txt and AI crawler management.

The third leg is the contact address. Cloudflare's email address obfuscation feature encrypted the address and put a decoding script in its place. A crawler that does not run JavaScript could not see the address at all; the script also added a link to the critical request chain of every page. The feature was turned off on 24 August 2026. We should state the cost as well: the address is now plain text and open to spam harvesters.

llms.txt, the sitemap and the redirects file are not edited by hand. All three are regenerated from the content data before every build; when a new article is added, it enters the lists on its own.

Live test on 11 September 2026

We took the table below while preparing this article, late at night on 11 September 2026. Each row is a single request sent to the /geo-ajansi address with the stated user-agent name.

DateAddressUser-agentStatus codeBytes downloaded
11 September 2026/geo-ajansiGPTBot/1.220073,983
11 September 2026/geo-ajansiClaudeBot/1.020073,983
11 September 2026/geo-ajansiPerplexityBot/1.020073,983
11 September 2026/geo-ajansiOAI-SearchBot/1.020073,983
11 September 2026/geo-ajansiMozilla/5.0 Chrome/12820073,983

All five requests received a response of the same size; the server does not show bots a different page from the one it shows browsers. The same night robots.txt returned 200; the file has 21 user-agent groups, all of them say Allow: /, and there is not a single Disallow line. llms.txt returned 200 and was 44,066 bytes. The sitemap lists 180 addresses. In the raw HTML, the page's H1 heading and structured data blocks are present without JavaScript running.

This test has a limit: the request went from our own computer, with a user-agent carrying the bot's name. Only server logs can prove that the same response is given to a request coming from the real bot's own IP address. How to set up the test and how to read the logs is explained in the guide to whether AI bots can reach your site; here we give only our own result.

Identity: what is in the identity record, and why is sameAs empty?

For an AI engine to recommend a business, it first has to recognise it. In the site's structured data the business is defined as both an Organization and a ProfessionalService. The identity record contains the district and province (Onikişubat, Kahramanmaraş), the founding year (2026), the employee range (1-10), the founder and a 17-item list of areas of expertise. There is no street address, because we do not have a street address that can be published.

The sameAs field is deliberately empty; on 11 September 2026 it sits in the page source as an empty list. This field exists to match the record on the site with profiles on other platforms. We do not yet have a social media profile or a Google Business Profile listing. Writing the address of a profile that does not exist into the schema means giving the machine information that cannot be verified. We covered how the field is used in general in the article on Knowledge Graph and entity management.

Every piece of information in the schema is also visible on the page. On our About page the same identity record sits as a block readers can read, and the page is connected to the Organization record through an AboutPage node. Before this connection was made, the page announcing the identity record had no Organization node at all. The same information is also written as an identity block at the top of the llms.txt file.

Why these fields? When we looked at the Turkish results for the search "en iyi GEO ajansı" (best GEO agency), every result was a third-party list page. These lists publish fields for each agency such as city, founding year, number of employees and whether it has a separate GEO page. We built the identity record to meet these fields in a verifiable way.

Content: does the page actually answer a question?

The unit AI engines quote is often a paragraph. That is why in our articles we build each subheading like a sentence a customer would ask and put the answer in the first paragraph directly under the heading. Every article ends with a five-question FAQ block; during the build this block is parsed and turned into an article-specific FAQPage schema.

We later had to correct the reasoning behind this schema. When we started, what we expected was Google's FAQ rich result; Google removed this result type on 7 May 2026. We kept the schema anyway: the FAQ text sits on the page as HTML, and the schema is a machine-readable copy of the same text. But we no longer expect any visual gain on the search results page.

The same audit revealed that two articles had no FAQ block at all. When the parser could not find the heading, it collected bold lines ending in a question mark from the last part of the article; the schema for those two articles was generated not from a real FAQ but from random lines in the body. A real FAQ block was written for each of them.

There was also a clean-up. The site's interface text contained eight unsourced performance claims; the home page also carried four numerical badges. There was no measurement behind any of them. All were replaced with qualitative wording. A figure without a source gives wrong information to the reader and to an AI engine alike.

We had given the same keyword to two pages

If a keyword appears in the target lists of two pages at once, the two pages suppress each other on the same query. In the first count we found that six Turkish keywords had double ownership among the articles, and we left each pair to the article that covers the topic in depth in its body.

Then we realised the count itself was incomplete. The first problem was letter case: the uppercase and lowercase versions of the same phrase had been counted as separate keywords, whereas for a search engine they are the same. The second was scope: only the article file had been counted. Once the sector, service and GEO agency pages and the meta records of the static pages were included, the count expanded to five files and double ownership showed up as nine Turkish and fifteen English pairs. All the pairs an article was party to were closed.

One part remains open, and we are writing that down too. Overlaps between two pages (such as the home page and a service page carrying the same keyword) were left in place deliberately; the decision is pending because it would change the design of the home page's meta. The rule, however, is now clear: the service page takes the purchase-intent keyword, the article takes the informational one.

Two languages: why are the English pages at separate addresses?

In the previous setup Turkish and English shared the same address; the language preference was stored in the browser. Because all of the pre-generated HTML was in Turkish, the English content never reached search engines. Now the language is read from the address: /geo-ajansi is Turkish, /en/geo-agency is English. No English address is generated for content that has not been translated.

The two pages point to each other with reciprocal hreflang tags; because a one-way declaration is ignored, reciprocity is required. On 11 September 2026 we checked both addresses: the Turkish page arrives with lang="tr" and carries tr, en and x-default links; the English page returns the same three links.

Speed: moving the fonts onto our own server

On the speed side, the clearest change we measured was the font decision. At first the site pulled its fonts from Google Fonts: one domain name lookup, one secure connection, one CSS request and four files, 202 KB in total. In Lighthouse, removing that connection alone and serving the fonts from our own server brought First Contentful Paint (FCP) down from 3.7 seconds to 2.2 seconds, and layout shift (CLS) from 0.036 to zero.

The two files were subset to hold the full Turkish character set; their sizes are 37 KB and 35 KB. These figures are lab measurements; we have not yet taken field measurements from real users.

Two things we deliberately did not do

The first is city pages. For the query "İstanbul diş kliniği SEO ajansı" (Istanbul dental clinic SEO agency), none of the seven results returned had a city name in its address; the query was being answered by general service pages. In queries where providers carrying the city name in their domain did appear, the signal came not from the address but from physical presence in that city. The agency's physical presence is only in Kahramanmaraş. Opening a page in the name of another city without an office or regular on-site presence there would be an unverifiable claim. What is missing for Kahramanmaraş is not a page but a Google Business Profile listing.

The second is profiles that do not exist: sameAs will be filled only when a real profile is opened.

The mistakes we made and how we found them

This section is the most important part of the log. What the four mistakes have in common is that all of them stayed live for a while.

The footer was invisible on 161 pages

An animation marker had been added by hand to the link columns at the bottom of the page. A style rule made any element carrying this marker invisible at first; the observer that makes it visible, however, had never been attached to the footer. The rule applied only when the device's "reduce motion" setting was off. On the development computer this setting was on, so the footer looked normal. A user reported the problem on mobile. The animation marker is no longer written by hand; it is added only through the component that registers with the observer.

A raw placeholder sat on nine sector pages

On all nine Turkish sector pages the screen showed {ui.badge}; instead of the text, the placeholder itself was being printed. Because the English equivalent was correct, it went unnoticed for months. While the service pages were being worked on, someone looked at the same component, spotted the bug there and fixed it.

We had the wrong idea about who was sending the security header

The HSTS header, which tells the browser to enter the site only over a secure connection, was present in the live response, and we assumed Cloudflare was sending it. In fact the previous hosting provider had been sending it. After we left that provider, a live measurement showed the header had disappeared, and the header was added to our own configuration file. On 11 September 2026 the header is in place in the response.

We counted meta description length wrong

In one audit two descriptions appeared to be 165 and 162 characters; the limit is 160. But the count had been done without decoding the HTML-encoded form of the quotation mark: a six-byte code is a single character on screen. The real lengths were 155 and 152, meaning both descriptions were already within the limit and would have been shortened for no reason. Character counts are now made after the text is decoded.

How do we measure the result?

We put the method on record before the figures so that the origin of every figure given can be questioned. It has four parts.

  • A fixed question set. An unchanging list made up of questions customers actually ask in the sectors we serve.
  • Engine coverage. The same questions are asked one by one on ChatGPT, Gemini, Perplexity and Google AI Overviews; the six clusters measured in this round cover only the first three engines, and Google AI Overviews is not included in them.
  • Date. Every round is recorded with its date, and the same set will be asked again at a regular interval.
  • Raw answer record. Not a summary score but the answer itself is stored: whether the brand was mentioned, whether the site was cited as a source.

On the analytics side, sessions coming from AI sources will be tracked separately. Which metrics to keep and how to set up the measurement log is explained in the article on how to measure AI visibility. The result of the six measurement clusters taken with this method is published on the GEO Visibility Index page. We were mentioned by name in 12 of 179 valid cells; 8 of those are cells where the question already contained our brand name, so they are not a discovery. In questions that did not contain our brand name, our name appeared in 4 cells: on ChatGPT, in the two runs of the question about an affordable GEO agency for a small business (source: our GEO pricing page); on Perplexity, in one run of the question about agencies providing GEO or SEO services in Kahramanmaraş (first in the list, source: our about page); and on ChatGPT, in one run of the English question about which agencies provide GEO services in Türkiye (fifth row of a ten-agency table). The last two did not repeat in the other run of the same question, so this visibility is unstable rather than won. Our name did not appear on the pricing questions, but in 6 cells the answer cited our site without naming us: 4 cells on ChatGPT and 2 on Gemini. This count was taken with a single account per engine and two runs and does not rank agencies by quality; 179 of the 180 planned cells are valid, and the single missing cell hit Perplexity's free search limit.

The checklist this log gives you for your own site

The part of the log you can adapt for yourself comes down to six items:

  1. Send a request with a bot's name and check whether you get the same status code and size as a browser does.
  2. Check whether the heading and body text are present in the page's raw source without JavaScript running.
  3. Look at whether a setting that blocks AI bots is switched on in your CDN or security dashboard.
  4. Confirm that every piece of information in your schema is also visible on the page; do not list a profile that does not exist.
  5. Make sure every figure on your site has a source; remove the ones that do not.
  6. Run your audit not with a single device setting but with different settings too; our footer bug hid behind a single accessibility setting.

If you would like to apply this list with a team, you can see the six work items and four phases on our GEO agency page. If you would rather talk about your own situation first, you can start from the contact page for a free business analysis.

Frequently Asked Questions

Is this article a GEO case study?

Partly. It describes the implementation side of a GEO project: the work done, the measurement methods and the mistakes. The results side is limited: in the six measurement clusters on 16, 17 and 18 September 2026, Next GEO Agency was mentioned by name in 12 of 179 valid answers from ChatGPT, Gemini and Perplexity; in 8 of those the question already contained the brand name, the mentions in questions without the brand name came to 4 answers, and two of those four did not repeat in the other run of the same question. In 6 answers nextgeoagency.com was cited without the name. Google AI Overviews is not included in these clusters, each engine was measured with a single account and two runs, and there is no traffic or conversion data. The article will be updated as the measurement is repeated.

Why don't you give traffic and conversion figures?

Because we do not have a measured result for either. The only figures we give for visibility in AI answers are the counts from the six measurement clusters, taken with a single account per engine and two runs: a mention by name in 12 of 179 answers — in 8 of those the question already contained our brand name — and a citation without our name in 6. Those figures are not a quality ranking or a lasting indicator of visibility. Writing an estimated figure for traffic or conversions would also lower the credibility of the verifiable information in the rest of this log.

Your bot test came back 200 — does that mean AI engines read your site?

No. A 200 code shows that the server delivered the page in full to a request carrying the bot's name. Only server access logs can prove that a real bot actually came to the site; whether an engine uses the page in its answers is a separate matter of measurement.

Isn't leaving the sameAs field in the schema empty a disadvantage?

As long as there is no profile, no; writing a profile that does not exist is a bigger problem. If the link written into the schema cannot be verified, the machine has been given wrong information. When a real profile is opened, the field will be filled and the same information made visible on the page as well.

Do these practices apply to every site?

The access and identity checks apply to most sites: bots seeing content in the raw HTML, permissions not being broken at the network layer, the schema being consistent with the page. Decisions such as not opening city pages or serving fonts from our own server, however, rest on our own measurements; do not apply them without making the same measurements.