Custom JavaScript for campaign form autofill not working on mobile browsers

We have custom JavaScript that autofills campaign form fields based on URL parameters when leads click through from email campaigns. Works great on desktop browsers, but completely fails on mobile devices - both iOS Safari and Android Chrome.

The script reads UTM parameters and populates hidden fields for campaign tracking. Here’s the core autofill logic:

const params = new URLSearchParams(window.location.search);
document.getElementById('campaign_source').value = params.get('utm_source');
document.getElementById('campaign_medium').value = params.get('utm_medium');

On mobile, the fields remain empty and we lose all campaign attribution data. This is forcing our marketing team to manually enter data for mobile leads, which is unsustainable. I’ve verified the URL parameters are present on mobile, so it’s something with how the form loads or how mobile browsers handle the DOM manipulation. Has anyone solved mobile event handling issues with campaign form automation?

Classic timing issue. Mobile browsers load and render differently than desktop. Your script is probably executing before the form elements are fully available in the DOM. Try wrapping your code in a DOMContentLoaded event listener, or better yet, use Zoho’s form ready callback if available.

Good catch on the timing issue. I added a DOMContentLoaded wrapper but still seeing failures on iOS specifically. Android Chrome seems better now but not 100% reliable. Could this be related to how mobile Safari handles form field manipulation?

Don’t forget about the differences in touch events versus click events on mobile. If your form has any interactive elements that trigger before the autofill, mobile event handling might be interfering. Also, check if Zoho’s mobile SDK has specific APIs for form field manipulation - using native SDK methods is always more reliable than direct DOM manipulation on mobile platforms.

Here’s a comprehensive solution that addresses mobile event handling, cross-device compatibility, and campaign form automation:

1. Mobile Event Handling - Proper Timing: The core issue is that mobile browsers (especially iOS Safari) load forms asynchronously and have stricter security policies. Replace your immediate execution with a robust waiting mechanism:

function waitForFormReady(callback, maxAttempts = 20) {
  let attempts = 0;
  const checkInterval = setInterval(() => {
    const form = document.querySelector('form[name="campaign_form"]');
    if (form && form.querySelector('#campaign_source')) {
      clearInterval(checkInterval);
      callback();
    } else if (++attempts >= maxAttempts) {
      clearInterval(checkInterval);
      console.error('Form elements not found');
    }
  }, 100);
}

2. Cross-Device Compatibility - Universal Selectors: Zoho’s mobile forms often use different element structures. Use more flexible selectors:

function setFieldValue(fieldName, value) {

  const selectors = [

    `#${fieldName}`,

    `input[name="${fieldName}"]`,

    `input[data-field="${fieldName}"]`,

    `.zoho-form-field[data-name="${fieldName}"] input
  ];

  for (const selector of selectors) {

    const field = document.querySelector(selector);

    if (field) {

      field.value = value;

      field.dispatchEvent(new Event('input', { bubbles: true }));

      field.dispatchEvent(new Event('change', { bubbles: true }));

      return true;

    }

  }

  return false;

}

3. Campaign Form Automation - Complete Implementation: Here’s the full mobile-compatible autofill solution:

(function() {

  'use strict';

  // Parse URL parameters

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

  const campaignData = {

    source: params.get('utm_source') || '',

    medium: params.get('utm_medium') || '',

    campaign: params.get('utm_campaign') || '',

    content: params.get('utm_content') || ''

  };

  // Wait for form to be ready (handles mobile async loading)

  waitForFormReady(function() {

    // Map campaign data to form fields

    const fieldMappings = {

      'campaign_source': campaignData.source,

      'campaign_medium': campaignData.medium,

      'campaign_name': campaignData.campaign,

      'campaign_content': campaignData.content

    };

    // Set values with mobile-compatible event triggering

    Object.keys(fieldMappings).forEach(fieldName => {

      if (fieldMappings[fieldName]) {

        const success = setFieldValue(fieldName, fieldMappings[fieldName]);

        if (!success) {

          console.warn(`Field ${fieldName} not found`);

        }

      }

    });

    // Store in session for form validation

    sessionStorage.setItem('campaign_data', JSON.stringify(campaignData));

  });

})();

4. iOS Safari Specific Fixes: iOS Safari blocks certain form manipulations for security. Add these workarounds:

  • Always dispatch both ‘input’ and ‘change’ events after setting values
  • Use bubbles: true in event constructors to ensure they propagate
  • For hidden fields, consider using data attributes instead: `form.setAttribute(‘data-campaign-source’, value)
  • If fields are still not populating, use a MutationObserver to wait for specific elements

5. Android Chrome Optimization: Android Chrome handles touch events differently:

  • Ensure your script runs after ‘DOMContentLoaded’ AND after any Zoho mobile SDK initialization
  • Test with Chrome DevTools mobile emulation, but always verify on real devices
  • Check for viewport-specific form rendering (Zoho may load different components below 768px width)

6. Fallback and Debugging: Add comprehensive error handling and fallback mechanisms:

// Fallback: Store in localStorage if form not ready
if (params.has('utm_source')) {
  localStorage.setItem('pending_campaign_data', JSON.stringify({
    data: campaignData,
    timestamp: Date.now()
  }));
}

// On form submit, verify data was captured
form.addEventListener('submit', function(e) {
  const sourceField = document.querySelector('#campaign_source');
  if (!sourceField || !sourceField.value) {
    // Attempt recovery from localStorage
    const pending = JSON.parse(localStorage.getItem('pending_campaign_data') || '{}');
    if (pending.data) {
      setFieldValue('campaign_source', pending.data.source);
    }
  }
});

Testing Checklist:

  • Test on iOS Safari (both iPhone and iPad)
  • Test on Android Chrome (various screen sizes)
  • Test with slow 3G connection (mobile forms may load slower)
  • Verify UTM parameters persist through redirects
  • Check that hidden fields are properly submitted with the form
  • Test with Zoho’s mobile app if your users access forms there

This solution handles the asynchronous nature of mobile form loading, works across different device types and browsers, and ensures your campaign attribution data is captured reliably regardless of how users access your forms.