Wizara Guide

How to Prefill an Embedded Wizara Form with URL Parameters

How to Pass Data Into a Form

GET parameters make it possible to pass information into an embedded Wizara form through the page URL. That means a form can open with useful context already in place instead of asking the visitor to start from scratch.

This is not limited to one form redirecting to another. The same pattern can be used when someone lands on the wrong form, scans a QR code on a tractor or trailer, clicks a link in an email, arrives from a campaign page, or follows a partner-specific link. In each case, the URL carries useful information into the embedded Wizara form so the experience feels faster, smarter, and more personalized.

Common examples include prefilling a company name, contact name, email address, equipment ID, service type, campaign source, referral code, or even a logo URL that can be used to personalize the page.

Common scenarios

What this guide covers

This guide explains the most reliable way to pass data into a Wizara form embedded on your website, especially when that form is running inside an iframe.

The core pattern is simple:

  1. Build a destination URL with query parameters.
  2. Send the visitor to the page containing the embedded Wizara form.
  3. Render the embedded form once.
  4. Read the query parameters from the parent page.
  5. Send those values into the iframe.
  6. Use On Form Load inside Wizara to populate the matching fields.

Why this needs special handling

When a form is embedded on a website, it usually runs inside an iframe. Because of that, the embedded form may not be able to read the parent page URL directly. In other words, the page can see ?companyName=Acme, but the embedded form inside the iframe may not see it unless the parent page passes it in.

This is why a direct link to the raw Wizara embed URL may work, while the same query parameters on your website page do nothing until you wire the iframe communication correctly.

What kinds of data can be passed?

Any value that makes the next step easier or more relevant is a good candidate. Common examples include:

Some values are used to prefill visible fields. Others can be used behind the scenes for routing, personalization, or conditional logic. For example, a passed companyName can prefill a company field, while a passed logoUrl can be used by custom HTML or EJS to create a more personalized experience.

Before you start

Before wiring this up, confirm these basics:

The cleanest setup is to use matching names wherever possible. For example:

firstName   -> firstName
lastName    -> lastName
email       -> email
companyName -> companyName
message     -> message
source      -> source
logoUrl     -> logoUrl

If your destination form uses different internal names, simply change the destination field names in the setValue() lines later in the process.

Step 1: Build the destination URL

On the source page or source form, use URLSearchParams to create a clean redirect URL. This properly encodes special characters and keeps the logic readable.

const params = new URLSearchParams({
  source: 'website-form',
  firstName: String(values.firstName || ''),
  lastName: String(values.lastName || ''),
  email: String(values.email || ''),
  companyName: String(values.companyName || ''),
  message: String(values.message || ''),
  logoUrl: String(values.logoUrl || '')
});

const redirectUrl =
  `https://www.example.com/request-details.html?${params.toString()}`;

If the source form itself is embedded in an iframe and the redirect should open the full page instead of staying trapped inside the frame, use:

if (window.top) {
  window.top.location.href = redirectUrl;
} else {
  window.location.href = redirectUrl;
}

Step 2: Add one container on the destination page

On the destination page, add one empty element where the embedded form should appear.

<div id="WZ--YOUR-FORM-ID"></div>

This step is intentionally simple. The page should contain the container, and your page-level JavaScript should handle the actual form rendering.

Important: render the form in one place only. If you render it once in inline page markup and again in site-level code, you can end up with two copies of the same form, two iframes competing for space, or one populated form and one blank form.

Step 3: Render the form once and forward the values into the iframe

The parent page should render the form, read the query parameters from the page URL, and send those values into the embedded iframe. The safest pattern is to retry a few times because the iframe may exist before the embedded form inside it is fully ready to receive messages.

