Landing Page with Email Capture template for Lovable
One offer, one action, an indexable copy body and an insert-only policy on the sign-up table. The kit is three files: a build prompt for Lovable, a Supabase schema with row-level security, and verification queries that run as the wrong user to prove each policy denies what it should. The prompt is free; the full SQL comes with the bundle.
By Marco Kohns · Stack: React + Vite, TypeScript, Tailwind CSS, shadcn/ui, Supabase
The trap
What goes wrong without the Landing Page with Email Capture kit?
A policy for all also grants select, so anyone holding the public key reads every email. The kit has one insert policy and no select policy, so reads return zero rows.
The mistake
A public form that exposes the whole list: the policy Lovable writes when nobody names the rule.
The check that catches it
verify.sql, check 2: Should return ZERO ROWS, not an error and not data. If this returns rows, your email list is publicly readable. Stop and fix the policy.
The policies that prevent it are in the kit's schema.sql, which ships with the bundle; the hub shows one pattern per kit.
verify.sql
How do you prove the Landing Page with Email Capture policies work?
Run every check as an ordinary signed-in user, never as service_role, which bypasses every policy and makes a broken schema look correct.
| # | Expected result |
|---|---|
| 1 | Should SUCCEED. An anonymous visitor can join the list. |
| 2 | Should return ZERO ROWS, not an error and not data. If this returns rows, your email list is publicly readable. Stop and fix the policy.catches the trap |
| 3 | Should return zero rows. Counting is still reading. |
| 4 | Should FAIL. No update policy exists. |
| 5 | Should FAIL. No delete policy exists. |
| 6 | Should SUCCEED silently and create no second row. |
| 7 | Confirm RLS is on. |

