Making a warm lead re-enter their name, email, and phone number after clicking a personalized email or SMS link kills conversion rates. It is unnecessary friction. You can easily pre-populate GoHighLevel booking pages using URL query parameters and a tiny bit of client-side JavaScript so your contacts see their details filled in the second the page loads.
Whether you’re running standalone HighLevel calendar links, native funnel pages, or embedding calendars via iframes on WordPress or Webflow, passing contact data takes about five minutes to wire up. Here is the exact setup I use across client sub-accounts to bypass manual data entry.

How GHL Calendars Read URL Parameters
Modern HighLevel booking widgets look for specific query keys in the page URL when rendering the contact form. If those keys exist, the calendar grabs the string values and injects them directly into the input fields.
The standard system keys supported out of the box are:
first_name: Contact’s first namelast_name: Contact’s last namename: Full name (use this if your calendar form only has a single full-name field)email: Contact’s email addressphone: Contact’s phone number (keep this in E.164 format)
A basic pre-filled direct calendar link looks like this:
https://api.leadconnectorhq.com/widget/booking/YOUR_CALENDAR_ID?first_name=John&last_name=Doe&email=john@example.com&phone=%2B15551234567Notice I used %2B1 instead of a literal +1 for the country code. Query strings need proper URL encoding—if you pass a raw plus sign, browsers often parse it as an empty space, and HighLevel’s phone validator will drop the input entirely.
Building Dynamic Calendar Links in Workflows and Campaigns
Hardcoding values is fine for testing, but in production, you’ll generate these links dynamically with HighLevel merge tags inside workflows, email broadcasts, and SMS steps.
If you have worked with GoHighLevel merge fields and fallbacks, you know that missing contact data can leave empty query params that look messy. Always structure your workflow links using clean contact variables.
Here is the exact format I drop into email templates and SMS action blocks:
When you are sending via SMS, keep your link short by routing through a custom subdomain instead of a massive raw URL. Check out our guide on how to connect a custom domain and subdomain to GoHighLevel funnels to keep your text links branded and clean.
Passing Parameters Through Funnel Steps to an Embedded Calendar
A classic two-step funnel setup captures lead info on Step 1 (an opt-in form or quick survey) and sends them to Step 2 to pick a time slot. HighLevel can pass that data downstream automatically without custom scripts.
Here is how to set it up:
- Open your Step 1 Form or Survey in the builder.
- Under Form Settings, set the On Submit action to Go to next step (or set a specific redirect URL).
- Toggle on Redirect with query parameters.
- On Step 2 (your calendar page), turn on Sticky Contact in the page settings.
With Sticky Contact and query parameter redirects enabled, GHL reads the URL string from Step 1, saves the values to the local browser session, and injects them into the calendar form when the user picks a date and time.
Scripting URL Parameter Forwarding for External Embeds
If you embed a HighLevel calendar on an external site like WordPress or Webflow, the widget runs inside an . An iframe cannot see the query parameters in the parent window’s address bar on its own—you have to read them and pass them into the iframe’s src attribute yourself.
I wrote this snippet to grab whatever query parameters exist on your parent page and append them directly to the GHL iframe embed before it loads.
Drop this JavaScript into your page right before the closing tag:
document.addEventListener("DOMContentLoaded", function() { const urlParams = new URLSearchParams(window.location.search); const iframe = document.querySelector("iframe[src*='leadconnectorhq.com'], iframe[src*='msgsndr.com']"); if (!iframe || !urlParams.toString()) { return; } try { const currentSrc = new URL(iframe.src); urlParams.forEach((value, key) => { currentSrc.searchParams.set(key, value); }); iframe.src = currentSrc.toString(); } catch (err) { console.error("Failed to update booking iframe parameters:", err); }
});This relies on the native MDN URLSearchParams API to loop through every parameter in the address bar and append them cleanly onto the calendar iframe.
Pre-Populating Custom Fields on Booking Forms
Standard fields are straightforward, but HighLevel calendars can also pre-fill custom fields—things like Company Name, Budget, or Website URL.
To pre-populate a custom field, you have to use the exact unique key defined in your account:
- Go to Settings > Custom Fields.
- Find your field (e.g., “Company Name”).
- Click the edit/info icon to grab the Unique Key (usually formatted like
contact.company_nameor justcompany_name).
If your unique key is company_name, your URL parameter simply looks like this:
https://yourdomain.com/calendar?first_name=Sarah&email=sarah@agency.com&company_name=Acme+CorpIf you’re routing lead data from external ad platforms or third-party webhooks, make sure your fields are mapped accurately using our walkthrough on how to map form submission data to custom fields in GoHighLevel.
Handling URL Encoding and Phone Number Formatting
The number one reason parameter auto-fill fails is bad string formatting. If your workflow pushes unencoded characters—like raw spaces, plus signs, or parentheses in phone numbers—the HighLevel widget validator silently fails and leaves the field blank.
Here is what your inputs should look like after encoding:
- Raw:
+1 (555) 019-2834→ Encoded:%2B15550192834 - Raw:
Jane Doe & Co.→ Encoded:Jane%20Doe%20%26%20Co. - Raw:
test+user@example.com→ Encoded:test%2Buser%40example.com
Inside HighLevel workflows, prefer using {{contact.phone_raw}} or plain {{contact.phone}} rather than formatted custom fields so the query string doesn’t get corrupted by unexpected spaces or symbols.
Troubleshooting: Why Fields Fail to Populate
If your fields aren’t populating, check these common failure points first:
- Calendar Widget Version: Make sure you are using the Neo / New Calendar widget engine under Calendars > Calendar Settings > Customizations. The legacy widget engine handles query params unreliably.
- Custom Form Field Mismatches: If your calendar uses a custom form from the Form Builder, verify you used standard system fields. If you replaced the default First Name field with a custom single-line text field,
first_namein the URL won’t map to it. - Sticky Contact Cookies Overriding URLs: If you’re testing multiple contacts in the same browser session, Sticky Contact cookies will override the parameters in your URL. Always test in an Incognito/Private window.
- Iframe Restrictions: When embedding externally, make sure you aren’t loading the calendar in a sandboxed iframe that blocks script execution or parameter forwarding. Check the GoHighLevel Help Center if you need the base embed snippet.
Frequently Asked Questions
Can I hide pre-populated fields so leads cannot change them?
Not through URL parameters alone. However, if your calendar links to a custom Form Builder form, you can add custom CSS in the form builder to set specific fields to display: none;. The URL parameters will still populate them in the DOM behind the scenes.
Does pre-populating contact details skip the contact step entirely?
No. HighLevel still requires the contact to view the confirmation step and click the final “Book Appointment” button. It just removes the typing step.
Will pre-populating overwrite existing contact data in HighLevel?
Yes. If a contact books with an updated phone number or name passed in the URL parameters, HighLevel updates their existing record based on their matching email address or contact ID.
Next Steps for Your Booking Setup
Once your parameters are populating reliably, make sure you clean up the post-booking redirect. Read our guide on how to redirect GoHighLevel calendars to custom confirmation pages to pass appointment data into your analytics and thank-you pages.

