Back to all posts

How-to: Framer.com pass form submission values to redirect URL

fgbytes

March 5, 2025

How-to: Framer.com pass form submission values to redirect URL

Framer is an incredible platform for building websites, but developers often encounter limitations when it comes to form submissions, particularly around handling URL parameters and custom redirects. The standard Framer form submission process can be restrictive, making it difficult to capture and forward important tracking information.

To address these challenges, I've developed a custom React high-order component that provides a flexible solution for form submissions. This override allows developers to seamlessly capture form data, send webhooks, integrate with Google Tag Manager, and redirect users with full parameter preservation.


Full code:

form.override.tsx
import type { ComponentType } from "react"
import { useEffect } from "react"

// Declare dataLayer for TypeScript
declare global {
    interface Window {
        dataLayer: any[]
    }
}

// Configuration constants
const CONFIG = {
    WEBHOOK_URL: 'https://your-webhook-url.com/endpoint', // Replace with your actual webhook URL
    REDIRECT_BASE_URL: 'https://your-redirect-url.com/landing', // Replace with your actual redirect URL
    ENABLE_WEBHOOK: true, // Toggle webhook functionality
    ENABLE_GTM: true, // Toggle Google Tag Manager functionality
    GTM_EVENT: {
        name: 'begin_checkout', // Event name
        type: 'submit_lead', // Event type for logging
    },
    SOURCE_PREFIX: 'landing_page', // Default source prefix for UTM tracking
}

export function withCustomRedirect(Component: ComponentType): ComponentType {
    return (props: any) => {
        useEffect(() => {
            // Debug log
            console.log("Override mounted, props:", props)

            // Find and modify the form as soon as it's available
            const findAndModifyForm = () => {
                const form = document.querySelector("form")
                if (form) {
                    console.log("Found form:", form)

                    // Remove Framer's form handlers
                    form.removeAttribute("data-framer-form-state")
                    form.removeAttribute("data-framer")

                    // Override form submission
                    form.onsubmit = async (e) => {
                        e.preventDefault()
                        e.stopPropagation()

                        console.log("Form submission intercepted")

                        const emailInput = form.querySelector(
                            'input[type="email"]'
                        ) as HTMLInputElement
                        if (!emailInput || !emailInput.value) {
                            console.error("No email input found or empty")
                            return
                        }

                        console.log("Email found:", emailInput.value)

                        // Get current URL parameters
                        const currentParams = new URLSearchParams(
                            window.location.search
                        )
                        console.log(
                            "Current URL params:",
                            Object.fromEntries(currentParams)
                        )

                        try {
                            const webhookData = {
                                lead: {
                                    email: emailInput.value,
                                    utm_source: currentParams.get("utm_source")
                                        ? `${CONFIG.SOURCE_PREFIX}__${currentParams.get("utm_source")}`
                                        : CONFIG.SOURCE_PREFIX,
                                    utm_campaign:
                                        currentParams.get("utm_campaign") || "",
                                    utm_medium:
                                        currentParams.get("utm_medium") || "",
                                },
                            }

                            console.log("Sending webhook data:", webhookData)

                            // Push to dataLayer if enabled
                            if (CONFIG.ENABLE_GTM && window.dataLayer) {
                                window.dataLayer.push({
                                    event: CONFIG.GTM_EVENT.name,
                                    lead_email: emailInput.value,
                                    lead_source: webhookData.lead.utm_source,
                                    lead_campaign: webhookData.lead.utm_campaign,
                                    lead_medium: webhookData.lead.utm_medium,
                                })
                                console.log(`GTM event pushed: ${CONFIG.GTM_EVENT.type}`)
                            }

                            // Send webhook if enabled
                            if (CONFIG.ENABLE_WEBHOOK) {
                                await fetch(CONFIG.WEBHOOK_URL, {
                                    method: "POST",
                                    headers: {
                                        "Content-Type": "application/json",
                                    },
                                    body: JSON.stringify(webhookData),
                                })
                            }

                            // Prepare redirect URL
                            const queryParams = new URLSearchParams(currentParams)
                            queryParams.set("email", emailInput.value)
                            const redirectUrl = `${CONFIG.REDIRECT_BASE_URL}?${queryParams.toString()}`

                            console.log("Redirecting to:", redirectUrl)

                            // Force redirect
                            window.location.href = redirectUrl
                        } catch (error) {
                            console.error("Error during submission:", error)
                        }
                    }

                    // Also handle the button click
                    const button = form.querySelector('button[type="submit"]')
                    if (button) {
                        console.log("Found submit button:", button)
                        button.onclick = (e) => {
                            e.preventDefault()
                            e.stopPropagation()
                            form.onsubmit?.(e as any)
                        }
                    }
                }
            }

            // Initial check
            findAndModifyForm()

            // Set up a mutation observer to watch for form addition
            const observer = new MutationObserver((mutations) => {
                for (const mutation of mutations) {
                    if (mutation.addedNodes.length) {
                        findAndModifyForm()
                    }
                }
            })

            observer.observe(document.body, {
                childList: true,
                subtree: true,
            })

            return () => observer.disconnect()
        }, [])

        return <Component {...props} />
    }
}


How the Override Works: Key Features and Configuration

Configuration Options

  • WEBHOOK_URL: The endpoint where form submission data will be sent. Replace with your actual webhook URL.
  • REDIRECT_BASE_URL: The base URL where users will be redirected after form submission.
  • ENABLE_WEBHOOK: Toggle to enable or disable webhook functionality (default: true), just leave false if you don't need it.
  • ENABLE_GTM: Control Google Tag Manager event tracking (default: true).
  • GTM_EVENT:
    • name: The event name for GTM tracking (e.g., 'begin_checkout')
    • type: A secondary event type for logging purposes
  • SOURCE_PREFIX: A prefix added to UTM source for additional tracking granularity.
conf.js
// Configuration constants
const CONFIG = {
    WEBHOOK_URL: 'https://your-webhook-url.com/endpoint', // Replace with your actual webhook URL
    REDIRECT_BASE_URL: 'https://your-redirect-url.com/landing', // Replace with your actual redirect URL
    ENABLE_WEBHOOK: true, // Toggle webhook functionality
    ENABLE_GTM: true, // Toggle Google Tag Manager functionality
    GTM_EVENT: {
        name: 'begin_checkout', // Event name
        type: 'submit_lead', // Event type for logging
    },
    SOURCE_PREFIX: 'landing_page', // Default source prefix for UTM tracking
}

Core Functionality

  • Intercepts form submission process
  • Removes Framer's default form handling
  • Captures email input
  • Preserves and forwards URL parameters
  • Sends optional webhook with lead information
  • Pushes events to Google Tag Manager
  • Redirects to a specified landing page with all original parameters

Technical Highlights

  • Uses React's useEffect for dynamic form modification
  • Implements a MutationObserver to handle dynamically loaded forms
  • Provides TypeScript support
  • Configurable and easy to attach to any Framer project

By implementing this override, developers can gain granular control over form submissions, tracking, and user redirects without being constrained by Framer's default behavior.

Still have questions? Just ping me in our Locals.ai community here: https://locals.org/today-i-learned-hxfy

Categories