Landing Page Builder
[landing-page] [admin] [branding]
Your own landing page for your provider portal, built directly in licensio, with no external CMS needed. Drag & drop sections, branding from your provider, live preview.
Who it's for
Admins who want to provide a public marketing/sales page for their license portal. It appears under <tenant>.licensio.io/ as the default start page.
Step by step
1. Open the builder
Settings → Landing Page.
2. Add sections
Available section types:
- Hero : large headline banner with a call to action
- Text & Image (About) : text block next to an image
- Packages : automatically all packages with
show_in_join_preview=trueas a pricing table - Features : feature grid (up to 6 tiles)
- CTA : a call-to-action block (headline + button)
- Screenshots : framed screenshot/mockup block
- Carousel : image slider with auto-play (see notes below)
- Portal preview : a live preview of the portal (dashboard/products/assets/account)
Header and footer are configured separately and inherit the branding.
3. Drag & drop
Reorder sections with the mouse. The order is saved live.
4. Branding
Sections automatically inherit your provider branding (colors, font, logo). Via separate per-section branding options, background types can be changed (solid, gradient, image).
5. Live preview
The mobile/desktop toggle shows how the page looks on various devices. There are also portal preview arrows to page through the sections.
6. Publish
Click Save, and the page is live immediately under <tenant>.licensio.io/. No separate deploy step.
Sections in detail
Hero
- Headline (large)
- Subheadline (small)
- Primary button (text + link)
- Background type: color / gradient / image
Packages
Automatically shows all active packages of your provider where show_in_join_preview=true is set (toggle in the package settings). Each package card shows:
- Name + description
- Price (monthly + setup fee if applicable)
- Feature list (✓ "Unlimited downloads", "Up to 3 printers", "CRM integration", depending on the feature flags)
- Call to action to register
Carousel
Upload images + set the order + auto-play interval. Arrows + dot indicators for manual navigation.
Caution: for carousel components with functional state updates, the logic is guarded against an endless-loop render (see commit
63ca931). The arrows trigger a carousel step incrementally.
Footer CTA
Final block with headline + button (e.g. "Secure your license now → /join").
Frequently asked questions
How do I change the header / logo / footer? Branding tab in Settings → logo, font, colors. This affects the landing page and portal at the same time.
Can I insert my own HTML? Currently only through the available section types. A custom HTML block is coming in Phase 2.
How do I link to registration?
Direct link: /join (shows self-service packages). If one of your packages has auto_activate=true, the customer goes straight through without any wait.
Does branding take effect immediately? Yes. Saving branding triggers a re-render on the landing page, with no additional step.
Are there templates? Currently you start with an empty page. A template library is coming in Phase 2.
Scroll animations (fade-in)
Since 2026-04-29, each section fades in gently as you scroll (opacity 0 → 1 + translateY 28px → 0, transition 0.6s). The first section (usually the hero) is already visible on page load; the following 5 get a staggered delay (0.05s per position) for a calm, cascaded effect.
Implementation details (for developers):
- Intersection observer (
threshold: 0.1) inapps/portal/app/components/LandingPage.tsx - Sections are direct children of an
lp-sections-containerdiv, which makes thenth-childcascading delays work cleanly - Header and footer intentionally do not animate: they stay static
- The preview buttons in the builder (🖥 Desktop / 📱 Mobile) open the real portal page with a token; the animations are visible there identically
Multilingual landing page (develop)
In addition to the original language (German), the landing page can have an English variant, maintained manually or translated automatically at the push of a button. The end customer sees the page in the language they set in the portal (i18n).
Language tab in the builder
At the top of the editor area, a toggle DE / EN:
- DE mode : you maintain the original, exactly as before.
- EN mode : for each text field, a read-only reference box appears with the German original (
🇩🇪 …, italic, beige background) and below it an empty input field for the English version.
Auto-translate
The button "🔄 Automatically translate to EN" (visible in the DE tab) fills all EN fields at once:
- Click → confirmation dialog.
- Confirm → licensio sends the texts to Claude (Sonnet) for translation. Takes a few seconds, cost per run ~$0.05 (borne by licensio).
- Success → all EN fields are filled, the tab switches automatically to
EN. You can refine each text manually and must then still click Save.
Rate limit: a maximum of 3 auto-translate runs per 72 hours and provider. Once the limit is reached, the button is disabled with a note of when it is available again; you can translate manually at any time in the meantime.
"Not translated" hint (NotTranslatedBadge)
If a visible field (e.g. the hero headline) has no translation yet in EN mode, the builder shows a small "Not translated" / "Not translated" badge right next to it. This way you can see at a glance where there are still gaps, especially when you have added individual fields after an auto-translate run or added new sections.
Important: the badge appears only in the admin preview (builder + preview tab with token URL). End customers on the live page never see it: there it silently falls back to the original (default_locale) so the page looks clean. This way you as the provider get the hint without your customers seeing translation gaps.
What happens with a missing translation?
The end customer never sees an empty spot: if the EN version of a field is missing, the display automatically falls back to the German original. The translation is thus additive: you can fill it in piece by piece without the page breaking.
What is covered?
- Phase 1 (Foundation): data model for translated fields, fallback logic, no migration needed. English texts live as a suffix key in the existing
tenants.landing_pageJSONB (headline= DE original,headline_en= English version). - Phase 2 (Builder UI + Auto-Translate): language tab, side-by-side editors, auto-translate button with rate limit, NotTranslatedBadge. Covers the top-level texts (headline / subline / body text / button text) in all section editors: Hero, About, Packages, Features, CTA, Screenshots, Carousel, portal preview.
Still open (Phase 3 / 4)
- Side-by-side also for list items (individual feature cards, carousel items: title + description) and for multiple buttons in the hero.
- More languages (ES, FR) in the LanguageProvider + dictionary.
For developers
- Translate route:
POST /api/landing-page/translate(Admin app), usesANTHROPIC_API_KEY. Without a key →503 { code: 'API_KEY_MISSING' }. ENV must be set inapps/admin/.env.local(local) and in the Vercel Admin project for Production + Preview. - Portal render:
getLocalizedField(data, field, locale, defaultLocale): readsdata[field_<locale>]iflocale != defaultLocale, otherwisedata[field], otherwise the original.
Related
- Branding : colors, logo, font
- Packages :
show_in_join_previewfor the pricing section - Custom Domain : own-domain hosting (in preparation)
- i18n : platform i18n setup