Hi everyone!
A huge thank you to Joyce from the WeWeb Team for bringing this issue to my attention. She mentioned that metadata on dynamic pages is one of the biggest pain points for self-hosting users right now, and after looking through the community threads, I could see exactly what she meant.
So I built something to help: @mel000000**/weweb-dynamic-metadata** β a build-time tool that generates unique SEO metadata for every dynamic page in a WeWeb project.
What it does:
-
Pulls metadata (titles, descriptions, OG images) directly from your Supabase tables
-
Creates a central metadata file and injects it into your WeWeb export
-
Gives every dynamic page (like
/article/1,/article/2) its own unique SEO tags -
Works with both static and dynamic collections
Why this matters:
-
No Cloudflare Workers or serverless functions needed -
Zero runtime overhead β everything pre-generated at build time -
Keep using dynamic collections (new content appears instantly) -
Completely free and open-source
For Supabase users: It connects directly to your database views, so you control exactly what metadata gets pulled per page.
Quick setup:
bash
npm install --save-dev @mel000000/weweb-dynamic-metadata
Add a config file pointing to your Supabase table, then run it after your exports:
bash
npx @mel000000/weweb-metadata
A quick note: I know this isnβt a one-size-fits-all solution. If you have thousands of pages that change constantly, a build-time approach might not be the right fit. But for projects with stable content that just needs proper SEO β blogs, documentation sites, marketing pages β Iβm hoping this can save some of you the headaches Iβve seen in the community threads.
The result: Each article page gets its own title, meta description, and Open Graph tags. Crawlers see unique content, social shares look right, and you keep all the WeWeb flexibility.
The project is open-source on GitHub: github.com/Mel000000/weweb-dynamic-metadata
Would love feedback, bug reports, or ideas for improvement. If you give it a try, let me know how it goes!