Back to Blog

Why your real product should not live on a builder's infrastructure

By Maria Catalina Kovacs · 19 September 2026 · 10 min read

It is a good place to think, but a bad place to be responsible.

A year ago builders were everywhere. I was hyped too. This is what I have learned in the past year: an AI builder is a good place to think and a very bad place to be responsible.

The site looked finished

I want to be careful about how I say this, because the easy version of this post is wrong. The easy version is that the tools are bad, and they are not. I built my company's website inside one, alone and quickly, and the result was good enough that I was proud of it. That matters to the argument, so I am saying it before anything else. What follows is only what I found when I finally looked at my own site the way I would look at a client's.

The words on my pages only existed after JavaScript had run, which meant that everything that does not run JavaScript was being handed an empty shell where a Vienna consultancy should be. LinkedIn saw nothing. WhatsApp saw nothing. Most of the AI crawlers that are quietly deciding what the internet says about your company saw nothing either. Google renders JavaScript, so Google was fine, and because Google was fine I did not think to check the others for months.

That much is a property of client-rendered applications in general and not the invention of any one platform, so I want to keep the claim narrow: the builder shipped that output and offered me no way to change it.

The page head was not really mine either. Meta tags I wrote in `index.html` never reached a visitor, because the platform composed its own at publish time from a template. For a while every link I shared previewed with the platform's default title and the platform's logo, which I discovered the way you discover a typo on a business card, after handing out fifty of them. All of that was irritating rather than serious, and none of it is why I left.

What one page view actually did

On 18 September I opened my own home page in Chrome and read the resource timings and the local storage, which is a thing I had done for clients and never once done for myself.

In a single page view, with no interaction beyond leaving the tab open, there were 187 calls to a session-recording ingest endpoint over 208 seconds. That is roughly one per second, continuously, for as long as anybody stays on the page. Four more calls went to an analytics batch endpoint. Three identifiers were written into the visitor's local storage with no expiry, and two third-party hosts were contacted, the platform's object storage and a public CDN, both of which therefore receive the IP address of every person who visits. There was no cookie banner, no consent request, and nothing anywhere on the site that mentioned any of it.

I should be exact about what I am and am not saying, because being exact is more or less the whole job. The endpoint is named session recording and it fires about once a second. I did not inspect what it transmits, so I will not tell you that it captures keystrokes or form input; I have no evidence of that and neither does anyone else who has only looked from outside. What I can state is the name of the endpoint, the frequency, the volume of data, and the identifier left sitting on the device of every person who came to read about my company.

Why I could not simply switch it off

My first instinct was to find the setting, and there was no setting. My second was to find the code, and this is where the evening changed direction.

I searched the entire codebase for the endpoint, then for the analytics calls, then for the storage host, and found nothing at all. Not a line. It was not in my source because it was injected at build time by the platform's build plugin, which means it did not exist until the platform compiled my site, and by the time it existed it was already inside the file that every visitor downloads.

You cannot remove what is not in your code. This is not a story about failing to find the right toggle, or about somebody who should have read the documentation more carefully. There was nothing to delete, because the thing did not exist anywhere I was permitted to work. It came into being at precisely the moment I lost the ability to inspect it, and I think that is the part other engineers should sit with for a minute, because it is not a bug and it will not be fixed.

Where was any of this processed

I could not establish it. Not the country, not even approximately, and that sounds like an administrative detail right up until the moment you sit down to write a privacy policy and discover there is a sentence in it you have no way of completing.

It was not that anybody was hiding it from me. It was structure, and you can see the structure in your own DNS records if you go and count the layers. My domain pointed at the builder, the builder ran on a hosting provider, that provider ran on somebody else's cloud, and the images came from a fourth company's object storage. Four parties stood between me and the hardware and I had a contract with exactly one of them. The chain was the answer.

Which is why I now say to clients, more often than they enjoy hearing it, that "it runs on AWS" is not a compliance answer. Before, the path ran from me to a builder, from the builder to a host, from the host to somebody else's cloud, and finally to a region that nobody could name. Today it runs from me to AWS, into a region I chose because I chose it, under a processing agreement I can produce if somebody asks. It may well be the same hardware. It is an entirely different legal position, and the difference is not technical.

