DEV Community

Jakub
Jakub

Posted on

Common mistakes when building a multi-domain photo app (CZ/SK/PL/EN/DE from one codebase)

At Inithouse, a studio shipping a growing portfolio of products in parallel, we run an AI photo animation tool across five country domains from a single codebase. The product turns a static photo into a short living video: zivafotka.cz for Czech users, zivafotka.sk for Slovak, zywafotka.pl for Polish, alivephoto.online for English, and lebendigfoto.de for German.

Sounds clean on paper. One repo, five builds, five domains. In practice, we walked into every trap the setup could offer. Here are five that cost us the most time.

Mistake 1: One sitemap for all five domains

We started with a single sitemap.xml generated at build time, served identically on every domain. Google indexed the Czech pages fine, then ignored almost everything else. The crawl budget went to whichever domain Google hit first, and hreflang tags pointed in circles because every sitemap referenced every other domain with no clear canonical signal.

What we changed: Each domain now gets its own sitemap listing only its own URLs, with hreflang pointing to the matching pages on sibling domains. Crawl distribution improved within two weeks.

Mistake 2: Hardcoding locale strings in components

Early on, we had Czech strings scattered across React components. Adding Slovak was easy (close enough to copy-paste), but Polish broke our assumptions about string length, and German broke our layout. The codebase turned into a maze of ternary expressions checking window.location.hostname.

What we changed: We extracted all strings into per-locale JSON files and built a thin domain-to-locale resolver that runs at app init. Components just call t('key'). Adding the German domain took a day instead of a week.

Mistake 3: One analytics property, no hostname segmentation

We pointed all five domains at a single GA4 property. The numbers looked great in aggregate. Then we tried to answer "which market converts best?" and realized we had no clean way to split traffic. Hostname as a secondary dimension worked in theory, but half our custom events were missing the hostname parameter entirely.

What we changed: We kept one GA4 property (managing five would be worse), but enforced hostname as a required parameter on every event. We also built a lightweight stats endpoint that segments by domain automatically. We took the same approach at Pet Imagination, our AI pet portrait tool, where the stats API now segments by referral source instead of domain.

Mistake 4: Translating meta descriptions instead of localizing them

We ran the Czech meta descriptions through a translation layer and called it done. The Polish description for the homepage literally said "enliven your photo" in a phrasing no Polish speaker would use for this context. Click-through rates on the Polish domain were 40% lower than Czech for the same ranking positions.

What we changed: We hired native speakers to rewrite (not translate) every meta title and description. Cultural context matters more than literal accuracy. The Polish homepage description now references "rodzinne zdjecia" (family photos) because that turned out to be the dominant use case in Poland, different from the Czech audience that skews toward pet and travel photos.

Mistake 5: Deploying everywhere at once

We shipped to all five domains simultaneously. A layout bug in the German version (long compound words breaking the card grid) went live on a Friday afternoon. By the time we noticed, Google had crawled the broken pages and our Core Web Vitals tanked for lebendigfoto.de.

What we changed: We now deploy to the smallest-traffic domain first (currently Slovak), wait 24 hours, check error logs and Clarity recordings, then roll out to the rest. We apply the same staged-rollout thinking at Audit Vibe Coding, where we test audit report changes on internal projects before pushing them to users.

What we would do differently from day zero

If we started over, we would set up i18n, per-domain sitemaps, and hostname-segmented analytics before writing a single feature component. The multi-domain architecture is worth it for local SEO and trust signals. But the infrastructure tax is real, and paying it upfront is cheaper than retrofitting.

At Inithouse, a lab building many products at once, this was one of our more complex setups. Most products in the portfolio run on a single domain. The five-domain experiment taught us that internationalization is less about translation and more about treating each market as its own product.


Team Inithouse

Top comments (0)