SEO with Compose for Web (WASM) - what are we real...
# compose-web
s
SEO with Compose for Web (WASM) - what are we realistically supposed to do? I'm building a KMP app (Android + iOS with Compose Multiplatform) and considering adding a web target. SEO is crucial for my use case - it's a consumer-facing product, and organic search is the main way users find us. The issue: Compose for Web renders everything on a
<canvas>
via Skia/WASM. Google's crawler sees an empty page - no text, links, headings, or semantic HTML. For any business reliant on SEO, this is a serious problem. I've been exploring alternatives that let me stay in Kotlin and reuse my commonMain business logic (repositories, models, API clients, mappers): 1. Ktor + kotlinx.html + HTMX + Tailwind CSS - Server-rendered HTML, ideal for SEO, all Kotlin. Ktor 3.2 even offers an official HTMX module. This seems the most mature option. 2. Kobweb - Compose HTML with SSG, but I've heard it can be complicated to set up. 3. Kilua - Compose Runtime-based with SSR support, but it's still in early stages. My questions for the community: - Are there any plans from JetBrains to improve SEO for Compose for Web? (e.g., SSR support, HTML fallback, pre-rendering?) - Has anyone launched a production website with SEO requirements using any of these approaches? What was your experience? - For those who chose Ktor + HTMX over Compose for Web for SEO reasons - how much of your KMP code could you share? Would love to hear how others are managing this. It seems like a gap in the KMP story - we can share code across Android, iOS, desktop, and web, but the web target isn’t indexable by search engines
👍 1
s
what exactly is the nature of your SEO relevant data? if this is something static and fine to update at build time you can totally get away with SSG. if it's more dynamic things are getting more complicated. regarding kobweb, SSG is done by default, setting up the code generation shouldn't be that complicated. SSR however, is not built in and definitely more complex to get working. kilua is the successor to kvision, which has been around for some time. all of these options are quite "early stages" compared to anything js, but that might revise your opinion of kilua a little.
s
Thanks for the input! The data is semi-dynamic - it's a content catalogue that grows regularly with new entries, but individual pages don't change much once published. So, SSG could work for the detail pages, but things like search results, filtered listings, and pagination are more dynamic. Good call on Kobweb SSG as the default - I'll take a closer look at it for the static content pages. My hesitation was mostly around how much it diverges from standard Compose MP patterns and the overall DX, but if SSG handles the pages I actually need Google to index, that could be enough. And fair point on Kilua being the successor to KVision - that does give it more history than I initially realised. I'll revisit it with that context. In our case, we're currently leaning towards Ktor + kotlinx.html + HTMX + Tailwind, since it handles both static and dynamic pages (search, filtering, infinite scroll) with a single consistent approach. Ktor 3.2's official HTMX module makes it feel like a first-class path from JetBrains. The main benefit is being able to add a jvmMain target to the existing KMP project and directly import ~80% of the data layer from commonMain - no need to publish shared libraries or duplicate models. Anders Sveen's KotlinConf 2025 talk on this exact pattern was very helpful for anyone exploring this route:

https://youtu.be/AlGWsTXnWsY

Still curious if anyone from JetBrains has thoughts on SSR or pre-rendering for Compose for Web down the road - it feels like it would unlock many use cases for the ecosystem.
s
compose for web does actually use html elements behind the canvas for accessibility reasons, so there is something to index, but realistically if SEO and indexing are crucial you will never get anywhere with a canvas. Flutter never solved this either.
s
I think Ktor + kotlinx.html + HTMX is the most pragmatic approach for us. Rewrite the UI layer in server-rendered HTML (which is the minimal part anyway), and reuse the entire data layer - API clients, DTOs, mappers, domain models, data sources - directly from
commonMain
via a jvmMain target. No shared library publishing, no code duplication. The UI is the only part that changes, and honestly, for web SEO, you want semantic HTML anyway, not a UI framework abstraction. The maturity of each component is what convinced me
s
personally I'm using kobweb, with self baked SSR. my requirements are not that heavy though. I find the experience to be as good as it gets for a kotlin dev doing web. you can share everything up to viewmodels but at the end of the day it's targeting the web, so there's no way around some html and css. for a real product requiring ssr, ktor and htmx seem like the most solid choice, yeah
🙌 1
r
With Kilua or Kobweb on the frontend you can probably get better user experience than with Ktor and htmx. Because once the app is loaded in the browser it works fully client side with full reactivity and instant DOM updates. No need to refresh the page for every single action. It could be also easier to reuse existing API (designed for client side CMP application). With Kilua (I'm the author), you get SSR almost for free. If you have any questions don't hesitate to ask.
s
Thanks, Robert, I appreciate you stepping in! The SSR + client-side hydration approach is definitely appealing for UX. Once the app loads, having full client-side reactivity without server round-trips offers a clear advantage over HTMX, where every interaction hits the network. A couple of questions, if you don't mind: 1. Stability - I see Kilua is at v0.0.32, and the dependencies include things like Kotlin 2.3.10-RC, Compose 1.11.0-alpha02, etc. For a production app that real users rely on, how stable would you say the framework is at this point? Are there any breaking changes between minor versions, or is the API fairly settled? 2. SSR in practice - When you say SSR comes "almost for free," what does the setup actually look like? Is it just a config toggle, or is there wiring involved (Node.js server, hydration config, etc.)? 3. Scale of adoption - Are there any production sites using Kilua with SSR that we could look at? It would help to see it in action. Not trying to be sceptical - the tech looks genuinely promising, and having Compose Runtime as the foundation is a huge plus for KMP developers. Just trying to gauge production readiness since we'd be shipping this to real users
r
The project API is quite stable. But it relies on components, which are definitely not yet stable. Kotlin Wasm is in beta, Wasm-JS interoperability is experimental, kotlin-wrappers project (one of key dependencies) likes to change a lot between releases. So I can't lie Kilua is stable - it's not and breaking changes are still to be expected. Having said that - I personally use Kilua in production without problems 🙂
You can check Kilua website with SSR hosted on Render. Sources are available.
There are commercial apps created with Kilua and running in production with SSR - https://mkatowice.sygnalista.finn.pl/
I've tried to describe SSR architecture and configuration as detailed as I could, so instead of repeating myself - please just take a look at the guide.
s
Really appreciate the honesty about stability I reviewed the docs, and the Compose world explainer is very well done - the distinction between Compose Runtime, Compose HTML, and Compose Web clears up a lot of confusion in the ecosystem. The fact that Kilua is essentially a ground-up rewrite of Compose HTML with Wasm support and SSR baked in is impressive. The SSR plus hydration model is clearly a better UX pattern compared to HTMX - no argument there. After the initial server-rendered load, full client-side reactivity without round trips is how modern web development should work. Currently, our main hesitation for a production launch is the chain of pre-release dependencies (Kotlin RC, Compose alpha). But I will genuinely keep Kilua on our radar - once the underlying dependencies stabilise and the version approaches something closer to 1.0, it could be the ideal KMP web solution. The Compose Runtime foundation, real DOM, SSR, and Tailwind support tick every box. Thanks for building this - the Kotlin web ecosystem really needs frameworks like this
s
If you are adopting Material Design, I am trying an alternative approach by providing both the Wasm site for better animation and the Compose HTML side for compatibility for now. See https://kotlinlang.slack.com/archives/C0BJ0GTE2/p1775569775314949 which is based on Material Web and Kobweb. I wouldn't say this is production grade now but you are welcome to give it a try.
240 Views