How do you add lead attribution to a vibe-coded site?
To add lead attribution to a site built with Lovable, v0, Bolt or Cursor, make every form save the visitor's UTM parameters and click IDs with the submission. AI builders generate forms that send the visible fields only, so you either prompt for hidden fields plus a storage script, or install a tracking snippet that adds them.
- Check what your form actually sends today.
- Add hidden UTM fields and a script that stores UTMs on arrival.
- Make the backend save those fields.
- Test with a tagged URL before launch.
A tagged link lands on the AI-built page, the UTMs are stored in a cookie, the form sends them to your database or CRM, and you can see leads by source.
Vibe coding means building software by describing it to an AI tool and accepting what it generates, rather than writing most of the code yourself. For the bigger picture of turning an AI-built site into revenue, see what to do after you build your AI-built website.
Why AI-built forms drop the lead source
The AI did exactly what you asked. You asked for a contact form, so you got name, email and message, posted to Supabase, a serverless function or an email service. Nobody asked for the source.
Three things go missing:
- No hidden fields. The form only sends what's visible.
- No persistence. Single-page apps change routes without reloading, and UTMs on the first URL disappear after the first navigation.
- No storage. Even if the values are sent, the table or email template has no column for them.
Lovable contact forms: where the source gets lost
A Lovable contact form is usually a React component that posts to one of three places: a Supabase table, an edge function that sends an email, or a form backend such as Formspree. Each one stores exactly the fields the form sends, and nothing more.
| Lovable form posts to | What to add so the lead keeps its source |
|---|---|
| Supabase table | Hidden inputs plus utm_source, utm_medium, utm_campaign columns in the table |
| Edge function or email | Hidden inputs, and the function must include them in the row or email it sends |
| Formspree | Hidden inputs only. Formspree stores every named field it receives, so the UTMs appear on each submission |
Formspree with Lovable is the simplest case: add hidden inputs named after each UTM, fill them from a stored cookie, and they arrive in Formspree alongside name and email. Check Formspree's docs for the current field handling. Trakt works with all AI-built sites, so its snippet adds the hidden UTM fields to Lovable forms whichever backend they post to.
Prompt your AI builder to add hidden UTM fields
Paste something like this into Lovable, v0, Bolt or Cursor. Adjust the table name.
Add lead source tracking to every form on this site.
1. On first page load, read utm_source, utm_medium, utm_campaign, utm_term,
utm_content, gclid and fbclid from the URL and save them in a first-party
cookie for 90 days. Do not overwrite saved values with empty ones.
2. Also save the landing page path and document.referrer on first visit.
3. Add hidden inputs for all of these to every form, filled from the cookie.
4. Send them with the submission and add matching columns to the leads table.
5. Only set the cookie after the visitor accepts analytics cookies, if a
consent banner exists.
Review what it generates. Check the columns exist and that the cookie is set before any redirect. Capturing UTM parameters in hidden fields has a reference script to compare against.
When the manual version works, keep it, or pre-register for Trakt and let the snippet maintain the hidden fields as your AI keeps rewriting the site.
How Trakt handles it on AI-built sites
Paste the Trakt snippet into your site's head once. It saves UTMs and click IDs in a first-party cookie, injects hidden UTM fields into your forms automatically and fills them, and records each submission with its source attached. Regenerated pages and new forms are covered because the snippet runs on every page. You can also build the form in Trakt instead.
Test checklist before launch
| Check | How | Pass looks like |
|---|---|---|
| UTMs survive navigation | Open ?utm_source=test, click two pages, submit | Lead shows source "test" |
| Click IDs captured | Open ?gclid=abc123, submit | Lead shows the gclid |
| Backend stores them | Look at the database row or CRM record | Columns filled, not blank |
| Consent respected | Decline cookies, submit | No tracking cookie set |
| Mobile in-app browser | Tap a tagged link inside Instagram or TikTok | Source still recorded |
| Redirects keep the query | Hit http:// and non-www versions | Tags still on the final URL |
Run the free attribution audit on the live URL too. It flags missing form capture, broken redirects and consent issues.
Why prompt-built tracking breaks in practice (and how Trakt helps)
AI builders rewrite files freely. The next "make the hero nicer" prompt can drop your hidden inputs or the cookie script, and you won't see it until leads arrive as Direct.
How Trakt closes the gap
Trakt works with all AI-built sites. The snippet injects and fills hidden fields on every form, so regenerated pages stay tracked. Each lead keeps its first touch, visits are linked across devices, source and revenue sync into your CRM, and new leads alert you by email and Slack. The dashboard shows leads by source.
Prompted tracking vs. Trakt, by requirement
| Requirement | Prompted code | Trakt |
|---|---|---|
| Hidden UTM fields | Generated per form | Injected automatically |
| Survives regeneration | Not guaranteed | Yes, snippet runs on every page |
| Consent handling | Whatever you prompt | Consent Mode v2, OneTrust, Cookiebot |
| Source and revenue in CRM | Build it | Synced |
| Tagging your campaign links | Same either way | Same either way |
FAQ
How do I track form submissions on a Lovable site?
Add hidden UTM fields to the form, a script that saves UTMs in a cookie on the first page, and columns in your database to store them. Or install a tracking snippet such as Trakt's, which injects and fills the hidden fields for you.
Why do leads from my AI-built site show no source?
AI builders create forms that send the visible fields only. Without hidden fields and a cookie to hold the UTMs across page changes, the submission has nothing to say where the visitor came from.
Can I prompt v0 or Bolt to add UTM tracking?
Yes. Ask for UTMs and click IDs to be saved in a first-party cookie on first load, hidden inputs on every form filled from it, and matching database columns. Review the code and test with a tagged URL.
Does Trakt work with Cursor or Lovable sites?
Yes. Trakt works with all AI-built sites. You add the snippet once, and it captures the source on every form, including forms the AI adds later.
How do I test tracking on a vibe-coded site before launch?
Open the site with a test UTM, navigate to another page, submit the form and check the stored record. Repeat for click IDs, a declined consent banner and a phone in-app browser, then run an attribution audit on the live URL.
What to do first
Open your live site with ?utm_source=test, click once, and submit your own form. Then open the database row. If the source column doesn't exist, start there: no prompt can fill a column that isn't in the table.