Who answers for it

Here is the part that builders do not put on the pricing page, and it is not their fault that it is true. Under the GDPR the person running the site is the controller, which in this case was not the platform but me, and whatever was switched on by default I was the one who answered for it.

Article 13 says visitors have to be told before their data is processed, and they were not. Section 165(3) of the Austrian Telecommunications Act, which is how the ePrivacy rules reach me here, says that storing a persistent identifier on somebody's device when it is not strictly necessary for the service requires their consent first, and nobody was asked. Article 28 requires a processing agreement with any processor, Article 30 requires records that say where processing happens, and session replay is behavioural monitoring, which supervisory authorities treat as higher-risk processing rather than as a detail.

What that adds up to is an obligation I had no way of discharging. I could not disclose what I could not inspect, could not obtain consent for something I could not switch off, and could not name a region I had no way of establishing. The privacy policy on my own website, the one with my signature behind it, could not be made true by any action available to me. I spend my working life advising other people on AI governance, and I was doing it from a page that recorded its visitors without asking them.

The fair version, and I mean it

This page was designed and written in it, fast, by one person, and it's good. The argument isn't that builders are bad. It's that a builder is a good place to think and a bad place to be responsible — because production is a promise to other people, and a promise can't rest on infrastructure that changes under you without your consent.

What the move actually took

One evening, which is the detail I find hardest to let go of. Export the project, strip out the platform's runtime, prerender every route into real HTML so that sixteen pages in two languages arrive with their words already in them, and put the files in private storage in Frankfurt behind a CDN. The design did not change, the words did not change, the icons did not change, and no visitor could tell you what happened. What changed is that there are now no third-party requests at all, no cookies, no analytics, no session recording, and a bill of about €50 a month became a bill of under €1.

Governance you can actually fail

The part I am proudest of is not the migration, it is the thing that now stands behind it. The deployment pipeline refuses to publish if the platform's runtime, its storage host, the session-recording endpoint or the analytics endpoint appears anywhere in what visitors download, and it refuses if my company name is missing from the Impressum when the page is fetched with JavaScript turned off. So the sentence in my privacy policy about no cookies, no analytics and no tracking has stopped being a promise and become a build failure, which is what I think governance is supposed to look like once somebody actually implements it. Not a policy document. A test that fails.

There is a list of deployment runs in my repository now, some of them red and some of them green, and I have stopped reading the red ones as failures. A red mark means that something which was not entirely mine did not reach anybody. A green one means it reached them after I had checked it. I do not have a better definition of governance than that, and it took a column on a screen to teach me rather than a framework.

Two things that cost me an afternoon, which you can have for nothing. The first is to check the thing that checks: my original version of that gate scanned only the HTML and not the JavaScript bundle, which is the file visitors actually run, so it passed happily while the very string it was hunting sat in the bundle, folded back together by the minifier. A control you have never tried to defeat is not a control, it is a decoration. The second is that a gate which cries wolf is worse than no gate at all. Mine later reported a failure that had not happened, because one connection was dropped, the response came back empty, and the check concluded that my structured data had disappeared. Fixing that took twenty minutes and I stopped everything to do it, because the alarm I would have learned to ignore is the one that matters.

What I would tell someone starting now

Keep the builder, and use it for the things it is genuinely good at: moving fast, changing your mind, trying an idea out before it has earned a repository, thinking out loud in something that answers back. I still keep one myself, on its own subdomain, for exactly that. Then take the thing that carries your name, the one other people are trusting, the one with a privacy policy signed by you, and put it somewhere you can answer for.

Between an idea that works and that same idea being served to other people there is a gap, and the gap is where the responsibility starts. Crossing it in a single afternoon is exactly what these tools are for and I would not give that up. Forgetting that the crossing happened at all is what put me where I was.

The line was never between good tools and bad tools. It runs between a place to think and a place to be responsible, and a builder is a very good place to think.

Happy coding.

MK!

Maria Catalina Kovacs