What is in the kit?
- A build prompt that starts from the traffic source, before any layout
- A leads table with case-insensitive deduplication and UTM capture
- An insert-only RLS policy for anonymous visitors, with no select policy at all
- A capture function so a repeat submission confirms instead of erroring, without a read
- Seven verification queries, one of which proves your list is not readable from the browser
What the kit does not do
- Not a pre-built app you clone and run. There is no repository and no node_modules.
- Not a design file or a theme. Lovable generates the interface from the prompt.
- Not a substitute for reading the SQL. You are running it against your own database.
Setup
In what order do you set up the kit?
Schema before prompt, because the prompt references the table names the schema creates.
- 01
Run schema.sql in the Supabase SQL editor
The prompt writes through capture_lead(), which this file creates.
- 02
Run verify.sql from the browser client as an anonymous visitor
Query 2 is the one that matters. If a bare select on leads returns rows, stop and fix it before shipping.
- 03
Paste prompt.md into Lovable
Then replace the offer and the audience.
- 04
Read your list from the dashboard or a server function
Never from the browser. There is no read policy, deliberately.
Things that catch people out
- The single most damaging mistake in a generated landing page is granting select on the leads table to anon so that a debug view works. That makes every address downloadable by anyone holding your project's public key, which is published in your own frontend.
- The prompt explicitly forbids inventing testimonials, logos or numbers. Lovable will otherwise generate plausible social proof, and fabricated proof on a live page is a liability; placeholders stay labelled.
- A page that is only a hero and a form has almost nothing to rank with. The prompt asks for a copy body and FAQ structured data for that reason.
The files
What do the kit files contain?
The build prompt in full, and the first 12 lines of each SQL file so you can judge the code before you run it anywhere.
prompt.md
Download prompt.mdThe build prompt
# Context Build a pre-launch landing page whose one job is collecting emails for the launch list. Visitors arrive from one traffic source carrying UTM parameters, so the page has one offer and one action. ## Core Features (Priority Order) 1. Hero with the offer and the email form visible without scrolling on a phone 2. Email form calling capture_lead with the email, source, utm_source, utm_medium, utm_campaign and referrer 3. Inline success state replacing the form without layout shift 4. A repeat address shows the same success state, because capture_lead ignores duplicates 5. A short body section, then three proof blocks as labelled placeholders ## Visual Style & Design - Minimal and focused: generous whitespace, one focal point, short body lines - Single column: hero first, sections stacked below - Fraunces for headings, Inter for body text - Colours: background #fafaf9, text #1c1917, muted #78716c, accent #ea580c on the submit button only - shadcn/ui Input and Button for the form, Card for proof blocks, Alert for the success state - Save these style keywords to the project knowledge. ## Page Copy - Headline: "Be first in line when [Product] launches" - Subtext: "Leave your email and we send one message on launch day, with your invite inside." - Button: "Join the waitlist" - Success: "You are on the list. Watch your inbox on launch day." - Proof: "[Placeholder: customer quote]", "[Placeholder: logo row]", "[Placeholder: one sourced number]" - No accounts: every visitor is signed out and sees the same page. ## States - Empty: an empty or malformed email shows an inline message under the field - Loading: the button shows a spinner and stays disabled while capture_lead runs - Error: a failure keeps the typed email and shows "Something went wrong. Try again." with retry ## Data & Access - The leads table, its row-level security policy and capture_lead already exist in the connected Supabase project from schema.sql. Never weaken, drop or bypass them or create tables; if something is missing, stop and ask me. - The form writes only through capture_lead. The browser never selects, counts, updates or deletes leads, and never gets a read policy. - Browser validation mirrors leads_email_shape. This build has no admin screen. ## Done When - Submitting a new address shows the success state and a row appears in leads with the utm_source from the URL - Submitting the same address in a different case shows the same success state and adds no second row - An anonymous select on leads from the browser returns no rows - An invalid email shows the inline error and never calls capture_lead ## Build Order The static page with final copy and meta tags, then the form wired to capture_lead, then UTM and referrer capture. ## Safe-Guard Instructions - One call to action: no second button, popup or navigation menu - No invented testimonials, logos, names or numbers - No browser read access to leads on later edits, and no service role key in client code ## Before Building Ask me any questions you need in order to fully understand what I want from this feature and how I envision it. Save my answers to the project knowledge so later prompts build on them.
schema.sql
Preview · full file in the bundleLeads table and capture function
-- Landing page lead capture for Lovable + Supabase -- Reviewed row-level security. Read the comments before running this. -- -- THE ONE THING THAT MATTERS HERE: a public form needs INSERT for anonymous visitors and -- must never grant SELECT. If you grant select to anon, your entire email list is -- downloadable by anyone with your project's public key. That is the single most common -- and most damaging mistake in a generated landing page. create table public.leads ( id uuid primary key default gen_random_uuid(), email text not null, -- Case-insensitive uniqueness, so Foo@x.com and foo@x.com are one lead.
verify.sql
Preview · full file in the bundlePolicy verification queries
-- Verification queries. Run these from the browser client, as an anonymous visitor.
-- The second one is the important one.
-- 1. Should SUCCEED. An anonymous visitor can join the list.
select public.capture_lead('verify@example.com', 'verification');
-- 2. Should return ZERO ROWS, not an error and not data.
-- If this returns rows, your email list is publicly readable. Stop and fix the policy.
select * from public.leads;
-- 3. Should return zero rows. Counting is still reading.
select count(*) from public.leads;After the kit
Which library prompts build on the Landing Page with Email Capture kit?
Each extends the kit's tables with one feature, keeps its policies, and ends with Done When checks Lovable can verify.
- Landing Page + Email Opt-In
A single-purpose pre-launch page with one offer and one form, where the signups table accepts inserts and forbids every browser read, and UTMs are stored per signup.
- Event Countdown Landing Page
A dated event page whose countdown, calendar links and live and replay variants all run from one UTC timestamp, with an insert-only reminder signup table.
- Landing Page A/B Variant Generator
Two-variant testing on a live landing page: one changed block, cookie-stable assignment, per-variant conversion events and a results view that waits for 300 visitors per variant.
- Basic Analytics for Landing Pages
First-party landing page analytics posted to your own server function: pageviews, sources, device, one conversion and a four-step funnel, read on an admin dashboard.
- Simple Sitemap & SEO Generator
Sitemap, robots.txt, titles, canonicals and structured data generated from one route registry in code, with an admin page that fetches each route and flags mismatches.
- Simple Press Kit Page
A public /press page served from tables: dated facts, quotes shown only when marked cleared, downloadable assets with dimensions, a ZIP of everything and a press contact.
The full SQL for all 4 kits
The Complete Lovable Bundle: every schema.sql and verify.sql, every Pro prompt, unlimited generation. One payment. No subscription, no renewal, ever.
Disclosure: if you create a Lovable account through links on this page, we may earn a commission. It costs you nothing and does not change what we recommend. Create a free Lovable account
Frequently asked
What does the Landing Page with Email Capture template for Lovable include?
A build prompt that starts from the traffic source, before any layout. A leads table with case-insensitive deduplication and UTM capture. An insert-only RLS policy for anonymous visitors, with no select policy at all. A capture function so a repeat submission confirms instead of erroring, without a read. Seven verification queries, one of which proves your list is not readable from the browser.
What mistake does the Landing Page with Email Capture kit prevent?
A public form that exposes the whole list. A policy for all also grants select, so anyone holding the public key reads every email. The kit has one insert policy and no select policy, so reads return zero rows.
How do I prove the Landing Page with Email Capture policies work?
Run verify.sql after schema.sql, as an ordinary signed-in user and never as service_role, which bypasses every policy. Check 2 is the one that catches the trap: Should return ZERO ROWS, not an error and not data. If this returns rows, your email list is publicly readable. Stop and fix the policy.
What we did not publish
- A Lovable credit cost for this kit. The SQL was validated against Postgres 17; the kit was not built end to end in Lovable for this page.
- The SQL in full; it is what the bundle sells.
- The mistake SQL is an illustration written for this page; the kit SQL beside it is quoted from schema.sql.
These templates are provided free and as-is, with no warranty of any kind. The SQL is intended to be run against your own Supabase project and will create and alter tables. Read it, run it on a development project first, and review every policy against your own requirements before going near production data. You remain responsible for the security and correctness of anything you ship. These schemas assume Supabase, which grants the anon and authenticated roles access to new tables in the public schema by default. Row-level security is what then restricts those roles. If you run this SQL on a plain Postgres instance instead, those grants do not exist, so the policies appear to work while the missing privileges are what blocks access, and a test there proves nothing about the policies.
Other kits
- SaaS Starter · a member promoting themselves to owner
- Internal Admin Dashboard · an aggregate function that leaks the event log
- Lightweight CRM · a record reassigned to someone else
Checks parsed from the kit files; page checked 23 October 2026.
Written by

Marco Kohns
Founder of ProtoBites - Venture Growth Studio
Growth PM at a Silicon Valley scale-up (a16z and General Catalyst backed), ex-Techstars where he consulted 13 early-stage startups, Reforge-trained. Every prompt on this site comes out of shipping ProtoBites' own portfolio products.
Related reading
- all four build kits · SaaS, dashboard, CRM.
- landing page prompts · Eleven pages by traffic source.
- the email opt-in prompt, run · 1.8 credits, one round.
- first 100 users · Where the captured list goes next.
- the SaaS starter kit · What comes after the capture page.
- Lovable pricing and credits · Plans read today and what one prompt costs in credits.
- Lovable vs Bolt · The same page on another meter.
- product-channel fit · Why the traffic source shapes the page.
- the CRM kit · Where captured leads go next.
- Lovable security · Why the leads table's select policy is proven, not assumed.
- SaaS landing page prompt · A SaaS landing page prompt run in Lovable, output checked line by line.
- the email opt-in prompt page · The prompt this kit's schema was written for, run and measured.