Elke GEO-tool kan een zichtbaarheidsgrafiek tekenen. Dat is de makkelijke helft, en daar houden de meeste op.
De moeilijke helft — de enige die een beslissing verandert — is wat er daarna op je eigen site gebeurde. Je merk werd genoemd in een AI-antwoord. Prima. Kwam er iemand? Kocht er iemand iets? Een grafiek die omhoog loopt terwijl er verder niets beweegt is een grafiek, geen signaal.
BrandTrace is mijn poging tot die tweede helft.
Wat GEO eigenlijk is
Generative Engine Optimization is het ongemakkelijke kleine broertje van SEO. Mensen stellen hun vraag steeds vaker aan ChatGPT, Gemini, Claude, Perplexity of Grok in plaats van in een zoekbalk, en het antwoord dat ze krijgen noemt sommige merken wel en andere niet. Ben jij een van de niet-genoemde, dan krijg je geen troostprijs op positie 11. Je bent gewoon afwezig.
Dat maakt drie vragen geld waard:
- Hoe vaak noemt een AI-antwoord jou, bij de vragen die je klanten daadwerkelijk stellen?
- Wie wordt er in plaats van jou genoemd?
- Uit welke bronnen putten die antwoorden — en zijn jouw pagina's überhaupt leesbaar voor de crawlers erachter?
De keten sluiten
BrandTrace houdt vier signalen bij elkaar voor dezelfde URL, in hetzelfde tijdvenster: een AI-antwoord citeerde een bron, een AI-bot crawlde die pagina, er kwam een sessie binnen vanaf een AI-oppervlak, er volgde een conversie.
Ik wil precies zijn over wat die claim inhoudt, want dit is waar GEO-tooling zichzelf meestal overschreeuwt. Vier signalen naast elkaar leggen is niet hetzelfde als bewijzen dat het ene het andere veroorzaakte. Causale attributie van een uitkomst aan een actie is een onopgelost probleem en ik heb het niet opgelost. Wat ik wel kan: voorkomen dat je vier tools naast elkaar openzet om te schatten of de lijnen op elkaar lijken.
Daar volgen twee dingen uit:
Eerstepartijsignaal wint van gevolgtrekking. Crawl-events, Search Console en SDK-sessies zijn grondwaarheid. Alles wat gemodelleerd of geschat is, staat als zodanig gelabeld. Als je kunt kiezen tussen afleiden en meten: meten.
Een inzicht moet eindigen in een actie. Een gap-score die niet leidt tot een specifieke pagina om te repareren is een onaffe feature, geen dashboardwidget.
Crawl-logs als bron
Koppel een Cloudflare Worker, of upload je serverlogs, en je ziet precies welke AI-bots welke pagina's ophaalden, hoe vaak, en welke statuscode ze terugkregen. Dit vind ik het direct nuttigste deel, en het deel waar verder niemand zich druk om lijkt te maken.
Het beantwoordt gênante vragen vroeg. Blokkeert een regel in robots.txt stiekem GPTBot? Heeft een deploy een week lang 404's aan een crawler zitten uitdelen? Is de pagina die je blijft optimaliseren er een die de crawler nooit heeft opgehaald?
Niets daarvan is afgeleid. Het is je eigen logregel.
De conversiekant
Een kleine pixel op je site stuurt pagina- en sessie-events naar een Go-ingestservice. Een doel benoemen is één aanroep in je eigen code:
brandtrace.track("signed_up")
Een standaardcatalogus plus soepele canonicalisatie maakt daar harde en zachte conversierapportage van, terug te leiden naar de sessie, de landingspagina, en het AI-antwoord dat die pagina citeerde.
Antwoordklaar zijn, en één keuze die ik verdedig
Genoemd worden door een AI-engine en er leesbaar voor zijn, zijn twee verschillende problemen.
Elke gecrawlde pagina krijgt een score op zeven signalen: crawler-toegang, gestructureerde data, leesbare inhoud, entiteitsduidelijkheid, koppenhiërarchie, llms.txt en citatiegereedheid. Het is bewust het enige onderdeel zonder voorwaarden vooraf — geen Search Console-koppeling, geen SDK-installatie. Een gecrawlde site is genoeg.
De score komt uit een kale, niet-gerenderde fetch in plaats van uit de headless render. Dat is een bewuste keuze en degene die ik het hardst zou verdedigen. De vraag die een crawler stelt is wat de HTML zegt voordat er JavaScript draait. Tegen de tijd dat Chromium klaar is, zien een lege single-page-app-schil en een server-gerenderde pagina er identiek uit — en een crawler wacht niet op Chromium.
Niet sturen op wat er nooit was
Een bronrapport dat citaten toont die het model uit trainingsdata verzon in plaats van van het web haalde, is erger dan geen rapport: het stuurt je op pad om een publicatie te benaderen die nooit geraadpleegd is.
Elk bronrapport draagt daarom een grounding-status. Bij ungrounded zijn de genoemde URL's gegenereerd en niet waargenomen, en is de juiste actie: geen. Het rapport zegt dat, in plaats van beide soorten citaten stilzwijgend als hetzelfde te presenteren.
Wat eronder zit
De API is FastAPI op een stapel domeinpakketten die niets van een webframework weten. De ingest is een aparte Go-service, omdat een pixelcollector en een rapportage-API tegengestelde dingen willen: de een moet niets weten en veel absorberen, de ander moet alles weten en zelden bevraagd worden.
Daartussen: Postgres, NATS JetStream, Valkey en een Playwright-crawler. Elke LLM-aanroep gaat via een interne gateway naar OpenRouter, getypeerd, gemeten en per plan-tier gerouteerd — wat als overhead klinkt tot je voor het eerst een maand modelkosten per klant moet verantwoorden.
De frontend is React en Vite, uitgeleverd als installeerbare PWA. Het draait op self-hosted k3s met SOPS-versleutelde secrets, traces naar SpanBarn, fouten naar BugBarn, productanalytics naar FunnelBarn. Dezelfde stack als alles wat ik verder draai.
Gebouwd voor bureaus
Bureaus zijn de vorm van de koper, dus zijn ze een eersteklas geval en geen enterprise-bijgedachte: één creditpool verdeeld over klantprojecten en direct herverdeeld als een klant vertrekt, modelkeuze per project zodat een klant die alleen ChatGPT wil niet voor vijf engines betaalt, multi-tenant isolatie met rollen per zetel, en bulk chat-export zodat je een klant het ruwe bewijs als CSV kunt geven.
Wat het niet doet
Twee dingen die ik vastgelegd wil hebben, want een eerdere versie van de README beweerde er één voordat de code bestond.
Er is geen briefinggenerator, geen conceptartikelgenerator, geen UGC-invalshoekgenerator en geen CMS-export. De generatieve helft blijft bij wat gebouwd is: een voorgestelde titel, een meta-omschrijving en één zelfstandige antwoordalinea voor een gemarkeerde pagina.
En de bureaufuncties — pitchprojecten en white-label — zijn gespecificeerd maar niet gebouwd. Dat is roadmap, geen gedrag.
Als een GEO-tool zegt dat hij alles doet, vraag dan welke helft hij je kan laten zien.