
SEO + AEO ENGINEERING
WE BUILT A SITE AI ASSISTANTS CAN ACTUALLY READ.
126 pages. A clean-Markdown twin of every one of them. One entity graph instead of 126 orphan claims. Here is the whole method, including what it could not do.
DISCLOSURE, UP FRONT
ALTAPRO AI IS OUR SIBLING COMPANY.
Same founder, different business. We say that first because it changes how you should read what follows.
What it costs us: we cannot point at an arm’s-length client and say they chose this. What it buys you: total access. We are showing you the actual architecture, file by file, because we own it — there is no vendor between you and the method and nothing here is a black box we are protecting.
This is a case study about method. Where we have outcome numbers we label them and say where they come from. Where we do not, we say so rather than fill the space — which is why the results section below reads the way it does.
THE PROBLEM
A RANKED LIST AND A GENERATED ANSWER ARE TWO DIFFERENT COMPETITIONS.
AltaPro AI sells custom operational software to established Alberta businesses. The buyer is an owner or an operations lead with a process problem, and increasingly that buyer does not open a search engine and scroll. They ask an assistant some version of “who builds custom software for contractors in Alberta?” and take the two or three names it returns.
A ranked list rewards the page that best matches a query. A generated answer rewards the entity the model is most confident about and the source it finds easiest to quote. Those are two different builds:
Confidence in the entity. A model has to believe AltaPro AI is a real, specific, disambiguated company — not a string that might be a similarly-named electrical contractor at a neighbouring domain.
Ease of quoting. A model has to be able to extract a specific, attributable claim. A React marketing page is navigation, footer, a chat widget, animation wrappers, and the actual claim buried somewhere in the middle.
Neither is solved by writing more blog posts.
WHAT WAS BUILT
COUNTED FROM THE REPOSITORY, NOT ESTIMATED.
Every figure below is a count taken from the AltaPro codebase on 23 September 2026. They describe what exists. None of them is a result, and none should be read as one.
126
pages
the size of the site the work was done on
142
routes in one registry
the same list drives the sitemap and the Markdown-twin allow-list
12
AI crawlers named and allowed
individually, in robots.ts, rather than by wildcard
37
schema.org types in use
including HowTo, DefinedTermSet and SpeakableSpecification
584
lines of internal-link map
covering 84 pages, rendered on 32
812
lines of llms.txt + llms-full.txt
maintained like pages, not generated and forgotten
01
A CLEAN-MARKDOWN TWIN OF EVERY PAGE.
Every page is mirrored at <path>/md and served as text/markdown. The important part is how the twin is made. It is not a second copy of the copy, hand-maintained alongside the page. The route renders the real page on the same deployment, strips header, nav, footer, scripts and styles, and converts what is left to Markdown. The twin is the page. It cannot drift, because there is nothing to drift from.
Each twin carries a title, a one-line description, its own canonical URL stated in the body, a provenance line explaining what it is, the content, and an attribution footer — so a model that quotes a twin can attribute the claim to the right URL.
Built from a 113-line orchestrator, a 491-line dependency-free HTML-to-Markdown converter written for this site’s markup, and eight thin route files. The route registry that drives the sitemap is the same list that drives the twin allow-list, so a page cannot be in one and missing from the other.
A detail that cost a day and is worth stealing: the internal render must refuse to follow redirects. Otherwise the twin of a retired URL quietly mirrors whatever that URL now points at, and you have published a page claiming to be something it is not. A twin must be the page living at that exact URL.
02
ONE ENTITY, STATED ONCE.
Every brand fact — name, address, phone, area served, what the company knows about, who founded it, what else it is called, what it is not — lives in a single module and is emitted as one canonical organization node referenced by ID from every other schema node on the site. Pages reference the entity; they never re-type it.
One node, not two. The organization is typed as both an Organization and a ProfessionalService, which is a LocalBusiness subtype, so one node carries the brand identity and the local signals together. The site originally shipped a second business node on the homepage on top of it. We removed it. Two nodes describing one company is split-entity risk, not extra signal.
Explicit disambiguation. One short line in the graph stating which entity this is and which similarly-named company it is not. One line — deliberately not an enumeration of every competitor, because a list of rivals in your own graph reads as competitor copy and hands those entities free association with yours.
A real external identity. The node carries a Wikidata item, declared both as a link and as a structured identifier. Wikidata is the structured facts database the knowledge graphs and answer engines reconcile entities against, and declaring the identifier from your own graph closes the loop between your self-claim and theirs.
03
INTERNAL LINKING WAS THE BIGGEST FINDING.
A crawl of the site’s 19 hub and navigation pages found 37 of 161 sitemap URLs reachable from none of them.
The cause was not laziness. The site navigation was a client-side component whose dropdown children only mounted on hover — so those links were never in the served HTML, and a crawler never saw them. The footer and in-page links were the only crawlable link surfaces on the site.
The fix was a 584-line internal-link map covering 84 pages, each with a label and a one-line description, grouped into clusters and exposed as a server-rendered block. Two rules keep it honest: it may never link a URL that redirects, and a description may not contain a claim that is not already on the page it describes.
This site had the identical defect, found while writing this page. It is fixed here too — which is the only reason we are comfortable publishing the finding.
DECISIONS
THE ONES WE WOULD DEFEND.
We wrote our own HTML-to-Markdown converter. 491 lines, no dependencies. A general-purpose converter plus a DOM implementation would have added megabytes to a route that runs on every twin request, to handle markup this site does not emit.
We did not chase page count.The site’s own diagnosis named templated thinness as the cause of its indexation problems. The build spent its effort making existing pages reachable, quotable and schema-complete before adding more.
We treated “what we have not done” as content.Each industry page states plainly what the company has not built in that sector and what adjacent work transfers. And the inverse: there is deliberately no “have you built for this industry before?” FAQ anywhere, because FAQs become FAQPage schema, and that question would ship a machine-readable statement about your gaps straight into the answer engines.
We published no fabricated ratings. There is no self-authored aggregate rating on the organization node. Review markup you write about yourself is worth nothing and risks having your rich results pulled.
RESULTS
THIS IS WHERE THE NUMBERS WOULD GO.
We have not published outcome numbers for this build, and we would rather say that plainly than show you something shaped like a result. The repository proves what was built. It does not record what it returned — traffic, indexation, citation share and lead volume all live in Search Console, server logs and analytics, not in code.
When they are published here they will carry the tool they came from, the date range, and a before as well as an after. If something else shipped in the same window that could explain the change, that will be said too.
You are reading a page that could have had five impressive percentages on it in about ten minutes. The reason it does not is the same reason the rest of this site publishes its prices and refuses to promise a result.
What is true today and can be stated now: the site is structurally complete for AI retrieval. Every page has a machine-readable twin, every page resolves to one canonical entity, that entity is reconciled against Wikidata, and the AI crawlers are named and allowed. Those are the preconditions for being cited. Being cited is then a function of authority — and authority is earned off your own domain.
THE HONEST HALF
WHAT THIS BUILD COULD NOT DO ON ITS OWN.
Everything above is on-domain engineering. It makes a site citable. It does not make it cited. Language models weight third-party corroboration far above self-claims, and an entity that only asserts things about itself is an entity a model hedges on.
The work that has to happen off the domain, which no amount of schema replaces:
- —Third-party profiles with real content, and byte-identical name, address and phone on every one of them.
- —Genuine reviews on Google Business Profile and the directories — reviews other people write about you, not markup you write about yourself.
- —Real links from real, topically-relevant sites, including credit links on the sites you build.
- —Local institutional presence: chambers of commerce, regional business and technology directories.
- —Original, citable material of your own — data or research a model has a reason to quote.
We sequence it deliberately. The on-domain engineering is a one-time pass with a defined end, and it is the thing that makes every off-domain citation land on a site an assistant can read. Doing the citations first, into a site with no entity graph and no machine-readable surface, wastes them.
That pass is what we sell as the AEO engineering pass — $1,500 to $2,000, one time — and the search half is the SEO pass at the same price.
FAQ
QUESTIONS ABOUT THIS BUILD.
What is AEO, and how is it different from SEO?
+
SEO competes for a position in a ranked list of links. AEO — answer engine optimization — competes to be the source a model quotes when it generates an answer instead of a list. The artifacts are different: SEO work targets crawlability, relevance and authority; AEO work targets entity clarity, extractable claims and machine-readable formats. Most businesses need both, and the technical foundations overlap by maybe half.
What is a Markdown twin?
+
A clean, plain-text mirror of a web page, served at the same URL with /md appended and delivered as text/markdown. It contains the page's real content with the navigation, footer, scripts and interface chrome removed, so a language model reading it gets the claims rather than the markup. On the AltaPro build the twin is generated from the live page itself, so it cannot fall out of sync with what visitors see.
What is llms.txt?
+
A plain-text file at the root of a site that tells AI systems what the business is, what it sells and which pages matter, in a format built for machine reading rather than for browsers. It is a proposed convention rather than a ratified standard, and the evidence for how much weight it carries is still thin — we publish one because it is cheap, it is honest, and it costs nothing if it turns out not to matter.
Do I need 126 pages for this to work?
+
No, and page count was not the lever. The AltaPro site happens to be that size; the work that mattered was making the pages that already existed reachable, quotable and attached to one clear entity. On that build, one of the highest-impact findings was that 37 URLs in the sitemap were reachable from no navigation page at all — a linking problem, not a volume problem.
Will this get my business recommended by ChatGPT?
+
It removes the technical reasons you would not be. Being recommended also depends on authority a model can see off your own domain — directory profiles, real reviews, real links, real mentions — and that part is earned rather than engineered. We will tell you which of the two is actually your constraint before you buy anything. There is no guarantee attached to this work.
How long does it take to show up?
+
Clients typically see movement in 14 to 90 days, measured against a baseline captured before the work starts. That is a typical-results claim, not a guarantee — we do not promise citations, rankings or recommendations, and for work that depends on third-party systems refreshing on their own schedules that distinction is not merely cautious phrasing.

WANT TO KNOW IF AN ASSISTANT CAN READ YOUR SITE?
The same first step we ran on AltaPro AI: what your entity looks like to a machine, what is reachable, and which of the two — technical foundation or off-domain authority — is actually holding you back.
Book a Free Call