Skip to content
LazyFrog

Your own domain

Connect a domain you own to your live site, with HTTPS ready before it switches.

Paid plans can use your own domain, one per project on Hobby, five on Pro and ten on Business. The domain serves the live site, so it shows your site once the project is published; you can add it before.

A domain counts once whether it's a bare domain with its www (example.com) or one other address (portal.example.com, so each address that opens the app directly counts as one more), and a released one never counts. The portal's Domains tab says what counts, for example "2 of 5 domains: example.com (with www), portal.example.com".

Connect it

Ask your AI to "connect example.com", or add it in the portal under Domains. A bare domain makes www.example.com your site's main address. Where your DNS provider can point the bare domain at another address (CNAME flattening or ALIAS: Cloudflare, Namecheap, Porkbun, Hostinger, NS1, DNSimple), example.com is connected too, with its own certificate, and sends visitors to www. A subdomain (portal.example.com) connects just that.

LazyFrog shows the records to add at your DNS provider, recognises the provider and links to its help page:

RecordWhat it does
TXT records per hostnameOne proves the domain is yours; the certificate ones (usually two, and more may appear within a minute: Check now shows them) let HTTPS be ready before traffic moves. Safe to add any time.
A CNAME to customers.lazyfrog.appSends visitors to your site. On a bare domain this is an ALIAS or "CNAME flattening", depending on the provider.

Keep your MX records: your email isn't affected.

Some providers (GoDaddy, IONOS, OVHcloud, Squarespace, Wix, Network Solutions, DreamHost, Amazon Route 53, Azure DNS) can't point a bare domain at another address by name. There only www.example.com is connected: edit the www record the provider already has (don't add a second one), and forward the bare domain (301) to https://www.example.com using the provider's forwarding, which LazyFrog names. The bare domain answers from the provider's forwarder, so it never shows as live in LazyFrog, and that's expected.

At a provider LazyFrog doesn't recognise, only www is connected too. If your provider allows a CNAME or ALIAS on the bare domain, connect the bare domain afterwards (Connect example.com too in Domains) and it sends visitors to www; otherwise forward it as above.

You need a domain you already own, registered with any registrar.

The steps

The portal shows each step as it completes: DNS points here → ownership confirmed → HTTPS certificate → live. Changes at a provider take a few minutes to an hour.

What each address does

Every address of your site has one of three roles, which you change in Domains or by asking your AI:

RoleWhat visitors get
MainYour site's address, exactly one. www by default; Make this the main address picks another, the bare domain included. Your app knows it as SITE_URL.
Sends visitors to the main addressA permanent redirect (308) that keeps the page and its query. The bare domain and your lazyfrog.app address work this way.
Opens the app directlyThe same app answers on this address as it is, with no redirect: your app decides what to show for it. For portal.example.com, api.example.com and so on. A subdomain you add after the main address starts this way.

Once the main address is live, the lazyfrog.app address and the redirecting addresses send visitors to it.

Beside SITE_URL, the live app gets SITE_HOSTS: the addresses it answers on as they are, comma-separated. First SITE_URL's, then a main address that isn't live yet (it opens the site as it is until then), then the addresses that open the app directly, pending ones included; never the ones that send visitors elsewhere. Once www is live that's www.example.com,portal.example.com; before, yoursite.lazyfrog.app,www.example.com,portal.example.com. In the preview it is the preview's one address.

Both are set when the app starts, at a publish or a wake: a domain going live doesn't restart your app, so publish again (or let it wake) for SITE_URL and SITE_HOSTS to follow.

With a domain connected, the live app also gets SITE_COOKIE_DOMAIN: the main domain's registrable part (example.com, or example.co.uk for www.example.co.uk), for a sign-in shared by its addresses. It isn't set in the preview or without a domain.

An app with several entry points routes by the request's exact hostname. In Next.js (proxy.ts in Next 16, middleware.ts before it):

import { NextResponse, type NextRequest } from "next/server";

// Each entry hostname, exactly, and the folder its pages live under (app/portal, app/api).
// Exact hosts: host.startsWith("portal.") would also catch portal.lazyfrog.app, another site.
const ENTRIES: Record<string, string> = {
  "portal.example.com": "/portal",
  "api.example.com": "/api",
};

export function proxy(req: NextRequest) {
  const host = (req.headers.get("host") ?? "").replace(/:\d+$/, "").toLowerCase();
  const base = ENTRIES[host];
  const path = req.nextUrl.pathname;
  if (!base || path === base || path.startsWith(`${base}/`)) return;
  const url = req.nextUrl.clone();
  url.pathname = path === "/" ? base : `${base}${path}`;
  return NextResponse.rewrite(url);
}

// Skips Next's own files, /api, static files by their extension (icon.svg, public/images,
// robots.txt, sitemap.xml; not any dotted path: /invoices/INV-2026.10 is a page) and the
// generated icons, social images and manifest: rewritten under /portal on an entry host
// they'd 404. Each is anchored, so /icons and /api-docs are pages too. api.example.com/orders
// becomes /api/orders and api.example.com/ is /api (add app/api/route.ts for it), while
// api.example.com/api/orders passes through as it is: both answer.
export const config = {
  matcher: [
    "/((?!_next/|api/|api$|favicon\\.ico$|(?:apple-)?icon\\d*(?:\\.\\w+)?$|(?:opengraph|twitter)-image(?:\\.\\w+)?$|manifest\\.(?:json|webmanifest)$|.*\\.(?:svg|png|jpe?g|gif|webp|avif|ico|txt|xml|webmanifest|css|js|map|woff2?)$).*)",
  ],
};

In production req.url is the app's own https://0.0.0.0:<port>, not the visitor's address: build absolute URLs from the Host header or SITE_URL.

To try an entry address before its DNS is set up, send its hostname: ask your AI to request the app with the header Host: portal.example.com, in the preview (curl from the terminal) or, once published, in production. A sign-in shared between addresses can only be checked in production on the real domain, once it is live.

A sign-in shared between www.example.com and portal.example.com needs its cookie set for the parent domain, Domain= SITE_COOKIE_DOMAIN; without it, each address signs in separately. Set it only when the request's address is on that domain, never on lazyfrog.app, which other sites share. An address under another domain of yours can't share it.

One app serves every address of a project: sending api.example.com to a different service or port isn't possible yet.

For your AI: this page as Markdown · llms.txt