<script>
  function onWizaraLoaded(Wizara) {
    const containerId = 'WZ--YOUR-FORM-ID';
    const formId = 'YOUR-FORM-ID';
    const container = document.getElementById(containerId);

    if (!container) return;

    container.innerHTML = '';

    Wizara.renderForm({
      element: '#' + containerId,
      formId: formId
    });

    const payload = (() => {
      const urlParams = new URLSearchParams(window.location.search);
      return {
        wizaraPopulateForm: true,
        firstName: urlParams.get('firstName') || '',
        lastName: urlParams.get('lastName') || '',
        email: urlParams.get('email') || '',
        companyName: urlParams.get('companyName') || '',
        message: urlParams.get('message') || '',
        source: urlParams.get('source') || '',
        logoUrl: urlParams.get('logoUrl') || ''
      };
    })();

    const sendPayload = () => {
      const iframe = container.querySelector('iframe');
      if (!iframe || !iframe.contentWindow) return false;
      iframe.contentWindow.postMessage(payload, '*');
      return true;
    };

    const waitForIframe = setInterval(() => {
      const iframe = container.querySelector('iframe');
      if (!iframe) return;

      clearInterval(waitForIframe);

      iframe.addEventListener('load', () => {
        let attempts = 0;
        const maxAttempts = 12;

        const retrySend = setInterval(() => {
          sendPayload();
          attempts += 1;
          if (attempts >= maxAttempts) clearInterval(retrySend);
        }, 400);
      });

      let bootAttempts = 0;
      const bootMaxAttempts = 12;

      const bootRetry = setInterval(() => {
        sendPayload();
        bootAttempts += 1;
        if (bootAttempts >= bootMaxAttempts) clearInterval(bootRetry);
      }, 400);
    }, 100);
  }
</script>
<script src="https://app.wizara.com/embed/js/index.browser.js" async></script>

Step 4: Populate the destination form using On Form Load

Inside the destination Wizara form, add an On Form Load handler that listens for the message and maps the incoming values to the right fields.

async (setValue, setValues) => {
  const applyValues = (data) => {
    if (!data || typeof data !== 'object') return;
    if (!data.wizaraPopulateForm) return;

    const firstName = String(data.firstName || '').trim();
    const lastName = String(data.lastName || '').trim();
    const email = String(data.email || '').trim();
    const companyName = String(data.companyName || '').trim();
    const message = String(data.message || '').trim();
    const source = String(data.source || '').trim();
    const logoUrl = String(data.logoUrl || '').trim();

    if (firstName) setValue('firstName', firstName);
    if (lastName) setValue('lastName', lastName);
    if (email) setValue('email', email);
    if (companyName) setValue('companyName', companyName);
    if (message) setValue('message', message);
    if (source) setValue('source', source);
    if (logoUrl) setValue('logoUrl', logoUrl);
  };

  window.addEventListener('message', (event) => {
    applyValues(event.data);
  });

  const urlParams = new URLSearchParams(window.location.search);

  applyValues({
    wizaraPopulateForm: true,
    firstName: urlParams.get('firstName'),
    lastName: urlParams.get('lastName'),
    email: urlParams.get('email'),
    companyName: urlParams.get('companyName'),
    message: urlParams.get('message'),
    source: urlParams.get('source'),
    logoUrl: urlParams.get('logoUrl')
  });
};

The direct URL check at the bottom is optional but useful. It allows the same logic to work when you open the raw embed URL directly during testing.

Optional use: personalize the form, not just the fields

Passing data into a form is not limited to visible inputs. It can also support a more customized experience.

For example:

This is especially useful for quote flows, partner referrals, white-label experiences, personalized onboarding, targeted landing pages, and enterprise workflows.

Troubleshooting

Testing checklist

Final recommendation

For most websites, the most dependable setup is to let the parent page read the URL parameters, render the embedded Wizara form once, and pass those values into the iframe after load. That approach is flexible enough for simple prefills and powerful enough for more advanced experiences such as personalized branding, preselected services, campaign-aware forms, and guided multi-step workflows.

Done carefully, it removes friction, reduces duplicate typing, and makes separate pages feel like one smooth conversation.